claudeos-core 2.5.0 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  Quick navigation to recent releases:
6
6
 
7
+ - [`2.5.2`](#252--2026-09-09) — Safety patch: URL passwords the masking rule cannot reach are dropped whole (raw `/` `?` `#` space, digit-leading, `@` in a query string), `host`/`apiTarget` never carry the sentinel, `init` names the dropped keys. Scanner byte-identical to 2.5.1.
8
+ - [`2.5.1`](#251--2026-09-08) — Legacy JVM detection (non-Boot Spring 1.x–6.x, Ant / Ivy, Eclipse / IntelliJ / NetBeans metadata, `WEB-INF/lib` jars, `web.xml`, Maven multi-module and sibling projects, eGovFrame), `.env` key-name redaction gaps closed, `.env.example` DB detection, LF line endings
7
9
  - [`2.5.0`](#250--2026-09-07) — Correctness release: append-only `decision-log.md`, read-only `health`, user-owned rules survive `--force`, flat-layout Java detection, Java multi-module + Next.js route groups, orchestrator-written path allowlist, `.env` credential masking
8
10
  - [`2.4.4`](#244--2026-05-04) — Translation polish for `docs/{lang}/` × 8 non-Korean languages + broken `#quick-start` anchor fix
9
11
  - [`2.4.3`](#243--2026-04-27) — Skills catalog reconciliation (MANIFEST ↔ §6 sync) + `STALE_PATH` naming-convention placeholder exemption
@@ -27,6 +29,92 @@ For older entries scroll past v1.5.0 or use the GitHub blame view.
27
29
 
28
30
  ---
29
31
 
32
+ ## [2.5.2] — 2026-09-09
33
+
34
+ Safety patch. v2.5.0 introduced URL credential masking and v2.5.1 closed its key-name gaps; this release closes the shapes the masking rule itself cannot reach. **Scope is deliberately narrow.** `plan-installer/scanners/scan-java.js` and `plan-installer/stack-detector.js` are **byte-identical to v2.5.1**, so no detection, domain or counting behavior changes at all. The Java layout work that was originally staged for this version (eGovFrame `web/` HTTP layers, `*/impl/` sub-layers, directory-fallback corrections) is withdrawn and deferred: independent review reproduced hard failures in it, including a scanner crash and a zero-domain `init` abort on trees v2.5.1 handled correctly. Shipping the credential fixes on their own is worth more than shipping them attached to a scanner regression.
35
+
36
+ `project-analysis.json` gains one optional array (`stack.envInfo.credentialWarnings`); two existing fields (`stack.envInfo.host`, `stack.envInfo.apiTarget`) can now be `null` where they previously carried a sentinel string. Test suite: 974 → **981 / 981** pass (7 added).
37
+
38
+ ### Fixed — safety
39
+
40
+ - **A URL password the userinfo rule cannot rewrite is no longer written verbatim.** v2.5.0 masks userinfo between `://` and the last `@` of the authority, and deliberately does not rewrite an `@` that appears after the first `/`, because such an `@` normally belongs to the path (`https://cdn.example.com/npm/@scope/pkg`) and rewriting it would replace the real host. `postgres://app:pa/ss@db:5432/app` therefore passed through unchanged, and because its key is `DATABASE_URL` the key-name rule did not backstop it either. That was the remaining combination able to put a plaintext password into `project-analysis.json`, which the Pass 3/4 prompts instruct the model to read. v2.5.1 recorded it as an accepted limit on the grounding that such a value is not a valid URL; the base64 alphabet contains `/`, so generated passwords hit the shape routinely.
41
+
42
+ `hasUnmaskedUrlCredentials` locates the `@` that actually terminates an authority: the last one followed by something that can be a host, optionally `:port`, then a delimiter or end of value. If the text before it holds no `/`, the userinfo rule already handled the value. If it does, the real authority ran past the point where that rule was forced to stop, and the **whole value** is dropped (`***REDACTED***`) rather than partially rewritten. Once the authority is ambiguous the host cannot be located reliably, and a lost host is a far cheaper failure than a leaked credential.
43
+
44
+ Three shapes beyond the original `/` case are caught. A password **beginning with digits** (`postgres://user:12345/6@db/app`) defeats any check that reasons from the truncated authority, since `user:12345` reads as a valid `host:port`. A password holding a **space** is invisible to the userinfo rule, whose character class excludes whitespace. And a DSN that also carries an `@` **inside a query parameter** — an email address, a redirect URL — must not end the search early; the scan continues past that `@` to the earlier one that terminates the real authority.
45
+
46
+ `user:12345` and `a.com:8080` are syntactically indistinguishable, so where the ambiguity is irreducible the scheme breaks the tie: for a DSN the value is treated as credentials, for `http`/`https`/`ws`/`wss` — where an `@` inside a path is routine — a head that is already a complete `host[:port]` means the authority ended there. Three further guards keep credential-free values intact: a bracketed IPv6 literal can only be a host, an `@` that sits in a query string after a path has begun is query content, and an unexpanded `${VAR}` template holds no live secret. Both corpora are pinned as tests: thirteen flagged shapes and twenty-six that must not flag.
47
+
48
+ - **`envInfo.host` and `envInfo.apiTarget` never carry the sentinel.** Both are rendered straight into CLAUDE.md §3, and the scaffold's only sentinel instruction covers `envInfo.vars`, so a dropped value reached the generated document as a literal `| API Proxy Target | ***REDACTED*** |` row. They are `null` instead, which the scaffold already handles by omitting the row.
49
+
50
+ - **`init` says which key it dropped.** Losing a `DATABASE_URL` silently looks like a detection bug. Phase 1 now names the affected keys — key names only, never any part of the value — for the root `.env` **and** for a sub-directory SPA's own `.env`, which the first cut of this warning did not read.
51
+
52
+ ### Withdrawn
53
+
54
+ - The Java layout work staged for v2.5.2 is not in this release. Independent review of it reproduced, against v2.5.1 as the baseline: a `TypeError` crash out of `scanJavaDomains` on a class name containing `Constructor`; a zero-domain result that aborts `init` on a single-domain legacy tree v2.5.1 scanned correctly; and five shapes that silently dropped real domains or their files, including numbered eGovFrame controllers (`EgovSample2Controller`) and any domain whose package name appears in an internal skip list. The 1,016-test suite in that revision passed while every one of those defects was live. The feature is worth having and will return once it is verified against those shapes rather than against the layouts it was designed for.
55
+
56
+ ### Behavior changes
57
+
58
+ Three observable changes, all in `.env` handling:
59
+
60
+ - A URL value whose userinfo the masking rule cannot rewrite is dropped whole instead of passing through. This covers a password holding a raw `/`, `?`, `#` or space, or one beginning with digits. The v2.5.0 assertion pinning the old pass-through result for `postgres://app:pa/ss@db:5432/app` is superseded, not relaxed. Percent-encode the password (`/` as `%2F`) to keep scheme, host and path visible in the generated docs.
61
+ - `envInfo.host` and `envInfo.apiTarget` are `null` rather than `"***REDACTED***"` when their value was dropped, so the corresponding CLAUDE.md §3 row is omitted instead of showing the sentinel.
62
+ - `init` prints a Phase 1 warning naming the keys it dropped. No value material is printed.
63
+
64
+ ### Known limits
65
+
66
+ - Where a URL's authority is genuinely ambiguous the scheme decides, so an `https://` value whose password both begins with digits and contains a `/` (`https://user:12345/6@host/x`) is read as a path and left masked-through. Ordinary HTTP basic-auth credentials, and every DSN scheme, are caught.
67
+ - Oracle-style JDBC DSNs (`jdbc:oracle:thin:scott/tiger@//dbhost:1521/ORCL`) are still not masked by any rule: the `://` gate cannot match them, the scheme-less branch fires only on the Go/MySQL `@tcp(`/`@unix(` shape, and neither `SPRING_DATASOURCE_URL` nor `JDBC_URL` trips a key-name rule. This shape is common in the legacy-Java trees v2.5.1 opened up and is the largest remaining hole; it is called out here rather than left implicit.
68
+ - Gradle build files are still not comment-stripped (Maven poms are), so a `//`-commented Spring coordinate still counts, as it always has for Boot.
69
+ - Cross-file inheritance (a corporate parent pom that itself extends `spring-boot-starter-parent`; a version held only in a parent pom outside the repository) remains out of scope; the resulting `null` falls through to LLM-side analysis.
70
+
71
+ ### Migration
72
+
73
+ None required, and no scanner output changes: domains, counts and patterns are exactly what v2.5.1 produced. If a project's `.env` holds a URL password containing a raw `/`, `?`, `#` or space, or one beginning with digits, that value is now dropped from `project-analysis.json` and `init` says so in Phase 1. Percent-encode the password and re-run to restore the host.
74
+
75
+ ## [2.5.1] — 2026-09-08
76
+
77
+ Patch release. Two things: the v2.5.0 credential-masking headline had a hole in it, and `init` on pre-Boot Java projects — the shape of most enterprise/SI codebases — reported "No language detected" and stopped. One new file (`plan-installer/jvm-detect.js`, pure text functions). `project-analysis.json` gains optional, additive fields only (`stack.packaging`, `stack.springFrameworkVersion`, `stack.sourceLayout`); no existing field changes type or meaning, and the `detected` array of every Spring Boot project is byte-identical to v2.5.0 output. Test suite: 825 → **974 / 974** pass (149 added, 0 changed).
78
+
79
+ ### Fixed — safety
80
+
81
+ - **`.env` key-name redaction had gaps.** v2.5.0 masked URL userinfo and connection parameters (`?password=`), and its `PARAM_RE` accepted `pass` as a parameter name — but the key-name rule beside it did not, so `DB_PASS=hunter2` was written verbatim into `project-analysis.json`. Closed, together with the other abbreviated and less-common names found by a 71-name sweep: `PASS` / `PW` (segment-anchored: `DB_PASS`, `ADMIN_PW`, `MYSQL_PASS` are redacted; `BYPASS_AUTH`, `PASSENGER_APP_ENV`, `COMPASS_URL`, `PWD` are not), `PASSPHRASE`, `PEPPER` (trailing segment only — `PEPPER_ROUNDS` is a cost parameter), `SSH_KEY` (anchored — `SSH_KEYSCAN_HOSTS` is a host list), `SIGNING_KEY`, `MASTER_KEY`, `DEPLOY_KEY`, `LICENSE_KEY`, `SERVER_KEY` (each anchored — `MASTER_KEYSPACE`, `SERVER_KEYSTORE_PATH` survive), and `SERVICE_ACCOUNT` / `SERVICE_ACCOUNT_{KEY,JSON,FILE,SECRET,TOKEN,CREDENTIALS}` (but not `SERVICE_ACCOUNT_EMAIL` / `_NAME` / `_ID`, which identify the account rather than authenticate as it). Deliberately **not** a blanket `*_KEY` rule: `ROUTING_KEY`, `PARTITION_KEY`, `SORT_KEY`, `IDEMPOTENCY_KEY`, `FOREIGN_KEY_CHECKS` are architecture facts the generated docs depend on. Known accepted over-match: a leading `PASS_` segment (`PASS_RATE`) — narrowing it to a trailing segment would drop `DB_PASS_2` / `PASS_FILE`, and the two failure modes are not symmetric. Both corpora (71 secret names, 53 benign names) are pinned as tests. End-to-end: seven canary secrets planted in `.env.example` appear in **none** of the six generated files; in v2.5.0 five of them did.
82
+ - **`.env.example`-only repositories never had their database detected.** `lib/env-parser.js` has always treated `.env.example` as canonical (it heads `ENV_FILE_ORDER`), but the DB-type scan in `stack-detector` read only `.env` / `.env.local` / `.env.development` — files that are gitignored in most repos — so a fresh clone with a committed `DATABASE_URL=postgres://…` template reported `database: null`. Templates (`.env.example`, `.env.sample`, `.env.template`) are now consulted, under two guards that keep the change strictly additive: only when no runtime env file *declared* a `DATABASE_URL` (a `jdbc:oracle:thin:@…` the keyword list does not cover still counts as declared), and only when no other source — build file, `application.yml`, **`schema.prisma`** — has already identified a database. The fallback runs *after* the Prisma block for that reason: a placeholder can never win the `if (!stack.database)` race against a declaration.
83
+
84
+ ### Added — legacy JVM detection
85
+
86
+ `init` previously set `language: "java"` from a Gradle file only when the string `spring-boot` appeared, and never set a framework or its version from Maven unless Boot was present. A 32-case matrix of real enterprise build-file shapes passed 1 case; the release passes a 103-case matrix — 66 detection shapes plus 37 false-positive / regression guards — every case pinned as a test. Nothing is inferred from a framework default: **every version string returned is a substring of a build file, a jar name, or a property/variable defined in the same project**, and an unresolvable `${var}` yields `null`, never the literal.
87
+
88
+ - **Gradle.** `apply plugin: 'java' | 'java-library' | 'war' | 'ear' | 'application'`, the `plugins { id '…' }` DSL, Kotlin-DSL bare identifiers (`java`, `war`, `` `java-library` ``) and `apply(plugin = "…")` are all Java evidence on their own. A dependency whose group is **exactly** `org.springframework` (`spring-webmvc`, `spring-context`, the 2.x single `spring` jar, `spring-framework-bom`) — in coordinate form, `group:/name:/version:` notation, `platform()` / `mavenBom`, or a version catalog `module = "org.springframework:spring-…"` with `version.ref` — yields `framework: "spring-framework"` with the version; `org.springframework.{boot,security,data,cloud}` are other projects and are never mistaken for it. `${springVersion}` resolves against `ext { }`, `def` / `val`, and **`gradle.properties`** (in-file wins). Spring Boot 1.x/2.x `buildscript { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.22.RELEASE") }` + `apply plugin: 'spring-boot'` now yields the Boot version (the old regexes anchored on a `version` keyword that form does not have). Root `subprojects { }` blocks and sub-module build files are swept with the same rules; a `war` / `ear` plugin sets `packaging`.
89
+ - **Maven.** `<packaging>` is reported (only when declared — the implicit `jar` default is not written back). A `<dependency>` whose `<groupId>` is exactly `org.springframework` (comment-stripped, so a `<!-- … -->`-disabled dependency is ignored) yields `spring-framework`; the version comes from `spring-framework-bom` in `<dependencyManagement>`, the first versioned Framework dependency, or a `<spring.version>` / `<spring-framework.version>` / **`<spring.maven.version>`** property, with `${prop}` resolved in-file. Spring Boot's version is now also read from `spring-boot-starter-parent`'s `<version>` (bounded to the `<parent>` block) and from a `spring-boot-dependencies` BOM import — previously only a `<spring-boot.version>` property was recognized, so `frameworkVersion` was `null` for every Initializr-generated pom. Java level: `<maven.compiler.release>` and the Maven-2-era `maven-compiler-plugin` `<configuration><source>1.5</source>` (bounded to the compiler plugin's own `<plugin>` block). **Multi-module:** a root `<packaging>pom</packaging>` with `<modules>` has its listed child poms (≤30) swept for framework, versions, ORM, DB and Java level, filling only what the root left null; `${prop}` in a child resolves against the child first, then the root `<properties>`.
90
+ - **Ant / Ivy / Eclipse WTP / no build tool.** `build.xml` → `buildTool: "ant"`, Java level from `<javac source="1.6">`; `ivy.xml` `<dependency org="org.springframework" name="spring-webmvc" rev="…"/>` (org exact-match, name whitelist) → framework + version, plus ORM / DB keywords. `.classpath` / `.project` → Java level from the JRE container (`JavaSE-1.7`, `J2SE-1.5`), `javanature`. **`**/{WEB-INF/lib,lib,libs}/*.jar`** (≤500 names) → `packaging: "war"` when under `WEB-INF`, Spring Framework / Boot presence and version parsed from the jar **name** (`spring-webmvc-3.0.5.RELEASE.jar`; an unversioned Spring-2.0-era `spring.jar` reports the framework with version `null`), JDBC drivers (`ojdbc*`, `postgresql-`, `mysql-connector`, `mariadb-java-client`, `h2-`, `sqlite-jdbc`, `mssql-jdbc` / `sqljdbc`, `db2jcc`, and the Korean-market **Tibero / Altibase / Cubrid**) and ORM jars (`ibatis-*` → `ibatis`, `mybatis-*`, `hibernate-*` / `eclipselink` / `openjpa` → `jpa`, `jooq-`). The jar scan also runs for Gradle/Maven projects whose build file still resolves from `fileTree(dir: 'lib')` instead of coordinates — common in codebases that adopted a build tool without migrating the jars — and fills nulls only. `**/*.java` is the last-resort language signal.
91
+ - **Spring 1.x.** Spring 1.0–1.2 published under the bare group `springframework` (no `org.`); Maven `<groupId>springframework</groupId>`, Gradle `'springframework:spring:1.2.9'` and Ivy `org="springframework"` are recognized alongside `org.springframework`. Still exact-match: `myspringframework` / `springframework.fake` are not it.
92
+ - **Gradle declaration long tail.** `group:` / `name:` / `version:` map notation in **any key order**, single- or multi-line; `${project.springVersion}` / `${rootProject.ext.springVersion}` / `${ext.x}` prefixes; Groovy version maps (`ext { versions = [spring: '…'] }` → `${versions.spring}`); buildSrc Kotlin constants (`object Versions { const val spring = "…" }` → `${Versions.spring}`); definitions pulled in through `apply from: 'gradle/dependencies.gradle'` (≤10 scripts, appended to the resolution text only); `options.release = 17` / `.set(17)`; a root holding only `settings.gradle{,.kts}`; `struts` / `struts2` / `jsf` coordinates add a tag in `detected` without setting a framework.
93
+ - **Repository shapes.** No root build file but sibling projects one directory down (`erp-web/pom.xml`, `erp-batch/pom.xml`) are absorbed with the Maven `<modules>` rules (`buildTool: "maven"`, depth-1 only, ≤30). JDBC coordinates for **MSSQL** (`mssql-jdbc`, `sqljdbc`, `jtds`, `sqlserver`), **DB2** (`com.ibm.db2`, `db2jcc`) and the Korean-market **Tibero / Altibase / Cubrid** are on the shared DB keyword list (additive to `stack.databases`; the primary-DB race is unchanged).
94
+ - **IDE metadata as evidence.** `.settings/org.eclipse.jdt.core.prefs` `compiler.compliance` (outranks the JRE container name), custom JRE names in `.classpath` (`jdk1.6.0_45`, `jdk-17.0.2`), `.classpath` `kind="lib"` / `kind="var"` jar paths (jars that are *not committed* — `M2_REPO/…/spring-webmvc-3.0.5.RELEASE.jar` still names the version), IntelliJ `.idea/misc.xml` `languageLevel="JDK_1_7"`, NetBeans `nbproject/project.properties` (`javac.source`, `file.reference.*.jar`). Jars under `lib/spring/`, `lib/db/` sub-folders are found (recursive under the lib roots).
95
+ - **Deployment descriptor and Spring XML.** `WEB-INF/web.xml` naming `org.springframework.web.servlet.DispatcherServlet` / `ContextLoaderListener` is Spring MVC evidence and a `war` signal; `ActionServlet` / `StrutsPrepareAndExecuteFilter` add a `struts` / `struts2` tag; `<web-app version="2.5">` adds `servlet 2.5`. `src/test/**` is excluded (a test-resources `web.xml` is not deployment evidence), and the whole block is skipped for Spring Boot projects — Boot's WAR packaging comes from the build file, and a Boot project's `detected` array stays byte-identical to v2.5.0; Struts / JSF coordinate tags are likewise not added to Boot projects. Spring XML configs' schema locations (`spring-beans-3.0.xsd`) yield a **major.minor** version — the lowest-fidelity source, consulted only when nothing else pinned a version, never overriding one (`spring-xsd 3.0` in `detected`).
96
+ - **Precedence against Node / Python.** All of the above runs *after* the Node and Python blocks and may only fill a language nobody claimed — or reclaim a *provisional* one: a root `package.json` that exists for gulp / jQuery / Tailwind tooling (no Node framework, no frontend framework detected) beside `build.xml`, a `.project` with `javanature`, a sibling pom/gradle, or a `WEB-INF/web.xml`. A Next.js / Express / Django project with a stray `.idea/misc.xml` or a vendored `tools/lib/*.jar` is never flipped to Java; a jar directory with no `*.java` sources claims nothing (no language, no framework, no DB). The reclaim is *parked*, not committed: if no JVM block then actually claims the project — a `build.xml` that is Phing or an empty stub, no `*.java` anywhere — the Node language is restored unchanged, and a `<project>` root element alone is not Ant (a `<javac>` task or `*.java` sources is required). A reclaimed Java project takes the JVM package manager (`ant` / `maven`), not the asset tooling's `npm`. EUC-KR-encoded poms with Korean comments detect normally (coordinates are ASCII).
97
+ - **eGovFrame (Korea's e-Government Standard Framework).** `egovframework.rte[.*]` coordinates (Maven or Gradle, `${egovframework.rte.version}` resolved) are reported as `spring-framework` — the templates and prompts understand Spring, and eGovFrame is Spring MVC underneath — plus an `egovframe <version>` tag in `detected`. Its `<spring.maven.version>` property is on the Framework-version property list.
98
+ - **`scan-java` reads legacy source roots.** Every pattern in the scanner is written against `src/main/java` / `src/main/resources`; those two leading segments are now rewritten per discovered root instead of being literal. Roots, in order: every `[<module>/]src/main/java` (unchanged, and if any exists the legacy fallbacks are **not** consulted — a modern tree with a stray top-level `src/` cannot be mis-rooted); otherwise `.classpath` `<classpathentry kind="src" path="…"/>` entries (test folders excluded — including a plain `test/` that `src/test/**` ignore rules would not catch), `build.xml` `<javac srcdir="${src}">` with `<property>` resolution, then `src/java`, `src`, `JavaSource`, `java`, `WebContent/WEB-INF/src` when they hold `*.java` (nested pairs keep the deeper one). For a legacy root the resources root is the java root itself — iBatis-era projects keep sqlmap XML beside the classes. `stack.sourceLayout: "legacy"` is set when a legacy root is in use. An Ant + `WEB-INF/lib` project with `src/com/acme/erp/{controller,service,dao}/` now yields `java 6 · spring-framework 3.0.5.RELEASE · oracle · ibatis · ant · war` and its three Pattern C domains; before, `init` reported "No language detected".
99
+
100
+ ### Changed
101
+
102
+ - **Line endings are LF, enforced.** A `.gitattributes` (`* text=auto eol=lf`, `*.sh eol=lf`, image types `binary`) is added. Every committed blob was already LF (`git ls-files --eol` at v2.5.0: 281 text files, all `i/lf`); the CRLF that showed up on Windows checkouts of the non-Korean `docs/{lang}/` sets, `package.json`, `.gitignore` and the CI workflow came from `core.autocrlf=true` smudging on checkout, not from the repository. The attribute file makes the working tree LF on every platform regardless of that setting and stops a CRLF blob from ever being committed. No file content changes; run `git add --renormalize .` once after pulling if `git status` lists unchanged files as modified. The suite was run on Windows with the attribute file in place (974 / 974).
103
+ - **Templates.** `java-spring/pass1.md` and `pass3.md` no longer assume Spring Boot: when `project-analysis.json` says `framework: "spring-framework"` the Pass 1 prompt reads `WEB-INF/web.xml` and the Spring XML configs instead of a non-existent `application.yml`, and is told not to describe Boot features (auto-configuration, starters, actuator) for a project that does not declare Boot. `pass-json-validator` treats `spring-framework` as a backend framework alongside `spring-boot`.
104
+ - **Docs.** `docs/stacks.md` (10 languages) lists the redaction key-name families that now apply, so the documented rule matches the code again. Supported Stacks in `README.md` names the non-Boot Java shapes, and `docs/stacks.md` gains a legacy-JVM section with a per-build-form evidence table, the version policy, the precedence chain, the false-positive guards and the source-root order. **Both are translated into all 10 languages** — identifiers, coordinates and the 11-row evidence table are byte-identical across them; only prose is localized.
105
+
106
+ ### Known limits (documented, unchanged)
107
+
108
+ - A password containing a raw `/`, `?` or `#` inside a URL's userinfo is not masked (`postgres://u:p/w@host/db`). These are RFC 3986 delimiters — an `@` after the first `/` belongs to the path (`https://cdn.example.com/npm/@scope/pkg`), and rewriting it would replace the real host — so the v2.5.0 rule stands; such a value must be percent-encoded (`%2F`). It is the one combination the key-name rule does not backstop, because the key is `DATABASE_URL`.
109
+ - Gradle build files are not comment-stripped (Maven poms are), so a `//`-commented Spring coordinate still counts — as it always has for Boot.
110
+ - Cross-file inheritance (a corporate parent pom that itself extends `spring-boot-starter-parent`; a version held only in a parent pom outside the repository) is out of scope; the resulting `null` falls through to LLM-side analysis.
111
+ - eGovFrame's default layout names its controller layer `web/` rather than `controller/`; the scanner's Pattern A/B do not yet recognize `web/` as a layer, so an `example/{web,service}/{user,board}/` tree yields a spurious `example` Pattern B domain beside the real ones. Detection output on that layout is identical to v2.5.0; a pattern change is a separate release.
112
+ - The stack-detector still passes the **redacted** `envInfo.vars` to `extractPort()` (`stack-detector.js`, `const vars = envInfo.vars || {}`). No current key-name rule intersects a port/host/api-target key (asserted across nine port-key variants), but a future blanket rule would break port detection silently; passing raw vars there is a structural follow-up.
113
+
114
+ ### Migration
115
+
116
+ None required. New `project-analysis.json` fields are additive and `null` for projects that do not declare them. Projects that previously aborted `init` with "No language detected" on a pre-Boot Java layout will now proceed through the Java pipeline; review the detected `framework` / `frameworkVersion` / `packaging` in the Phase 1 summary the first time.
117
+
30
118
  ## [2.5.0] — 2026-09-07
31
119
 
32
120
  Correctness release driven by a full-source audit of v2.4.4. No new dependencies, no new files. `project-analysis.json` gains optional, additive fields only (`stack.frontendRoot`, `stack.frontendBundler`, `stack.frontendPort`, `stack.frontendEnvInfo`, domain `pattern: "layer-first"`); pass-marker schemas are unchanged. Minor version bump because five behaviors that users could observe changed on purpose (see **Behavior changes** and **Migration**). Test suite: 736 → **825 / 825** pass (89 added, 2 legacy assertions replaced).
package/README.de.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ Pro-Pass-Details, Marker-basiertes Resume, der Staged-Rules-Workaround für die
358
358
 
359
359
  12 Stacks, automatisch aus deinen Projektdateien erkannt:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (sowie Spring Framework ohne Boot, siehe unten) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Auch Multi-Stack-Projekte funktionieren ohne Zusatzaufwand, etwa ein Spring-Boot-Backend zusammen mit einem Next.js-Frontend.
366
366
 
367
+ **Legacy-Java ist ein vollwertiges Ziel (v2.5.1).** Spring 1.x–6.x ohne Boot wird erkannt: Gradle (`apply plugin:`-Ära, `group:/name:/version:`-Notation in beliebiger Reihenfolge, Auflösung über `gradle.properties` / `apply from:` / buildSrc, Version Catalogs, Roots mit nur `settings.gradle`), Maven (Maven-2-POMs, `${spring.version}`-Properties, `spring-framework-bom`, Multi-Module-Roots, Schwesterprojekte ohne Root-POM), **Ant + Ivy**, **Metadaten von Eclipse / IntelliJ / NetBeans** (`.classpath` inklusive Verweisen auf nicht eingecheckte JARs, Compliance-Level aus `.settings`, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, Spring-XSD-Schemaversionen und **eGovFrame** — mit Framework, Spring-Framework-Version, Java-Level, `war`/`ear`-Packaging, JDBC-Treiber und ORM. Quellbäume mit `src/`-Root werden mit denselben Domain-Mustern gescannt wie `src/main/java`. Jede gemeldete Version stammt aus einer Build-Datei, einem JAR-Namen oder einer im Projekt definierten Property; nichts wird aus Framework-Defaults abgeleitet. JVM-Projekte ganz ohne Spring (`java-library`, `application`, reines Servlet-`war`) werden als Java mit `framework: null` gemeldet, niemals als Spring.
368
+
367
369
  Erkennungsregeln und die Felder, die jeder Scanner extrahiert, beschreibt [docs/de/stacks.md](docs/de/stacks.md).
368
370
 
369
371
  ---
package/README.es.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ Para los detalles de cada paso, el sistema de resume basado en marcadores, el tr
358
358
 
359
359
  12 stacks que se autodetectan a partir de los archivos del proyecto:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (y Spring Framework sin Boot, ver más abajo) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Los proyectos multi-stack (por ejemplo, backend Spring Boot con frontend Next.js) funcionan tal cual.
366
366
 
367
+ **El Java heredado es un objetivo de primera clase (v2.5.1).** Se detecta Spring 1.x–6.x sin Boot en Gradle (era de `apply plugin:`, notación `group:/name:/version:` en cualquier orden, resolución vía `gradle.properties` / `apply from:` / buildSrc, catálogos de versiones, raíces con solo `settings.gradle`), Maven (POMs de Maven 2, propiedades `${spring.version}`, `spring-framework-bom`, raíces multi-módulo, proyectos hermanos sin POM raíz), **Ant + Ivy**, **metadatos de Eclipse / IntelliJ / NetBeans** (`.classpath` incluidas las referencias a JARs no versionados, nivel de cumplimiento de `.settings`, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, versiones de esquema XSD de Spring y **eGovFrame** — con framework, versión de Spring Framework, nivel de Java, empaquetado `war`/`ear`, driver JDBC y ORM. Los árboles de fuentes con raíz `src/` se escanean con los mismos patrones de dominio que `src/main/java`. Toda versión reportada se lee de un archivo de build, del nombre de un JAR o de una propiedad definida en el proyecto; nada se supone a partir de valores por defecto del framework. Los proyectos JVM sin Spring alguno (`java-library`, `application`, `war` solo de servlets) se reportan como Java con `framework: null`, nunca como Spring.
368
+
367
369
  Las reglas de detección y lo que extrae cada scanner están en [docs/es/stacks.md](docs/es/stacks.md).
368
370
 
369
371
  ---
package/README.fr.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ Pour les détails par passe, le mécanisme de reprise par marker, le contourneme
358
358
 
359
359
  12 stacks, détectés automatiquement à partir des fichiers de votre projet.
360
360
 
361
- **Backend :** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend :** Java/Spring Boot (ainsi que Spring Framework sans Boot, voir plus bas) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend :** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Les projets multi-stack (par exemple un backend Spring Boot couplé à un frontend Next.js) fonctionnent sans configuration particulière.
366
366
 
367
+ **Le Java hérité est une cible de premier plan (v2.5.1).** Spring 1.x–6.x sans Boot est détecté : Gradle (ère `apply plugin:`, notation `group:/name:/version:` dans n'importe quel ordre, résolution via `gradle.properties` / `apply from:` / buildSrc, catalogues de versions, racines ne contenant qu'un `settings.gradle`), Maven (POM Maven 2, propriétés `${spring.version}`, `spring-framework-bom`, racines multi-modules, projets frères sans POM racine), **Ant + Ivy**, **métadonnées Eclipse / IntelliJ / NetBeans** (`.classpath` y compris les références vers des JAR non versionnés, niveau de conformité de `.settings`, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, versions de schéma XSD Spring et **eGovFrame** — avec le framework, la version de Spring Framework, le niveau Java, le packaging `war`/`ear`, le driver JDBC et l'ORM. Les arborescences dont la racine est `src/` sont scannées avec les mêmes motifs de domaine que `src/main/java`. Chaque version rapportée provient d'un fichier de build, d'un nom de JAR ou d'une propriété définie dans le projet ; rien n'est déduit des valeurs par défaut d'un framework. Les projets JVM sans aucun Spring (`java-library`, `application`, `war` purement servlet) sont rapportés comme Java avec `framework: null`, jamais comme Spring.
368
+
367
369
  Pour les règles de détection et le contenu extrait par chaque scanner, voir [docs/fr/stacks.md](docs/fr/stacks.md).
368
370
 
369
371
  ---
package/README.hi.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ Pipeline **तीन stages** में चलती है, और LLM call क
358
358
 
359
359
  12 stacks, project files से auto-detected।
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (और Boot के बिना Spring Framework, नीचे देखें) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Multi-stack projects (जैसे Spring Boot backend + Next.js frontend) भी out of the box चलते हैं।
366
366
 
367
+ **Legacy Java अब first-class target है (v2.5.1).** Boot के बिना Spring 1.x–6.x detect होता है: Gradle (`apply plugin:` युग, किसी भी क्रम में `group:/name:/version:` notation, `gradle.properties` / `apply from:` / buildSrc से resolution, version catalogs, सिर्फ़ `settings.gradle` वाले root), Maven (Maven-2 POM, `${spring.version}` properties, `spring-framework-bom`, multi-module root, बिना root POM के sibling projects), **Ant + Ivy**, **Eclipse / IntelliJ / NetBeans metadata** (`.classpath` — बिना commit किए JAR references सहित, `.settings` का compliance level, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, Spring XSD schema versions और **eGovFrame** — framework, Spring Framework version, Java level, `war`/`ear` packaging, JDBC driver और ORM के साथ। `src/`-rooted source tree भी उन्हीं domain patterns से scan होते हैं जो `src/main/java` पर लगते हैं। बताई गई हर version किसी build file, JAR के नाम या project में define की गई property से पढ़ी जाती है; framework के default से कुछ भी नहीं माना जाता। जिन JVM projects में Spring है ही नहीं (`java-library`, `application`, सिर्फ़ servlet वाला `war`) उन्हें `framework: null` के साथ Java बताया जाता है, Spring कभी नहीं।
368
+
367
369
  Detection rules और हर scanner क्या निकालता है, यह [docs/hi/stacks.md](docs/hi/stacks.md) में है।
368
370
 
369
371
  ---
package/README.ja.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ severity は 3 段階 (`fail` / `warn` / `advisory`) に分かれており、ユ
358
358
 
359
359
  12 スタックを、プロジェクトのファイルから自動で検出します。
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (Boot なしの Spring Framework も。下記参照) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  マルチスタックのプロジェクト (例: Spring Boot バックエンド + Next.js フロントエンド) もそのまま動きます。
366
366
 
367
+ **レガシー Java は第一級の対象です (v2.5.1)。** Boot なしの Spring 1.x–6.x を検出します。Gradle (`apply plugin:` 時代、順序を問わない `group:/name:/version:` 記法、`gradle.properties` / `apply from:` / buildSrc による解決、バージョンカタログ、`settings.gradle` だけのルート)、Maven (Maven 2 の POM、`${spring.version}` プロパティ、`spring-framework-bom`、マルチモジュールのルート、ルート POM のない兄弟プロジェクト)、**Ant + Ivy**、**Eclipse / IntelliJ / NetBeans のメタデータ** (コミットされていない JAR への参照を含む `.classpath`、`.settings` のコンプライアンスレベル、`.idea/misc.xml`、`nbproject`)、`WebContent/WEB-INF/lib/**/*.jar`、`WEB-INF/web.xml`、Spring XSD のスキーマバージョン、そして **eGovFrame** — フレームワーク、Spring Framework のバージョン、Java レベル、`war`/`ear` パッケージング、JDBC ドライバ、ORM まで取得します。`src/` をルートとするソースツリーも `src/main/java` と同じドメインパターンでスキャンされます。報告されるバージョンはすべてビルドファイル・JAR 名・プロジェクト内で定義されたプロパティから読み取ったもので、フレームワークのデフォルトから推測することはありません。Spring をまったく使わない JVM プロジェクト (`java-library`、`application`、サーブレットのみの `war`) は `framework: null` の Java として報告され、Spring とされることはありません。
368
+
367
369
  検出ルールと各スキャナが取り出す情報については [docs/ja/stacks.md](docs/ja/stacks.md) を参照してください。
368
370
 
369
371
  ---
package/README.ko.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ ClaudeOS-Core는 일반적인 Claude Code 워크플로를 거꾸로 뒤집습니
358
358
 
359
359
  12개 스택을 프로젝트 파일에서 자동으로 감지합니다:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (Boot 없는 Spring Framework 포함, 아래 참고) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  멀티 스택 프로젝트 (예: Spring Boot 백엔드 + Next.js 프론트엔드)도 그대로 동작합니다.
366
366
 
367
+ **레거시 Java도 1급 대상입니다 (v2.5.1).** Boot 없는 Spring 1.x–6.x를 탐지합니다. Gradle (`apply plugin:` 시절, 순서 무관한 `group:/name:/version:` 표기, `gradle.properties` / `apply from:` / buildSrc를 통한 변수 해석, 버전 카탈로그, `settings.gradle`만 있는 루트), Maven (Maven 2 POM, `${spring.version}` 프로퍼티, `spring-framework-bom`, 멀티 모듈 루트, 루트 POM 없는 형제 프로젝트), **Ant + Ivy**, **Eclipse / IntelliJ / NetBeans 메타데이터** (커밋되지 않은 JAR 참조를 포함한 `.classpath`, `.settings`의 compliance 레벨, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, Spring XSD 스키마 버전, 그리고 **eGovFrame (전자정부 표준프레임워크)** 까지 — 프레임워크, Spring Framework 버전, Java 레벨, `war`/`ear` 패키징, JDBC 드라이버, ORM을 뽑아냅니다. `src/`를 루트로 하는 소스 트리도 `src/main/java`와 동일한 도메인 패턴으로 스캔합니다. 보고되는 모든 버전은 빌드 파일, JAR 이름, 또는 프로젝트 안에 정의된 프로퍼티에서 읽은 값이며 프레임워크 기본값으로 추정하지 않습니다. Spring을 전혀 쓰지 않는 JVM 프로젝트 (`java-library`, `application`, 서블릿만 쓰는 `war`)는 `framework: null`인 Java로 보고되며 Spring으로 잡히지 않습니다.
368
+
367
369
  감지 규칙과 각 scanner가 추출하는 내용은 [docs/ko/stacks.md](docs/ko/stacks.md) 참고.
368
370
 
369
371
  ---
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ For per-pass details, marker-based resume, the staged-rules workaround for Claud
358
358
 
359
359
  12 stacks, auto-detected from your project files:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (and non-Boot Spring Framework, see below) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Multi-stack projects (e.g., Spring Boot backend + Next.js frontend) work out of the box.
366
366
 
367
+ **Legacy Java is a first-class target (v2.5.1).** Pre-Boot Spring 1.x–6.x on Gradle (`apply plugin:` era, `group:/name:/version:` notation in any order, `gradle.properties` / `apply from:` / buildSrc indirection, version catalogs, settings-only roots), Maven (Maven-2 poms, `${spring.version}` properties, `spring-framework-bom`, multi-module roots, sibling projects with no root pom), **Ant + Ivy**, **Eclipse / IntelliJ / NetBeans metadata** (`.classpath` incl. uncommitted jar references, `.settings` compliance level, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, Spring XSD schema versions and **eGovFrame** are detected — framework, Spring Framework version, Java level, `war`/`ear` packaging, JDBC driver and ORM — and `src/`-rooted source trees are scanned with the same domain patterns as `src/main/java`. Every version reported is read from a build file, a jar name or a property defined in the project; nothing is assumed from a framework default. JVM projects with no Spring at all (`java-library`, `application`, servlet-only `war`) are reported as Java with `framework: null`, never as Spring.
368
+
367
369
  For detection rules and what each scanner extracts, see [docs/stacks.md](docs/stacks.md).
368
370
 
369
371
  ---
package/README.ru.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ ClaudeOS-Core переворачивает привычный сценарий
358
358
 
359
359
  12 стеков, которые определяются автоматически по файлам проекта:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (а также Spring Framework без Boot, см. ниже) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Многостековые проекты (например, Spring Boot на бэкенде и Next.js на фронтенде) поддерживаются из коробки.
366
366
 
367
+ **Legacy-Java — полноценная цель (v2.5.1).** Распознаётся Spring 1.x–6.x без Boot: Gradle (эпоха `apply plugin:`, нотация `group:/name:/version:` в любом порядке, разрешение переменных через `gradle.properties` / `apply from:` / buildSrc, каталоги версий, корни только с `settings.gradle`), Maven (POM времён Maven 2, свойства `${spring.version}`, `spring-framework-bom`, многомодульные корни, соседние проекты без корневого POM), **Ant + Ivy**, **метаданные Eclipse / IntelliJ / NetBeans** (`.classpath`, включая ссылки на JAR, которых нет в репозитории, уровень compliance из `.settings`, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, версии XSD-схем Spring и **eGovFrame** — вместе с фреймворком, версией Spring Framework, уровнем Java, упаковкой `war`/`ear`, JDBC-драйвером и ORM. Деревья исходников с корнем `src/` сканируются теми же доменными шаблонами, что и `src/main/java`. Любая выводимая версия прочитана из файла сборки, имени JAR или свойства, определённого в самом проекте; ничего не берётся из значений по умолчанию фреймворка. JVM-проекты вовсе без Spring (`java-library`, `application`, чисто сервлетный `war`) выводятся как Java с `framework: null` и никогда как Spring.
368
+
367
369
  Правила детекции и то, что вытаскивает каждый сканер, описаны в [docs/ru/stacks.md](docs/ru/stacks.md).
368
370
 
369
371
  ---
package/README.vi.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ Cốt lõi gắn kết tất cả lại là một bất biến: **Claude chỉ
358
358
 
359
359
  12 stack, tự động phát hiện từ chính các file dự án.
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (và Spring Framework không dùng Boot, xem bên dưới) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  Dự án multi-stack (chẳng hạn Spring Boot backend cộng Next.js frontend) chạy được luôn mà không cần điều chỉnh.
366
366
 
367
+ **Java cũ là mục tiêu hạng nhất (v2.5.1).** Spring 1.x–6.x không dùng Boot được nhận diện: Gradle (thời `apply plugin:`, cách viết `group:/name:/version:` theo thứ tự bất kỳ, phân giải biến qua `gradle.properties` / `apply from:` / buildSrc, version catalog, root chỉ có `settings.gradle`), Maven (POM thời Maven 2, property `${spring.version}`, `spring-framework-bom`, root multi-module, các project anh em không có POM gốc), **Ant + Ivy**, **metadata của Eclipse / IntelliJ / NetBeans** (`.classpath` kể cả tham chiếu tới JAR không commit, mức compliance trong `.settings`, `.idea/misc.xml`, `nbproject`), `WebContent/WEB-INF/lib/**/*.jar`, `WEB-INF/web.xml`, version schema XSD của Spring và **eGovFrame** — kèm framework, version Spring Framework, mức Java, packaging `war`/`ear`, driver JDBC và ORM. Cây source lấy `src/` làm gốc cũng được quét bằng đúng các domain pattern như `src/main/java`. Mọi version báo ra đều đọc từ file build, tên JAR hoặc property định nghĩa trong chính project; không suy ra từ giá trị mặc định của framework. Project JVM hoàn toàn không có Spring (`java-library`, `application`, `war` chỉ dùng servlet) được báo là Java với `framework: null`, không bao giờ là Spring.
368
+
367
369
  Quy tắc phát hiện và những gì mỗi scanner trích xuất được mô tả trong [docs/vi/stacks.md](docs/vi/stacks.md).
368
370
 
369
371
  ---
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/claudeos-core.svg?logo=npm&label=npm)](https://www.npmjs.com/package/claudeos-core)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/claudeos-core/claudeos-core/test.yml?branch=master&logo=github&label=CI)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
- [![tests](https://img.shields.io/badge/tests-825%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
5
+ [![tests](https://img.shields.io/badge/tests-981%20passing-brightgreen?logo=node.js&logoColor=white)](https://github.com/claudeos-core/claudeos-core/actions/workflows/test.yml)
6
6
  [![node](https://img.shields.io/node/v/claudeos-core.svg?logo=node.js&logoColor=white&label=node)](https://nodejs.org/)
7
7
  [![license](https://img.shields.io/npm/l/claudeos-core.svg?color=blue)](LICENSE)
8
8
  [![downloads](https://img.shields.io/npm/dm/claudeos-core.svg?logo=npm&color=blue&label=downloads)](https://www.npmjs.com/package/claudeos-core)
@@ -358,12 +358,14 @@ severity 分三档 (`fail` / `warn` / `advisory`),这样用户能手动修掉的
358
358
 
359
359
  12 种技术栈,从项目文件里自动识别:
360
360
 
361
- **Backend:** Java/Spring Boot · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
361
+ **Backend:** Java/Spring Boot (以及不用 Boot 的 Spring Framework,见下文) · Kotlin/Spring Boot · Node/Express · Node/Fastify · Node/NestJS · Python/Django · Python/FastAPI · Python/Flask
362
362
 
363
363
  **Frontend:** Node/Next.js · Node/Vite · Angular · Vue/Nuxt
364
364
 
365
365
  多栈项目 (例如 Spring Boot 后端 + Next.js 前端) 也能直接跑。
366
366
 
367
+ **遗留 Java 是一等目标 (v2.5.1)。** 可识别不使用 Boot 的 Spring 1.x–6.x:Gradle (`apply plugin:` 时代、顺序任意的 `group:/name:/version:` 写法、通过 `gradle.properties` / `apply from:` / buildSrc 解析变量、版本目录、只有 `settings.gradle` 的根目录)、Maven (Maven 2 时代的 POM、`${spring.version}` 属性、`spring-framework-bom`、多模块根、没有根 POM 的同级项目)、**Ant + Ivy**、**Eclipse / IntelliJ / NetBeans 元数据** (`.classpath`,包括指向未提交 JAR 的引用、`.settings` 中的 compliance 级别、`.idea/misc.xml`、`nbproject`)、`WebContent/WEB-INF/lib/**/*.jar`、`WEB-INF/web.xml`、Spring XSD 架构版本,以及 **eGovFrame** — 连同框架、Spring Framework 版本、Java 级别、`war`/`ear` 打包方式、JDBC 驱动和 ORM 一并给出。以 `src/` 为根的源码树也会用与 `src/main/java` 相同的 domain 模式扫描。报告的每个版本都来自构建文件、JAR 文件名或项目内定义的属性;不会依据框架默认值推测。完全不用 Spring 的 JVM 项目 (`java-library`、`application`、仅有 servlet 的 `war`) 会被报告为 `framework: null` 的 Java,绝不会当成 Spring。
368
+
367
369
  具体的识别规则、每个 scanner 抽取了什么内容,详见 [docs/zh-CN/stacks.md](docs/zh-CN/stacks.md)。
368
370
 
369
371
  ---