claudeos-core 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeos-core",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Auto-generate Claude Code documentation from your actual source code — Standards, Rules, Skills, and Guides tailored to your project",
5
5
  "main": "health-checker/index.js",
6
6
  "bin": {
@@ -181,6 +181,27 @@ async function detectStack() {
181
181
  }
182
182
  }
183
183
 
184
+ // ── Config file fallback (모노레포: package.json에 없어도 설정 파일로 감지) ──
185
+ if (!stack.frontend) {
186
+ const nextConfigs = ["next.config.js", "next.config.mjs", "next.config.ts"];
187
+ if (nextConfigs.some(c => fs.existsSync(path.join(ROOT, c)))) {
188
+ stack.frontend = "nextjs"; stack.detected.push("next.config (fallback)");
189
+ if (!stack.language) stack.language = "typescript";
190
+ }
191
+ }
192
+ if (!stack.frontend) {
193
+ if (fs.existsSync(path.join(ROOT, "vite.config.ts")) || fs.existsSync(path.join(ROOT, "vite.config.js"))) {
194
+ if (!stack.frontend) { stack.frontend = "react"; stack.detected.push("vite.config (fallback)"); }
195
+ if (!stack.language) stack.language = "typescript";
196
+ }
197
+ }
198
+ if (!stack.frontend) {
199
+ if (fs.existsSync(path.join(ROOT, "nuxt.config.ts")) || fs.existsSync(path.join(ROOT, "nuxt.config.js"))) {
200
+ stack.frontend = "vue"; stack.detected.push("nuxt.config (fallback)");
201
+ if (!stack.language) stack.language = "typescript";
202
+ }
203
+ }
204
+
184
205
  return stack;
185
206
  }
186
207
 
@@ -274,6 +295,24 @@ async function scanStructure(stack) {
274
295
  if (Object.keys(domainMap).length > 0) detectedPattern = "C";
275
296
  }
276
297
 
298
+ // ── 보충 스캔: controller 없는 서비스 도메인 감지 ──
299
+ // core/delivery 처럼 service/mapper만 있고 controller가 없는 도메인 포착
300
+ if (detectedPattern === "B" || detectedPattern === "D" || !detectedPattern) {
301
+ const serviceDirs = await glob("src/main/java/**/*/service/*.java", { cwd: ROOT });
302
+ const mapperDirs = await glob("src/main/java/**/*/{mapper,repository}/*.java", { cwd: ROOT });
303
+ const allServiceFiles = [...serviceDirs, ...mapperDirs];
304
+ const skipDomains = ["common", "config", "util", "utils", "base", "core", "shared", "global", "framework", "infra"];
305
+ for (const f of allServiceFiles) {
306
+ const m = f.match(/\/([^/]+)\/(service|mapper|repository)\/[^/]+\.java$/);
307
+ if (m) {
308
+ const d = m[1];
309
+ if (!domainMap[d] && !skipDomains.includes(d)) {
310
+ domainMap[d] = { controllers: 0, services: 0, mappers: 0, dtos: 0, xmlMappers: 0, pattern: detectedPattern || "B" };
311
+ }
312
+ }
313
+ }
314
+ }
315
+
277
316
  // 각 도메인의 service/mapper/dto/xml 파일 스캔
278
317
  for (const d of Object.keys(domainMap)) {
279
318
  const p = domainMap[d].pattern;
@@ -333,6 +372,7 @@ async function scanStructure(stack) {
333
372
 
334
373
  // ── Next.js/React/Vue ──
335
374
  if (stack.frontend === "nextjs" || stack.frontend === "react" || stack.frontend === "vue") {
375
+ // App Router / Pages Router 도메인
336
376
  const allDirs = [
337
377
  ...await glob("{app,src/app}/*/", { cwd: ROOT }),
338
378
  ...await glob("{pages,src/pages}/*/", { cwd: ROOT }),
@@ -344,10 +384,34 @@ async function scanStructure(stack) {
344
384
  const files = await glob(`${dir}**/*.{tsx,jsx,ts,js}`, { cwd: ROOT });
345
385
  if (files.length > 0) {
346
386
  const pages = files.filter(f => /page\.|index\./.test(f)).length;
347
- const components = files.filter(f => !/page\.|layout\.|index\./.test(f)).length;
348
- frontendDomains.push({ name, type: "frontend", pages, components, totalFiles: files.length });
387
+ const layouts = files.filter(f => /layout\./.test(f)).length;
388
+ const clientFiles = files.filter(f => /client\./.test(f)).length;
389
+ const serverFiles = pages + layouts;
390
+ const components = files.filter(f => !/page\.|layout\.|index\.|client\./.test(f)).length;
391
+ frontendDomains.push({
392
+ name, type: "frontend", pages, layouts, clientFiles, serverFiles, components, totalFiles: files.length,
393
+ rscPattern: clientFiles > 0 ? "RSC+Client split" : "default",
394
+ });
349
395
  }
350
396
  }
397
+
398
+ // FSD (Feature-Sliced Design): features/*, widgets/*, entities/*
399
+ const fsdLayers = ["features", "widgets", "entities"];
400
+ for (const layer of fsdLayers) {
401
+ const fsdDirs = await glob(`{${layer},src/${layer}}/*/`, { cwd: ROOT });
402
+ for (const dir of fsdDirs) {
403
+ const name = path.basename(dir);
404
+ if (["ui", "common", "shared", "lib", "config", "index"].includes(name)) continue;
405
+ const files = await glob(`${dir}**/*.{tsx,jsx,ts,js}`, { cwd: ROOT, ignore: ["**/*.spec.*", "**/*.test.*", "**/*.stories.*"] });
406
+ if (files.length > 0) {
407
+ const uiFiles = files.filter(f => /\bui\b/.test(f)).length;
408
+ const modelFiles = files.filter(f => /model|store|hook/.test(f)).length;
409
+ frontendDomains.push({ name: `${layer}/${name}`, type: "frontend", components: uiFiles, models: modelFiles, totalFiles: files.length });
410
+ }
411
+ }
412
+ }
413
+
414
+ // components/* (기존)
351
415
  const compDirs = await glob("{src/,}components/*/", { cwd: ROOT });
352
416
  for (const dir of compDirs) {
353
417
  const name = path.basename(dir);
@@ -406,6 +470,17 @@ async function scanStructure(stack) {
406
470
  frontend.hooks = (await glob("{src/,}**/hooks/**/*.{ts,js}", { cwd: ROOT, ignore: ["**/node_modules/**"] })).length;
407
471
  }
408
472
 
473
+ // App Router RSC/Client 전체 통계 (project-analysis.json용)
474
+ if (stack.frontend === "nextjs") {
475
+ const allClientFiles = await glob("{app,src/app}/**/client.{tsx,ts,jsx,js}", { cwd: ROOT });
476
+ const allPageFiles = await glob("{app,src/app}/**/page.{tsx,ts,jsx,js}", { cwd: ROOT });
477
+ const allLayoutFiles = await glob("{app,src/app}/**/layout.{tsx,ts,jsx,js}", { cwd: ROOT });
478
+ frontend.clientComponents = allClientFiles.length;
479
+ frontend.serverPages = allPageFiles.length;
480
+ frontend.layouts = allLayoutFiles.length;
481
+ frontend.rscPattern = allClientFiles.length > 0;
482
+ }
483
+
409
484
  // 전체 도메인 = 백엔드 + 프론트엔드 (type 태그 포함)
410
485
  const allDomains = [
411
486
  ...backendDomains.sort((a, b) => b.totalFiles - a.totalFiles),