claudeos-core 1.0.3 → 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 +75 -75
- package/plan-installer/index.js +134 -11
package/package.json
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "claudeos-core",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Auto-generate Claude Code documentation from your actual source code — Standards, Rules, Skills, and Guides tailored to your project",
|
|
5
|
-
"main": "health-checker/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"claudeos-core": "bin/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"bin/",
|
|
11
|
-
"content-validator/",
|
|
12
|
-
"health-checker/",
|
|
13
|
-
"import-linter/",
|
|
14
|
-
"manifest-generator/",
|
|
15
|
-
"pass-json-validator/",
|
|
16
|
-
"pass-prompts/",
|
|
17
|
-
"plan-installer/",
|
|
18
|
-
"plan-validator/",
|
|
19
|
-
"sync-checker/",
|
|
20
|
-
"bootstrap.sh",
|
|
21
|
-
"README.md",
|
|
22
|
-
"README.ko.md",
|
|
23
|
-
"LICENSE",
|
|
24
|
-
"CHANGELOG.md",
|
|
25
|
-
"CONTRIBUTING.md",
|
|
26
|
-
"README.zh-CN.md",
|
|
27
|
-
"README.ja.md",
|
|
28
|
-
"README.es.md",
|
|
29
|
-
"README.vi.md",
|
|
30
|
-
"README.hi.md",
|
|
31
|
-
"README.ru.md",
|
|
32
|
-
"README.fr.md",
|
|
33
|
-
"README.de.md"
|
|
34
|
-
],
|
|
35
|
-
"scripts": {
|
|
36
|
-
"init": "node bin/cli.js init",
|
|
37
|
-
"health": "node bin/cli.js health",
|
|
38
|
-
"validate": "node bin/cli.js validate",
|
|
39
|
-
"refresh": "node bin/cli.js refresh",
|
|
40
|
-
"restore": "node bin/cli.js restore",
|
|
41
|
-
"test": "node health-checker/index.js"
|
|
42
|
-
},
|
|
43
|
-
"keywords": [
|
|
44
|
-
"claude-code",
|
|
45
|
-
"automation",
|
|
46
|
-
"code-analysis",
|
|
47
|
-
"CLAUDE.md",
|
|
48
|
-
"standards",
|
|
49
|
-
"rules",
|
|
50
|
-
"skills",
|
|
51
|
-
"scaffolding",
|
|
52
|
-
"spring-boot",
|
|
53
|
-
"nextjs",
|
|
54
|
-
"express",
|
|
55
|
-
"django",
|
|
56
|
-
"fastapi"
|
|
57
|
-
],
|
|
58
|
-
"author": "claudeos-core <claudeoscore@gmail.com> (https://github.com/claudeos-core)",
|
|
59
|
-
"license": "ISC",
|
|
60
|
-
"repository": {
|
|
61
|
-
"type": "git",
|
|
62
|
-
"url": "git+https://github.com/claudeos-core/claudeos-core.git"
|
|
63
|
-
},
|
|
64
|
-
"homepage": "https://github.com/claudeos-core/claudeos-core#readme",
|
|
65
|
-
"bugs": {
|
|
66
|
-
"url": "https://github.com/claudeos-core/claudeos-core/issues"
|
|
67
|
-
},
|
|
68
|
-
"engines": {
|
|
69
|
-
"node": ">=18.0.0"
|
|
70
|
-
},
|
|
71
|
-
"dependencies": {
|
|
72
|
-
"glob": "^13.0.6",
|
|
73
|
-
"gray-matter": "^4.0.3"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "claudeos-core",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Auto-generate Claude Code documentation from your actual source code — Standards, Rules, Skills, and Guides tailored to your project",
|
|
5
|
+
"main": "health-checker/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claudeos-core": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"content-validator/",
|
|
12
|
+
"health-checker/",
|
|
13
|
+
"import-linter/",
|
|
14
|
+
"manifest-generator/",
|
|
15
|
+
"pass-json-validator/",
|
|
16
|
+
"pass-prompts/",
|
|
17
|
+
"plan-installer/",
|
|
18
|
+
"plan-validator/",
|
|
19
|
+
"sync-checker/",
|
|
20
|
+
"bootstrap.sh",
|
|
21
|
+
"README.md",
|
|
22
|
+
"README.ko.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"CHANGELOG.md",
|
|
25
|
+
"CONTRIBUTING.md",
|
|
26
|
+
"README.zh-CN.md",
|
|
27
|
+
"README.ja.md",
|
|
28
|
+
"README.es.md",
|
|
29
|
+
"README.vi.md",
|
|
30
|
+
"README.hi.md",
|
|
31
|
+
"README.ru.md",
|
|
32
|
+
"README.fr.md",
|
|
33
|
+
"README.de.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"init": "node bin/cli.js init",
|
|
37
|
+
"health": "node bin/cli.js health",
|
|
38
|
+
"validate": "node bin/cli.js validate",
|
|
39
|
+
"refresh": "node bin/cli.js refresh",
|
|
40
|
+
"restore": "node bin/cli.js restore",
|
|
41
|
+
"test": "node health-checker/index.js"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"claude-code",
|
|
45
|
+
"automation",
|
|
46
|
+
"code-analysis",
|
|
47
|
+
"CLAUDE.md",
|
|
48
|
+
"standards",
|
|
49
|
+
"rules",
|
|
50
|
+
"skills",
|
|
51
|
+
"scaffolding",
|
|
52
|
+
"spring-boot",
|
|
53
|
+
"nextjs",
|
|
54
|
+
"express",
|
|
55
|
+
"django",
|
|
56
|
+
"fastapi"
|
|
57
|
+
],
|
|
58
|
+
"author": "claudeos-core <claudeoscore@gmail.com> (https://github.com/claudeos-core)",
|
|
59
|
+
"license": "ISC",
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "git+https://github.com/claudeos-core/claudeos-core.git"
|
|
63
|
+
},
|
|
64
|
+
"homepage": "https://github.com/claudeos-core/claudeos-core#readme",
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/claudeos-core/claudeos-core/issues"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18.0.0"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"glob": "^13.0.6",
|
|
73
|
+
"gray-matter": "^4.0.3"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/plan-installer/index.js
CHANGED
|
@@ -295,6 +295,24 @@ async function scanStructure(stack) {
|
|
|
295
295
|
if (Object.keys(domainMap).length > 0) detectedPattern = "C";
|
|
296
296
|
}
|
|
297
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
|
+
|
|
298
316
|
// 각 도메인의 service/mapper/dto/xml 파일 스캔
|
|
299
317
|
for (const d of Object.keys(domainMap)) {
|
|
300
318
|
const p = domainMap[d].pattern;
|
|
@@ -332,6 +350,50 @@ async function scanStructure(stack) {
|
|
|
332
350
|
domainMap[d].xmlMappers = xml.length;
|
|
333
351
|
backendDomains.push({ name: d, type: "backend", ...domainMap[d], totalFiles: svc.length + mpr.length + dto.length + xml.length + domainMap[d].controllers });
|
|
334
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
|
+
}
|
|
335
397
|
}
|
|
336
398
|
|
|
337
399
|
// ── Node.js 백엔드 (Express/NestJS) — 프론트엔드 존재 여부와 무관하게 스캔 ──
|
|
@@ -377,17 +439,6 @@ async function scanStructure(stack) {
|
|
|
377
439
|
}
|
|
378
440
|
}
|
|
379
441
|
|
|
380
|
-
// App Router RSC/Client 전체 통계 (project-analysis.json용)
|
|
381
|
-
if (stack.frontend === "nextjs") {
|
|
382
|
-
const allClientFiles = await glob("{app,src/app}/**/client.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
383
|
-
const allPageFiles = await glob("{app,src/app}/**/page.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
384
|
-
const allLayoutFiles = await glob("{app,src/app}/**/layout.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
385
|
-
frontend.clientComponents = allClientFiles.length;
|
|
386
|
-
frontend.serverPages = allPageFiles.length;
|
|
387
|
-
frontend.layouts = allLayoutFiles.length;
|
|
388
|
-
frontend.rscPattern = allClientFiles.length > 0;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
442
|
// FSD (Feature-Sliced Design): features/*, widgets/*, entities/*
|
|
392
443
|
const fsdLayers = ["features", "widgets", "entities"];
|
|
393
444
|
for (const layer of fsdLayers) {
|
|
@@ -414,6 +465,67 @@ async function scanStructure(stack) {
|
|
|
414
465
|
frontendDomains.push({ name: `comp-${name}`, type: "frontend", components: files.length, totalFiles: files.length });
|
|
415
466
|
}
|
|
416
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
|
+
}
|
|
417
529
|
}
|
|
418
530
|
|
|
419
531
|
// ── Python/Django ──
|
|
@@ -463,6 +575,17 @@ async function scanStructure(stack) {
|
|
|
463
575
|
frontend.hooks = (await glob("{src/,}**/hooks/**/*.{ts,js}", { cwd: ROOT, ignore: ["**/node_modules/**"] })).length;
|
|
464
576
|
}
|
|
465
577
|
|
|
578
|
+
// App Router RSC/Client 전체 통계 (project-analysis.json용)
|
|
579
|
+
if (stack.frontend === "nextjs") {
|
|
580
|
+
const allClientFiles = await glob("{app,src/app}/**/client.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
581
|
+
const allPageFiles = await glob("{app,src/app}/**/page.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
582
|
+
const allLayoutFiles = await glob("{app,src/app}/**/layout.{tsx,ts,jsx,js}", { cwd: ROOT });
|
|
583
|
+
frontend.clientComponents = allClientFiles.length;
|
|
584
|
+
frontend.serverPages = allPageFiles.length;
|
|
585
|
+
frontend.layouts = allLayoutFiles.length;
|
|
586
|
+
frontend.rscPattern = allClientFiles.length > 0;
|
|
587
|
+
}
|
|
588
|
+
|
|
466
589
|
// 전체 도메인 = 백엔드 + 프론트엔드 (type 태그 포함)
|
|
467
590
|
const allDomains = [
|
|
468
591
|
...backendDomains.sort((a, b) => b.totalFiles - a.totalFiles),
|