claudeos-core 1.0.4 → 1.0.5
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 +1 -1
- package/plan-installer/index.js +105 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudeos-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
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": {
|
package/plan-installer/index.js
CHANGED
|
@@ -350,6 +350,50 @@ async function scanStructure(stack) {
|
|
|
350
350
|
domainMap[d].xmlMappers = xml.length;
|
|
351
351
|
backendDomains.push({ name: d, type: "backend", ...domainMap[d], totalFiles: svc.length + mpr.length + dto.length + xml.length + domainMap[d].controllers });
|
|
352
352
|
}
|
|
353
|
+
|
|
354
|
+
// ── Java 폴백: 위 글로브가 0개일 때 전체 .java 파일에서 직접 도메인 추출 ──
|
|
355
|
+
if (backendDomains.length === 0) {
|
|
356
|
+
const allJava = await glob("**/*.java", { cwd: ROOT, ignore: ["**/node_modules/**", "**/build/**", "**/target/**", "**/test/**", "**/generated/**"] });
|
|
357
|
+
const javaDomains = {};
|
|
358
|
+
const skipNames = ["common", "config", "util", "utils", "base", "shared", "global", "framework", "infra", "api", "main"];
|
|
359
|
+
const layerNames = ["controller", "service", "mapper", "repository", "dao", "dto", "vo", "entity", "aggregator", "adapter"];
|
|
360
|
+
|
|
361
|
+
for (const f of allJava) {
|
|
362
|
+
const parts = f.replace(/\\/g, "/").split("/");
|
|
363
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
364
|
+
if (layerNames.includes(parts[i]) && i > 0) {
|
|
365
|
+
// Pattern A 감지: .../{domain}/controller/... 또는 .../controller/{domain}/...
|
|
366
|
+
const prevDir = parts[i - 1];
|
|
367
|
+
const nextDir = parts[i + 1];
|
|
368
|
+
|
|
369
|
+
// {domain}/layer/ 패턴 (도메인이 레이어 앞에)
|
|
370
|
+
if (!skipNames.includes(prevDir) && !layerNames.includes(prevDir) && !prevDir.includes(".")) {
|
|
371
|
+
if (!javaDomains[prevDir]) javaDomains[prevDir] = { controllers: 0, services: 0, mappers: 0, dtos: 0, xmlMappers: 0, pattern: "B" };
|
|
372
|
+
if (parts[i] === "controller") javaDomains[prevDir].controllers++;
|
|
373
|
+
else if (parts[i] === "service") javaDomains[prevDir].services++;
|
|
374
|
+
else if (["mapper", "repository", "dao"].includes(parts[i])) javaDomains[prevDir].mappers++;
|
|
375
|
+
else if (["dto", "vo"].includes(parts[i])) javaDomains[prevDir].dtos++;
|
|
376
|
+
}
|
|
377
|
+
// layer/{domain}/ 패턴 (레이어가 도메인 앞에)
|
|
378
|
+
if (nextDir && !nextDir.endsWith(".java") && !skipNames.includes(nextDir) && !layerNames.includes(nextDir)) {
|
|
379
|
+
if (!javaDomains[nextDir]) javaDomains[nextDir] = { controllers: 0, services: 0, mappers: 0, dtos: 0, xmlMappers: 0, pattern: "A" };
|
|
380
|
+
if (parts[i] === "controller") javaDomains[nextDir].controllers++;
|
|
381
|
+
else if (parts[i] === "service") javaDomains[nextDir].services++;
|
|
382
|
+
else if (["mapper", "repository", "dao"].includes(parts[i])) javaDomains[nextDir].mappers++;
|
|
383
|
+
else if (["dto", "vo"].includes(parts[i])) javaDomains[nextDir].dtos++;
|
|
384
|
+
}
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
for (const [d, data] of Object.entries(javaDomains)) {
|
|
391
|
+
const total = data.controllers + data.services + data.mappers + data.dtos;
|
|
392
|
+
if (total > 0) {
|
|
393
|
+
backendDomains.push({ name: d, type: "backend", ...data, totalFiles: total });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
353
397
|
}
|
|
354
398
|
|
|
355
399
|
// ── Node.js 백엔드 (Express/NestJS) — 프론트엔드 존재 여부와 무관하게 스캔 ──
|
|
@@ -421,6 +465,67 @@ async function scanStructure(stack) {
|
|
|
421
465
|
frontendDomains.push({ name: `comp-${name}`, type: "frontend", components: files.length, totalFiles: files.length });
|
|
422
466
|
}
|
|
423
467
|
}
|
|
468
|
+
|
|
469
|
+
// ── 폴백: 위 스캐너로 0개일 때 page.tsx/index.tsx 위치에서 직접 도메인 추출 ──
|
|
470
|
+
if (frontendDomains.length === 0) {
|
|
471
|
+
const pageFiles = await glob("**/page.{tsx,jsx}", { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**"] });
|
|
472
|
+
const domainSet = {};
|
|
473
|
+
const skipNames = ["app", "src", "pages", "api", "_app", "_document"];
|
|
474
|
+
for (const f of pageFiles) {
|
|
475
|
+
const parts = f.replace(/\\/g, "/").split("/");
|
|
476
|
+
const appIdx = parts.indexOf("app");
|
|
477
|
+
const pagesIdx = parts.indexOf("pages");
|
|
478
|
+
const baseIdx = appIdx >= 0 ? appIdx : pagesIdx;
|
|
479
|
+
if (baseIdx >= 0 && baseIdx + 1 < parts.length - 1) {
|
|
480
|
+
const domain = parts[baseIdx + 1];
|
|
481
|
+
if (!skipNames.includes(domain) && !domain.startsWith("_") && !domain.startsWith("(") && !domain.startsWith(".")) {
|
|
482
|
+
if (!domainSet[domain]) domainSet[domain] = { pages: 0, clientFiles: 0, totalFiles: 0 };
|
|
483
|
+
domainSet[domain].pages++;
|
|
484
|
+
domainSet[domain].totalFiles++;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// client.tsx도 카운트
|
|
489
|
+
const clientFiles = await glob("**/client.{tsx,jsx}", { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**"] });
|
|
490
|
+
for (const f of clientFiles) {
|
|
491
|
+
const parts = f.replace(/\\/g, "/").split("/");
|
|
492
|
+
const appIdx = parts.indexOf("app");
|
|
493
|
+
const baseIdx = appIdx >= 0 ? appIdx : -1;
|
|
494
|
+
if (baseIdx >= 0 && baseIdx + 1 < parts.length - 1) {
|
|
495
|
+
const domain = parts[baseIdx + 1];
|
|
496
|
+
if (domainSet[domain]) {
|
|
497
|
+
domainSet[domain].clientFiles++;
|
|
498
|
+
domainSet[domain].totalFiles++;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
for (const [name, data] of Object.entries(domainSet)) {
|
|
503
|
+
frontendDomains.push({
|
|
504
|
+
name, type: "frontend", pages: data.pages, clientFiles: data.clientFiles, totalFiles: data.totalFiles,
|
|
505
|
+
rscPattern: data.clientFiles > 0 ? "RSC+Client split" : "default",
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// widgets/features/entities도 직접 스캔 (글로브 폴백)
|
|
510
|
+
for (const layer of ["widgets", "features", "entities"]) {
|
|
511
|
+
const layerFiles = await glob(`**/${layer}/*/**/*.{tsx,jsx,ts,js}`, { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**", "**/*.spec.*", "**/*.test.*"] });
|
|
512
|
+
const layerDomains = {};
|
|
513
|
+
for (const f of layerFiles) {
|
|
514
|
+
const parts = f.replace(/\\/g, "/").split("/");
|
|
515
|
+
const layerIdx = parts.indexOf(layer);
|
|
516
|
+
if (layerIdx >= 0 && layerIdx + 1 < parts.length) {
|
|
517
|
+
const domain = parts[layerIdx + 1];
|
|
518
|
+
if (!["ui", "common", "shared", "lib", "config"].includes(domain)) {
|
|
519
|
+
if (!layerDomains[domain]) layerDomains[domain] = 0;
|
|
520
|
+
layerDomains[domain]++;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
for (const [name, count] of Object.entries(layerDomains)) {
|
|
525
|
+
frontendDomains.push({ name: `${layer}/${name}`, type: "frontend", totalFiles: count });
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
424
529
|
}
|
|
425
530
|
|
|
426
531
|
// ── Python/Django ──
|