Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/biafra23_jako.json
T

1 line
119 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "biafra23/jako", "files": {"java-to-kotlin/orchestrator/src/main/kotlin/jako/Config.kt": {"8ab47177ba3090f2f435f0e2ddfd61508c791319": {"t": 1785745716.9366114, "n": 7436, "h": "c5b2cbf5418b005c", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val convert: ConvertCfg = ConvertCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 20,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n /** Maximum simultaneous `claude -p` subprocesses Phase 2 will run when\n * refining a batch (SCC or `--only` set). 1 = serial. Going much above\n * 6 risks tripping the Claude subscription per-minute rate limit. */\n val concurrency: Int = 4,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class ConvertCfg(\n /**\n * If false, leave `*Test.java` files un-converted in\n * `src/jvmTest/java`. Useful as a regression net during the\n * Java→Kotlin migration: the un-touched test suite (still\n * exercising assertions against the original behaviour) keeps\n * working against the converted Kotlin main code, surfacing\n * conversion bugs that would otherwise hide in a all-Kotlin\n * rewrite.\n *\n * Scaffold still moves the test .java into the KMP layout\n * (`src/jvmTest/java`) so the generated `build.gradle.kts`\n * source-set redirect picks them up.\n */\n @SerialName(\"include_tests\") val includeTests: Boolean = true,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n /**\n * If true, skip the gradle compile + refine#2 pass during per-batch\n * conversion and instead run a single final compile + per-file\n * refine#2 across the whole module after every batch has been\n * J2K'd + refine#1'd. Defaults to true because the per-batch\n * compile is doomed while .java files remain in the module —\n * Java references to types whose signatures changed on the .kt\n * side won't resolve until those .java files are also Kotlin.\n * The current flow triple-retries refine#2 on every batch, which\n * burns ~6× the LLM tokens for the same eventual outcome.\n */\n @SerialName(\"deferred_compile\") val deferredCompile: Boolean = true,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "a8c30a35920189a5d804ca959719192dc72b350e": {"t": 1785755898.516403, "n": 7436, "h": "c5b2cbf5418b005c", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val convert: ConvertCfg = ConvertCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 20,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n /** Maximum simultaneous `claude -p` subprocesses Phase 2 will run when\n * refining a batch (SCC or `--only` set). 1 = serial. Going much above\n * 6 risks tripping the Claude subscription per-minute rate limit. */\n val concurrency: Int = 4,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class ConvertCfg(\n /**\n * If false, leave `*Test.java` files un-converted in\n * `src/jvmTest/java`. Useful as a regression net during the\n * Java→Kotlin migration: the un-touched test suite (still\n * exercising assertions against the original behaviour) keeps\n * working against the converted Kotlin main code, surfacing\n * conversion bugs that would otherwise hide in a all-Kotlin\n * rewrite.\n *\n * Scaffold still moves the test .java into the KMP layout\n * (`src/jvmTest/java`) so the generated `build.gradle.kts`\n * source-set redirect picks them up.\n */\n @SerialName(\"include_tests\") val includeTests: Boolean = true,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n /**\n * If true, skip the gradle compile + refine#2 pass during per-batch\n * conversion and instead run a single final compile + per-file\n * refine#2 across the whole module after every batch has been\n * J2K'd + refine#1'd. Defaults to true because the per-batch\n * compile is doomed while .java files remain in the module —\n * Java references to types whose signatures changed on the .kt\n * side won't resolve until those .java files are also Kotlin.\n * The current flow triple-retries refine#2 on every batch, which\n * burns ~6× the LLM tokens for the same eventual outcome.\n */\n @SerialName(\"deferred_compile\") val deferredCompile: Boolean = true,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "6b570b2c0960ffae70362c0e6ea69dc0e630b3a4": {"t": 1785755900.1171484, "n": 6694, "h": "bdaef378c605c5f9", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 20,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n /** Maximum simultaneous `claude -p` subprocesses Phase 2 will run when\n * refining a batch (SCC or `--only` set). 1 = serial. Going much above\n * 6 risks tripping the Claude subscription per-minute rate limit. */\n val concurrency: Int = 4,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n /**\n * If true, skip the gradle compile + refine#2 pass during per-batch\n * conversion and instead run a single final compile + per-file\n * refine#2 across the whole module after every batch has been\n * J2K'd + refine#1'd. Defaults to true because the per-batch\n * compile is doomed while .java files remain in the module —\n * Java references to types whose signatures changed on the .kt\n * side won't resolve until those .java files are also Kotlin.\n * The current flow triple-retries refine#2 on every batch, which\n * burns ~6× the LLM tokens for the same eventual outcome.\n */\n @SerialName(\"deferred_compile\") val deferredCompile: Boolean = true,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "b4612d90808303db3517039c3d69054ab63d3bb9": {"t": 1785755901.5682988, "n": 5997, "h": "61109b2685d92027", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 20,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n /** Maximum simultaneous `claude -p` subprocesses Phase 2 will run when\n * refining a batch (SCC or `--only` set). 1 = serial. Going much above\n * 6 risks tripping the Claude subscription per-minute rate limit. */\n val concurrency: Int = 4,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "60e206f8c8a41f769c8850b0e11a6cef8b6808ee": {"t": 1785755902.8952074, "n": 5739, "h": "547471aea27e9099", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 20,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "2df34cd6aec2281d62536d816b716b510bc9deb7": {"t": 1785755904.8923328, "n": 5739, "h": "2c9f477749cb4883", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 10,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "8d2a2844ffab45392582d9c685fe2646ee6ddcef": {"t": 1785755906.4730837, "n": 5738, "h": "9c329dac54d55495", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 3,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlin :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}, "79b438a166f5086d753763dd3e8786ccb913b66e": {"t": 1785755907.8308587, "n": 5741, "h": "4db7c898384cf5ff", "c": "package jako\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\n\n/**\n * Top-level YAML config. snake_case in the file, camelCase in Kotlin; the\n * @SerialName annotations bridge the two.\n *\n * `base` is set after loading to the directory the YAML lives in so relative\n * paths inside the file (e.g. `scripts/passthrough-j2k.sh`) resolve against\n * the config's location rather than the JVM's working directory.\n */\n@Serializable\ndata class Config(\n val project: ProjectCfg = ProjectCfg(),\n val claude: ClaudeCfg = ClaudeCfg(),\n val j2k: J2KCfg = J2KCfg(),\n val skills: SkillsCfg = SkillsCfg(),\n val gradle: GradleCfg = GradleCfg(),\n val analysis: AnalysisCfg = AnalysisCfg(),\n val verify: VerifyCfg = VerifyCfg(),\n val git: GitCfg = GitCfg(),\n @SerialName(\"local_model\") val localModel: LocalModelCfg = LocalModelCfg(),\n val fallback: FallbackCfg = FallbackCfg(),\n val state: StateCfg = StateCfg(),\n) {\n @kotlinx.serialization.Transient\n var base: Path = Path.of(\".\").toAbsolutePath().normalize()\n\n fun resolve(raw: String): Path {\n val expanded = if (raw.startsWith(\"~\")) {\n Path.of(System.getProperty(\"user.home\") + raw.removePrefix(\"~\"))\n } else {\n Path.of(raw)\n }\n return if (expanded.isAbsolute()) expanded.normalize()\n else base.resolve(expanded).normalize()\n }\n\n fun stateDir(): Path = resolve(state.dir)\n fun projectRoot(): Path = resolve(project.root)\n fun skillPath(name: String): Path = resolve(skills.root).resolve(name)\n}\n\n@Serializable\ndata class ProjectCfg(\n val root: String = \"\",\n val module: String = \"\",\n)\n\n@Serializable\ndata class ClaudeCfg(\n val cli: String = \"\",\n @SerialName(\"default_model\") val defaultModel: String = \"claude-sonnet-4-6\",\n val models: Map<String, String> = mapOf(\n \"LOW\" to \"claude-haiku-4-5-20251001\",\n \"MEDIUM\" to \"claude-sonnet-4-6\",\n \"HIGH\" to \"claude-opus-4-7\",\n ),\n @SerialName(\"max_turns\") val maxTurns: Int = 3,\n @SerialName(\"permission_mode\") val permissionMode: String = \"acceptEdits\",\n @SerialName(\"extra_args\") val extraArgs: List<String> = emptyList(),\n @SerialName(\"pause_on_rate_limit\") val pauseOnRateLimit: Boolean = true,\n)\n\n@Serializable\ndata class J2KCfg(\n /** \"external\" | \"headless_idea\" | \"passthrough\". */\n val strategy: String = \"passthrough\",\n val command: String = \"\",\n val args: List<String> = emptyList(),\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class SkillsCfg(\n val root: String = \"vendored-skills/upstream/skills\",\n @SerialName(\"java_to_kotlin\") val javaToKotlin: String = \"kotlin-tooling-java-to-kotlin/SKILL.md\",\n @SerialName(\"agp9_migration\") val agp9Migration: String = \"kotlin-tooling-agp9-migration/SKILL.md\",\n)\n\n@Serializable\ndata class GradleCfg(\n val wrapper: String = \"./gradlew\",\n @SerialName(\"test_command\") val testCommand: String = \":{module}:compileKotlinJvm :{module}:test\",\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n)\n\n@Serializable\ndata class AnalysisCfg(\n val parser: String = \"javaparser\",\n @SerialName(\"separate_tests\") val separateTests: Boolean = true,\n @SerialName(\"reflection_imports\") val reflectionImports: List<String> = listOf(\n \"java.lang.reflect\", \"sun.misc.Unsafe\",\n ),\n @SerialName(\"high_threshold\") val highThreshold: Int = 3,\n @SerialName(\"medium_threshold\") val mediumThreshold: Int = 1,\n)\n\n@Serializable\ndata class VerifyCfg(\n @SerialName(\"max_retries\") val maxRetries: Int = 3,\n)\n\n@Serializable\ndata class GitCfg(\n @SerialName(\"commit_per_file\") val commitPerFile: Boolean = true,\n val author: String = \"\",\n)\n\n/**\n * Local OpenAI-compatible endpoint (LM Studio / Ollama / vLLM / llama.cpp).\n * Used only for LOW-risk files when enabled = true and the reachability\n * probe at phase-2 start succeeds.\n */\n@Serializable\ndata class LocalModelCfg(\n val enabled: Boolean = false,\n @SerialName(\"base_url\") val baseUrl: String = \"http://localhost:1234/v1\",\n val model: String = \"google/gemma-4-31b\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 1800,\n @SerialName(\"probe_timeout_seconds\") val probeTimeoutSeconds: Long = 3,\n)\n\n@Serializable\ndata class DeepSeekCfg(\n @SerialName(\"base_url\") val baseUrl: String = \"https://api.deepseek.com\",\n @SerialName(\"api_key_env\") val apiKeyEnv: String = \"DEEPSEEK_API_KEY\",\n val model: String = \"deepseek-chat\",\n val temperature: Double = 0.1,\n @SerialName(\"max_tokens\") val maxTokens: Int = 16384,\n @SerialName(\"timeout_seconds\") val timeoutSeconds: Long = 600,\n)\n\n@Serializable\ndata class FallbackCfg(\n val enabled: Boolean = false,\n @SerialName(\"return_to_claude_after_window\") val returnToClaudeAfterWindow: Boolean = true,\n val backend: String = \"deepseek\",\n val deepseek: DeepSeekCfg = DeepSeekCfg(),\n)\n\n@Serializable\ndata class StateCfg(\n val dir: String = \"state\",\n)\n\n// ----- loader ------------------------------------------------------------\n\nprivate val yaml = Yaml(\n configuration = YamlConfiguration(\n strictMode = false,\n encodeDefaults = true,\n )\n)\n\nfun loadConfig(path: Path): Config {\n val text = Files.readString(path)\n val cfg = yaml.decodeFromString(Config.serializer(), text)\n cfg.base = path.absolute().parent.normalize()\n return cfg\n}\n"}}, "java-to-kotlin/config.yaml": {"8ab47177ba3090f2f435f0e2ddfd61508c791319": {"t": 1785746847.7699351, "n": 5048, "h": "379158be8514789e", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-haiku-4-5-20251001\n # Risk-tier -> model. Temporarily haiku-everywhere for debugging — the\n # 5-hour subscription window was burning down too fast on Sonnet/Opus.\n # Restore the tiered split (haiku/sonnet/opus by risk) once jako's\n # refine quality is debugged.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-haiku-4-5-20251001\n HIGH: claude-haiku-4-5-20251001\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. The orchestrator batches a whole\n # cycle into a single IDE invocation via the manifest\n # protocol — ~20s of IDE startup amortizes across the\n # batch, sub-second per file thereafter.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> (or `--manifest <path>` if it\n # supports batch mode) and writes the converted Kotlin.\n # strategy: passthrough\n # command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n strategy: headless_idea\n command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nconvert:\n # When false, leave *Test.java files unconverted (still as Java under\n # src/jvmTest/java) so the untouched test suite acts as a regression\n # net against bugs the Kotlin conversion might introduce. Set to true\n # for an all-Kotlin module.\n include_tests: false\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: false\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "a8c30a35920189a5d804ca959719192dc72b350e": {"t": 1785755896.4821346, "n": 5048, "h": "379158be8514789e", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-haiku-4-5-20251001\n # Risk-tier -> model. Temporarily haiku-everywhere for debugging — the\n # 5-hour subscription window was burning down too fast on Sonnet/Opus.\n # Restore the tiered split (haiku/sonnet/opus by risk) once jako's\n # refine quality is debugged.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-haiku-4-5-20251001\n HIGH: claude-haiku-4-5-20251001\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. The orchestrator batches a whole\n # cycle into a single IDE invocation via the manifest\n # protocol — ~20s of IDE startup amortizes across the\n # batch, sub-second per file thereafter.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> (or `--manifest <path>` if it\n # supports batch mode) and writes the converted Kotlin.\n # strategy: passthrough\n # command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n strategy: headless_idea\n command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nconvert:\n # When false, leave *Test.java files unconverted (still as Java under\n # src/jvmTest/java) so the untouched test suite acts as a regression\n # net against bugs the Kotlin conversion might introduce. Set to true\n # for an all-Kotlin module.\n include_tests: false\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: false\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "6b570b2c0960ffae70362c0e6ea69dc0e630b3a4": {"t": 1785755897.849977, "n": 4770, "h": "f33e895a1925a345", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-haiku-4-5-20251001\n # Risk-tier -> model. Temporarily haiku-everywhere for debugging — the\n # 5-hour subscription window was burning down too fast on Sonnet/Opus.\n # Restore the tiered split (haiku/sonnet/opus by risk) once jako's\n # refine quality is debugged.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-haiku-4-5-20251001\n HIGH: claude-haiku-4-5-20251001\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. The orchestrator batches a whole\n # cycle into a single IDE invocation via the manifest\n # protocol — ~20s of IDE startup amortizes across the\n # batch, sub-second per file thereafter.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> (or `--manifest <path>` if it\n # supports batch mode) and writes the converted Kotlin.\n # strategy: passthrough\n # command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n strategy: headless_idea\n command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: false\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "387d0fefc6082ed0315bf1c818483bde0b4ef48e": {"t": 1785755899.3363566, "n": 4613, "h": "df7d3cefc5b3e9ae", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. The orchestrator batches a whole\n # cycle into a single IDE invocation via the manifest\n # protocol — ~20s of IDE startup amortizes across the\n # batch, sub-second per file thereafter.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> (or `--manifest <path>` if it\n # supports batch mode) and writes the converted Kotlin.\n # strategy: passthrough\n # command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n strategy: headless_idea\n command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "c96a2851f55f97890d881909bfb760a50a848691": {"t": 1785755901.171492, "n": 4613, "h": "480c532a939599ff", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. The orchestrator batches a whole\n # cycle into a single IDE invocation via the manifest\n # protocol — ~20s of IDE startup amortizes across the\n # batch, sub-second per file thereafter.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> (or `--manifest <path>` if it\n # supports batch mode) and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n # strategy: headless_idea\n # command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "db81ef861c7b8d97c68f4f266148840acac8105d": {"t": 1785755902.5926347, "n": 4697, "h": "7fca0dc507298c69", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive a real headless IntelliJ via the :j2k-plugin\n # ApplicationStarter. The orchestrator gets idiomatic\n # Kotlin as J2K's output, so the LLM refine step only\n # needs to polish. Trade-off: ~20s of IDE startup per\n # file (a 26-file cycle = ~9 min of pure startup).\n # Worth it when refine quality matters more than wall\n # time. Use `external` + `scripts/run-j2k-headless.sh`\n # below — that wraps the right `./gradlew :j2k-plugin\n # :runIde --args=\"jakoConvert <in> <out>\"` invocation.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n # To opt into real J2K via the bundled IntelliJ plugin:\n # strategy: external\n # command: scripts/run-j2k-headless.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "b4612d90808303db3517039c3d69054ab63d3bb9": {"t": 1785755904.3063164, "n": 4107, "h": "bc49313b00170d58", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n # Parallel `claude -p` calls inside a single refine pass. The Claude\n # subscription has a per-minute throughput cap; staying ≤ 6 keeps us\n # well under it. Set to 1 for serial / debugging.\n concurrency: 4\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "60e206f8c8a41f769c8850b0e11a6cef8b6808ee": {"t": 1785755906.6258657, "n": 3896, "h": "c6633957fd61461d", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # On a single leaf file Read .java + Read .kt + Edit .kt is ~3 turns.\n # Inside an SCC the model also reads sibling files in the cycle to\n # understand cross-file types, which can take 8-12 turns alone. 20\n # gives headroom for that plus a few self-verification reads without\n # tripping `error_max_turns`. M3 (6-file Bytes48 cycle) showed 10 was\n # too tight — half the files in the cycle never reached refinement.\n max_turns: 20\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "2df34cd6aec2281d62536d816b716b510bc9deb7": {"t": 1785755907.9786837, "n": 3692, "h": "4c2cec47bbc3bb33", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n # Read .java + Read .kt + Edit/Write .kt + (optional) Read-back verify\n # is already 3-4 turns on any non-trivial file. 10 gives headroom for the\n # skill to chain a couple of edits without false `error_max_turns`.\n max_turns: 10\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "48013d0fbb95a8e69e8ec65473dd4bd34327e3f0": {"t": 1785755909.2562673, "n": 3472, "h": "ef12c95dd92628a4", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n max_turns: 3\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlin :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "e0c43a3d043193904fd7a5266ea27a1817b026fc": {"t": 1785755910.5834603, "n": 3475, "h": "53706a469d881c8a", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n max_turns: 3\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlinJvm :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: true\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: true # DEEPSEEK_API_KEY env var must be set\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "79b438a166f5086d753763dd3e8786ccb913b66e": {"t": 1785755911.904361, "n": 3486, "h": "3a5a8aae743621df", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n# YAML uses snake_case; Kotlin maps it to camelCase via @SerialName.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n max_turns: 3\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Per-file backend chain step 1. See plan §Phase 2.\n # passthrough: copy .java verbatim into the .kt slot; the LLM step does\n # the whole conversion. The fallback when no J2K binary\n # is wired up. The orchestrator treats this as \"J2K not\n # available\" for chain-routing purposes.\n # headless_idea: drive idea.sh in headless mode via a custom IntelliJ\n # ApplicationStarter plugin we ship. Requires building\n # that plugin separately.\n # external: `command` is a fully-formed script that takes\n # <java_in> <kt_out> and writes the converted Kotlin.\n strategy: passthrough\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlinJvm :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n parser: javaparser # only javaparser is supported in the Kotlin orchestrator\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# Per-file backend chain step 2: local OpenAI-compatible endpoint\n# (LM Studio / Ollama / vLLM / llama.cpp server). Used ONLY for LOW-risk\n# files when enabled and the reachability probe at phase-2 start passes.\nlocal_model:\n enabled: false\n base_url: http://localhost:1234/v1\n model: google/gemma-4-31b\n # Leave empty for typical local servers; set to env-var name (e.g.\n # \"OPENAI_API_KEY\") if your server requires a bearer token.\n api_key_env: \"\"\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 1800\n probe_timeout_seconds: 3\n\n# Per-file backend chain steps 4 & 5: when claude -p hits its 5-hour window,\n# the orchestrator falls through to DeepSeek (if enabled and credits) or\n# parks until the window resets.\nfallback:\n enabled: false # flip to true once DEEPSEEK_API_KEY is exported\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "6e640d84e110b6301c35f0c856edc0976beb04d5": {"t": 1785755913.1098044, "n": 3006, "h": "6a66a8c9a02079a0", "c": "# Plan 2 — thin orchestrator config.\n# Paths are resolved relative to this file unless absolute. `~` is expanded.\n\nproject:\n # Root of the Gradle/Maven project to convert.\n root: ~/tuweni-gemma4-pipe\n # Gradle subproject to operate on. The KMP scaffold and per-file\n # compile gate both use this module name.\n module: bytes\n\nclaude:\n # `claude` binary. Empty = look on PATH.\n cli: \"\"\n default_model: claude-sonnet-4-6\n # Risk-tier -> model. The skill is identical across tiers; only the model\n # backing the refinement step changes.\n models:\n LOW: claude-haiku-4-5-20251001\n MEDIUM: claude-sonnet-4-6\n HIGH: claude-opus-4-7\n max_turns: 3\n permission_mode: acceptEdits\n extra_args: []\n pause_on_rate_limit: true\n\nj2k:\n # Mechanical first-pass strategy. The orchestrator never inspects what J2K\n # produces — it just feeds the .kt file forward to the refinement step.\n # headless_idea: pass --command to `idea.sh` for headless conversion (Option A)\n # requires a custom IntelliJ plugin that registers an\n # ApplicationStarter; vanilla idea has no built-in J2K command.\n # vscode_engine: shell out to a Node wrapper around j2k-vscode (Option B)\n # j2k-vscode is currently editor-only; needs a fork to expose a CLI.\n # external: `command` is a fully-formed script that takes <java_in> <kt_out>\n # scripts/passthrough-j2k.sh is a 3-line no-op shim that lets\n # the claude-skill refinement step do the whole conversion.\n strategy: external\n command: scripts/passthrough-j2k.sh\n args: []\n timeout_seconds: 1800\n\nskills:\n # Vendored JetBrains kotlin-agent-skills (git submodule). We never edit the\n # files under here; we just point claude -p at them.\n root: vendored-skills/upstream/skills\n java_to_kotlin: kotlin-tooling-java-to-kotlin/SKILL.md\n agp9_migration: kotlin-tooling-agp9-migration/SKILL.md\n\ngradle:\n wrapper: ./gradlew\n # {module} is templated in at run-time from project.module.\n test_command: \":{module}:compileKotlinJvm :{module}:test\"\n timeout_seconds: 1800\n\nanalysis:\n # javalang = proper AST; regex = no extra dep, less accurate.\n parser: javalang\n separate_tests: true\n # Files importing any of these are risk-bumped.\n reflection_imports:\n - java.lang.reflect\n - sun.misc.Unsafe\n high_threshold: 3\n medium_threshold: 1\n\nverify:\n max_retries: 3\n\ngit:\n commit_per_file: true\n author: \"\"\n\n# When claude -p hits the 5-hour subscription window, fall through to a\n# different API for the rest of that window. The orchestrator remembers when\n# the window resets and resumes claude automatically.\nfallback:\n enabled: false # flip to true once DEEPSEEK_API_KEY is exported\n return_to_claude_after_window: true\n backend: deepseek\n deepseek:\n base_url: https://api.deepseek.com\n api_key_env: DEEPSEEK_API_KEY\n model: deepseek-chat\n temperature: 0.1\n max_tokens: 16384\n timeout_seconds: 600\n\nstate:\n dir: state\n"}, "d8ff3fbafe1f1018d9e31515eaa7e315f4f94d58": {"t": 1785755914.3528345, "n": 2606, "h": "b7818cd872b6ec34", "c": "# Java -> Kotlin conversion pipeline config.\n# Paths are resolved relative to this file unless absolute.\n\nproject:\n # Root containing the Java source tree to convert.\n # For the tuweni smoke test we point at the bytes module.\n source_root: ~/tuweni-gemma4-pipe/bytes/src/main/java\n test_root: ~/tuweni-gemma4-pipe/bytes/src/test/java\n output_root: output\n\nllm:\n base_url: http://localhost:1234/v1\n model_name: google/gemma-4-31b\n temperature: 0.1\n # Hard upper bound on completion tokens per request. Set well below\n # LM Studio's loaded context length (64141 here) so input+output fits.\n # Big translations (Bytes.java is ~19K input tokens, ~17K output) need\n # the headroom. 48000 leaves ~16K for prompt, fine for files up to\n # ~1500 LOC of Java.\n max_tokens: 48000\n # Per-request HTTP/LLM timeout. A full translation of a ~1700-LOC file at\n # ~19 sec/LOC observed throughput (Gemma 31B Q4_K_M on M1, no_think) wants\n # ~55 min, so 3600 gives generous headroom.\n timeout_seconds: 3600\n # Transient-error retry (network/HTTP) — distinct from the semantic retry loop.\n transient_retries: 3\n transient_backoff_seconds: 5\n # Best-effort reasoning suppression. Each backend reads one of these at most;\n # sending all of them lets the OpenAI / vLLM / Qwen-style servers each pick\n # up the knob they honour. The prompt itself also instructs the model to\n # skip deliberation — that's the load-bearing layer.\n reasoning_effort: minimal\n enable_thinking: false\n no_think: true\n\ntranslate:\n # Max number of direct-dependency signature blocks to splice into the prompt.\n max_dependency_signatures: 12\n # Hard truncation on each dep signature blob to keep prompt size bounded.\n max_signature_chars: 4000\n\nverify:\n # per_file = compile each .kt against already-converted deps after translation.\n # per_module = compile the entire output tree once at the end.\n # both = per_file during the run + a final per_module sweep.\n mode: both\n # Bound on semantic retries when kotlinc rejects a file.\n max_retries: 3\n # Extra classpath JARs (absolute paths) used at per_file and per_module\n # compile time. Inline list, merged with any paths from classpath_file.\n extra_classpath: []\n # Optional file holding one absolute JAR path per line. Regenerated by\n # running scripts/resolve-classpath.sh against the source project.\n classpath_file: state/classpath.txt\n\ndiscover:\n # regex (default) or javalang (more accurate, requires `pip install javalang`).\n parser: regex\n # If true, test files are treated as a separate (later) batch.\n separate_tests: true\n\nstate:\n dir: state\n"}, "16ded820b766dbaf694ba7ed409f18d2b676d03a": {"t": 1785755915.691009, "n": 2170, "h": "eb11e00f358ac902", "c": "# Java -> Kotlin conversion pipeline config.\n# Paths are resolved relative to this file unless absolute.\n\nproject:\n # Root containing the Java source tree to convert.\n # For the tuweni smoke test we point at the bytes module.\n source_root: ~/tuweni-gemma4-pipe/bytes/src/main/java\n test_root: ~/tuweni-gemma4-pipe/bytes/src/test/java\n output_root: output\n\nllm:\n base_url: http://localhost:1234/v1\n model_name: google/gemma-4-31b\n temperature: 0.1\n # Cap; translate.py also sizes the request based on the input length.\n max_tokens: 16384\n timeout_seconds: 600\n # Transient-error retry (network/HTTP) — distinct from the semantic retry loop.\n transient_retries: 3\n transient_backoff_seconds: 5\n # Best-effort reasoning suppression. Each backend reads one of these at most;\n # sending all of them lets the OpenAI / vLLM / Qwen-style servers each pick\n # up the knob they honour. The prompt itself also instructs the model to\n # skip deliberation — that's the load-bearing layer.\n reasoning_effort: minimal\n enable_thinking: false\n no_think: true\n\ntranslate:\n # Max number of direct-dependency signature blocks to splice into the prompt.\n max_dependency_signatures: 12\n # Hard truncation on each dep signature blob to keep prompt size bounded.\n max_signature_chars: 4000\n\nverify:\n # per_file = compile each .kt against already-converted deps after translation.\n # per_module = compile the entire output tree once at the end.\n # both = per_file during the run + a final per_module sweep.\n mode: both\n # Bound on semantic retries when kotlinc rejects a file.\n max_retries: 3\n # Extra classpath JARs (absolute paths) used at per_file and per_module\n # compile time. Inline list, merged with any paths from classpath_file.\n extra_classpath: []\n # Optional file holding one absolute JAR path per line. Regenerated by\n # running scripts/resolve-classpath.sh against the source project.\n classpath_file: state/classpath.txt\n\ndiscover:\n # regex (default) or javalang (more accurate, requires `pip install javalang`).\n parser: regex\n # If true, test files are treated as a separate (later) batch.\n separate_tests: true\n\nstate:\n dir: state\n"}, "a7f693d0c9774ba3e4b64ff7bcce7732691ee9d3": {"t": 1785755916.9549055, "n": 1812, "h": "7a12ff71f01129ef", "c": "# Java -> Kotlin conversion pipeline config.\n# Paths are resolved relative to this file unless absolute.\n\nproject:\n # Root containing the Java source tree to convert.\n # For the tuweni smoke test we point at the bytes module.\n source_root: ~/tuweni-gemma4-pipe/bytes/src/main/java\n test_root: ~/tuweni-gemma4-pipe/bytes/src/test/java\n output_root: output\n\nllm:\n base_url: http://localhost:1234/v1\n model_name: google/gemma-4-31b\n temperature: 0.1\n # Cap; translate.py also sizes the request based on the input length.\n max_tokens: 16384\n timeout_seconds: 600\n # Transient-error retry (network/HTTP) — distinct from the semantic retry loop.\n transient_retries: 3\n transient_backoff_seconds: 5\n\ntranslate:\n # Max number of direct-dependency signature blocks to splice into the prompt.\n max_dependency_signatures: 12\n # Hard truncation on each dep signature blob to keep prompt size bounded.\n max_signature_chars: 4000\n\nverify:\n # per_file = compile each .kt against already-converted deps after translation.\n # per_module = compile the entire output tree once at the end.\n # both = per_file during the run + a final per_module sweep.\n mode: both\n # Bound on semantic retries when kotlinc rejects a file.\n max_retries: 3\n # Extra classpath JARs (absolute paths) used at per_file and per_module\n # compile time. Inline list, merged with any paths from classpath_file.\n extra_classpath: []\n # Optional file holding one absolute JAR path per line. Regenerated by\n # running scripts/resolve-classpath.sh against the source project.\n classpath_file: state/classpath.txt\n\ndiscover:\n # regex (default) or javalang (more accurate, requires `pip install javalang`).\n parser: regex\n # If true, test files are treated as a separate (later) batch.\n separate_tests: true\n\nstate:\n dir: state\n"}, "a4c10e0ed89b7cbd50b3a82ce5af843026be20e2": {"t": 1785755918.260649, "n": 1557, "h": "fde47463395d74fc", "c": "# Java -> Kotlin conversion pipeline config.\n# Paths are resolved relative to this file unless absolute.\n\nproject:\n # Root containing the Java source tree to convert.\n # For the tuweni smoke test we point at the bytes module.\n source_root: ~/tuweni-gemma4-pipe/bytes/src/main/java\n test_root: ~/tuweni-gemma4-pipe/bytes/src/test/java\n output_root: output\n\nllm:\n base_url: http://localhost:1234/v1\n model_name: google/gemma-4-31b\n temperature: 0.1\n # Cap; translate.py also sizes the request based on the input length.\n max_tokens: 16384\n timeout_seconds: 600\n # Transient-error retry (network/HTTP) — distinct from the semantic retry loop.\n transient_retries: 3\n transient_backoff_seconds: 5\n\ntranslate:\n # Max number of direct-dependency signature blocks to splice into the prompt.\n max_dependency_signatures: 12\n # Hard truncation on each dep signature blob to keep prompt size bounded.\n max_signature_chars: 4000\n\nverify:\n # per_file = compile each .kt against already-converted deps after translation.\n # per_module = compile the entire output tree once at the end.\n # both = per_file during the run + a final per_module sweep.\n mode: both\n # Bound on semantic retries when kotlinc rejects a file.\n max_retries: 3\n # Extra classpath JARs (absolute paths) used at per_file compile time.\n extra_classpath: []\n\ndiscover:\n # regex (default) or javalang (more accurate, requires `pip install javalang`).\n parser: regex\n # If true, test files are treated as a separate (later) batch.\n separate_tests: true\n\nstate:\n dir: state\n"}, "16a9a7aa185ca967be77cd9d1b8e64b5a70e7cb2": {"t": 1785755919.5011258, "n": 1561, "h": "da03a24d27cf2fca", "c": "# Java -> Kotlin conversion pipeline config.\n# Paths are resolved relative to this file unless absolute.\n\nproject:\n # Root containing the Java source tree to convert.\n # For the tuweni smoke test we point at the bytes module.\n source_root: ~/tuweni-gemma4-pipe/bytes/src/main/java\n test_root: ~/tuweni-gemma4-pipe/bytes/src/test/java\n output_root: output\n\nllm:\n base_url: http://localhost:1234/v1\n model_name: google/gemma-4-26b-a4b\n temperature: 0.1\n # Cap; translate.py also sizes the request based on the input length.\n max_tokens: 16384\n timeout_seconds: 600\n # Transient-error retry (network/HTTP) — distinct from the semantic retry loop.\n transient_retries: 3\n transient_backoff_seconds: 5\n\ntranslate:\n # Max number of direct-dependency signature blocks to splice into the prompt.\n max_dependency_signatures: 12\n # Hard truncation on each dep signature blob to keep prompt size bounded.\n max_signature_chars: 4000\n\nverify:\n # per_file = compile each .kt against already-converted deps after translation.\n # per_module = compile the entire output tree once at the end.\n # both = per_file during the run + a final per_module sweep.\n mode: both\n # Bound on semantic retries when kotlinc rejects a file.\n max_retries: 3\n # Extra classpath JARs (absolute paths) used at per_file compile time.\n extra_classpath: []\n\ndiscover:\n # regex (default) or javalang (more accurate, requires `pip install javalang`).\n parser: regex\n # If true, test files are treated as a separate (later) batch.\n separate_tests: true\n\nstate:\n dir: state\n"}}}}