claudeos-core 1.3.0 → 1.4.0
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.
Potentially problematic release.
This version of claudeos-core might be problematic. Click here for more details.
- package/CHANGELOG.md +35 -0
- package/README.de.md +75 -27
- package/README.es.md +75 -27
- package/README.fr.md +75 -27
- package/README.hi.md +76 -28
- package/README.ja.md +94 -28
- package/README.ko.md +94 -28
- package/README.md +93 -26
- package/README.ru.md +75 -27
- package/README.vi.md +75 -27
- package/README.zh-CN.md +76 -28
- package/bin/cli.js +38 -10
- package/bootstrap.sh +13 -2
- package/content-validator/index.js +18 -13
- package/manifest-generator/index.js +24 -1
- package/package.json +1 -1
- package/pass-prompts/templates/java-spring/pass1.md +1 -1
- package/pass-prompts/templates/java-spring/pass3.md +25 -5
- package/pass-prompts/templates/kotlin-spring/pass1.md +1 -1
- package/pass-prompts/templates/kotlin-spring/pass3.md +25 -5
- package/pass-prompts/templates/node-express/pass1.md +1 -1
- package/pass-prompts/templates/node-express/pass3.md +24 -5
- package/pass-prompts/templates/node-nextjs/pass1.md +1 -1
- package/pass-prompts/templates/node-nextjs/pass3.md +25 -5
- package/pass-prompts/templates/python-django/pass1.md +1 -1
- package/pass-prompts/templates/python-django/pass3.md +24 -5
- package/pass-prompts/templates/python-fastapi/pass1.md +1 -1
- package/pass-prompts/templates/python-fastapi/pass3.md +24 -5
- package/plan-installer/domain-grouper.js +3 -10
- package/plan-installer/prompt-generator.js +0 -5
- package/plan-installer/stack-detector.js +2 -2
- package/plan-installer/structure-scanner.js +58 -7
- package/plan-validator/index.js +4 -2
- package/sync-checker/index.js +4 -2
|
@@ -17,6 +17,13 @@ If a standard defines a specific pattern (e.g., import path, file naming, API us
|
|
|
17
17
|
the corresponding rule MUST use the same pattern. Before generating each rule file,
|
|
18
18
|
verify it is consistent with the related standard file.
|
|
19
19
|
|
|
20
|
+
CRITICAL — Code Example Accuracy:
|
|
21
|
+
ALL code examples in rules and standards MUST use EXACT method names, class names,
|
|
22
|
+
and signatures from pass2-merged.json analysis data.
|
|
23
|
+
Do NOT paraphrase, rename, or infer API names.
|
|
24
|
+
If a method signature is not captured in the analysis data,
|
|
25
|
+
write "See corresponding standard for exact API" instead of guessing.
|
|
26
|
+
|
|
20
27
|
CRITICAL — CLAUDE.md Reference Table Completeness:
|
|
21
28
|
The reference table in CLAUDE.md MUST list ALL generated standard files, not just core.
|
|
22
29
|
Include all frontend-ui, backend-api, security-db, infra, and verification standards.
|
|
@@ -55,19 +62,32 @@ Generation targets:
|
|
|
55
62
|
- Key rules summary table
|
|
56
63
|
|
|
57
64
|
3. .claude/rules/ (active domains only)
|
|
58
|
-
- Every rule file MUST include `paths: ["**/*"]` in YAML frontmatter — this ensures Claude Code always loads the rule regardless of which file is being edited
|
|
59
65
|
- Write the full rule content directly in each file (self-contained, no external references)
|
|
60
66
|
- Include 5-15 lines of key rules with concrete examples
|
|
61
67
|
- Do NOT use @import — it is not a Claude Code feature and does not work
|
|
62
|
-
-
|
|
68
|
+
- Each rule file MUST end with a `## Reference` section linking to the corresponding standard file(s):
|
|
69
|
+
```
|
|
70
|
+
## Reference
|
|
71
|
+
> For detailed patterns and examples, Read: claudeos-core/standard/20.frontend-ui/01.component-patterns.md
|
|
72
|
+
```
|
|
73
|
+
- `paths:` frontmatter per rule category:
|
|
74
|
+
- `00.core/*` rules: `paths: ["**/*"]` — always loaded (architecture, naming are universally needed)
|
|
75
|
+
- `10.backend/*` rules: `paths: ["**/*"]` — always loaded (backend rules needed for any source editing)
|
|
76
|
+
- `20.frontend/*` rules: `paths: ["**/*"]` — always loaded (frontend rules needed for any source editing)
|
|
77
|
+
- `30.security-db/*` rules: `paths: ["**/*"]` — always loaded (cross-cutting concerns)
|
|
78
|
+
- `40.infra/*` rules: `paths: ["**/*.json", "**/*.env*", "**/next.config.*", "**/Dockerfile*", "**/*.yml", "**/*.yaml"]` — loaded only for config/infra files
|
|
79
|
+
- `50.sync/*` rules: `paths: ["**/claudeos-core/**", "**/.claude/**"]` — loaded only when editing claudeos-core files
|
|
80
|
+
- MUST generate `.claude/rules/00.core/00.standard-reference.md` — a directory of all standard files. This is NOT a "read all" instruction. Claude should Read ONLY the standards relevant to the current task. Structure it as:
|
|
63
81
|
```
|
|
64
82
|
---
|
|
65
83
|
paths:
|
|
66
84
|
- "**/*"
|
|
67
85
|
---
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
##
|
|
86
|
+
# Standard Documents Directory
|
|
87
|
+
Below is the complete list of standard files. Read ONLY the ones relevant to your current task — do NOT read all files.
|
|
88
|
+
Each rule file in .claude/rules/ links to its corresponding standard in the ## Reference section. Follow those links first.
|
|
89
|
+
This directory is for discovering standards that have no corresponding rule file.
|
|
90
|
+
## Core
|
|
71
91
|
- claudeos-core/standard/00.core/01.project-overview.md
|
|
72
92
|
- claudeos-core/standard/00.core/02.architecture.md
|
|
73
93
|
- claudeos-core/standard/00.core/03.naming-conventions.md
|
|
@@ -89,7 +89,7 @@ Analysis items (per domain):
|
|
|
89
89
|
- Security issues (SQL Injection, missing authorization, CSRF)
|
|
90
90
|
- Performance issues (unnecessary queries, memory)
|
|
91
91
|
|
|
92
|
-
Do not create files. Analysis only.
|
|
92
|
+
Do not create or modify source files. Analysis only.
|
|
93
93
|
Save results to claudeos-core/generated/pass1-{{PASS_NUM}}.json in the following format:
|
|
94
94
|
|
|
95
95
|
{
|
|
@@ -16,6 +16,13 @@ If a standard defines a specific pattern (e.g., import path, file naming, API us
|
|
|
16
16
|
the corresponding rule MUST use the same pattern. Before generating each rule file,
|
|
17
17
|
verify it is consistent with the related standard file.
|
|
18
18
|
|
|
19
|
+
CRITICAL — Code Example Accuracy:
|
|
20
|
+
ALL code examples in rules and standards MUST use EXACT method names, class names,
|
|
21
|
+
and signatures from pass2-merged.json analysis data.
|
|
22
|
+
Do NOT paraphrase, rename, or infer API names.
|
|
23
|
+
If a method signature is not captured in the analysis data,
|
|
24
|
+
write "See corresponding standard for exact API" instead of guessing.
|
|
25
|
+
|
|
19
26
|
CRITICAL — CLAUDE.md Reference Table Completeness:
|
|
20
27
|
The reference table in CLAUDE.md MUST list ALL generated standard files, not just core.
|
|
21
28
|
Include all backend-api, security-db, infra, and verification standards.
|
|
@@ -56,19 +63,31 @@ Generation targets:
|
|
|
56
63
|
- Key rules summary table
|
|
57
64
|
|
|
58
65
|
3. .claude/rules/ (active domains only)
|
|
59
|
-
- Every rule file MUST include `paths: ["**/*"]` in YAML frontmatter — this ensures Claude Code always loads the rule regardless of which file is being edited
|
|
60
66
|
- Write the full rule content directly in each file (self-contained, no external references)
|
|
61
67
|
- Include 5-15 lines of key rules with concrete examples
|
|
62
68
|
- Do NOT use @import — it is not a Claude Code feature and does not work
|
|
63
|
-
-
|
|
69
|
+
- Each rule file MUST end with a `## Reference` section linking to the corresponding standard file(s):
|
|
70
|
+
```
|
|
71
|
+
## Reference
|
|
72
|
+
> For detailed patterns and examples, Read: claudeos-core/standard/10.backend-api/01.view-patterns.md
|
|
73
|
+
```
|
|
74
|
+
- `paths:` frontmatter per rule category:
|
|
75
|
+
- `00.core/*` rules: `paths: ["**/*"]` — always loaded (architecture, naming are universally needed)
|
|
76
|
+
- `10.backend/*` rules: `paths: ["**/*"]` — always loaded (backend rules needed for any source editing)
|
|
77
|
+
- `30.security-db/*` rules: `paths: ["**/*"]` — always loaded (cross-cutting concerns)
|
|
78
|
+
- `40.infra/*` rules: `paths: ["**/*"]` — always loaded (Django settings are .py files, so infra paths cannot be scoped separately)
|
|
79
|
+
- `50.sync/*` rules: `paths: ["**/claudeos-core/**", "**/.claude/**"]` — loaded only when editing claudeos-core files
|
|
80
|
+
- MUST generate `.claude/rules/00.core/00.standard-reference.md` — a directory of all standard files. This is NOT a "read all" instruction. Claude should Read ONLY the standards relevant to the current task. Structure it as:
|
|
64
81
|
```
|
|
65
82
|
---
|
|
66
83
|
paths:
|
|
67
84
|
- "**/*"
|
|
68
85
|
---
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
##
|
|
86
|
+
# Standard Documents Directory
|
|
87
|
+
Below is the complete list of standard files. Read ONLY the ones relevant to your current task — do NOT read all files.
|
|
88
|
+
Each rule file in .claude/rules/ links to its corresponding standard in the ## Reference section. Follow those links first.
|
|
89
|
+
This directory is for discovering standards that have no corresponding rule file.
|
|
90
|
+
## Core
|
|
72
91
|
- claudeos-core/standard/00.core/01.project-overview.md
|
|
73
92
|
- claudeos-core/standard/00.core/02.architecture.md
|
|
74
93
|
- claudeos-core/standard/00.core/03.naming-conventions.md
|
|
@@ -93,7 +93,7 @@ Analysis items (per domain):
|
|
|
93
93
|
- Security issues (injection, missing authorization)
|
|
94
94
|
- Performance issues (blocking I/O, N+1)
|
|
95
95
|
|
|
96
|
-
Do not create files. Analysis only.
|
|
96
|
+
Do not create or modify source files. Analysis only.
|
|
97
97
|
Save results to claudeos-core/generated/pass1-{{PASS_NUM}}.json in the following format:
|
|
98
98
|
|
|
99
99
|
{
|
|
@@ -16,6 +16,13 @@ If a standard defines a specific pattern (e.g., import path, file naming, API us
|
|
|
16
16
|
the corresponding rule MUST use the same pattern. Before generating each rule file,
|
|
17
17
|
verify it is consistent with the related standard file.
|
|
18
18
|
|
|
19
|
+
CRITICAL — Code Example Accuracy:
|
|
20
|
+
ALL code examples in rules and standards MUST use EXACT method names, class names,
|
|
21
|
+
and signatures from pass2-merged.json analysis data.
|
|
22
|
+
Do NOT paraphrase, rename, or infer API names.
|
|
23
|
+
If a method signature is not captured in the analysis data,
|
|
24
|
+
write "See corresponding standard for exact API" instead of guessing.
|
|
25
|
+
|
|
19
26
|
CRITICAL — CLAUDE.md Reference Table Completeness:
|
|
20
27
|
The reference table in CLAUDE.md MUST list ALL generated standard files, not just core.
|
|
21
28
|
Include all backend-api, security-db, infra, and verification standards.
|
|
@@ -56,19 +63,31 @@ Generation targets:
|
|
|
56
63
|
- Key rules summary table
|
|
57
64
|
|
|
58
65
|
3. .claude/rules/ (active domains only)
|
|
59
|
-
- Every rule file MUST include `paths: ["**/*"]` in YAML frontmatter — this ensures Claude Code always loads the rule regardless of which file is being edited
|
|
60
66
|
- Write the full rule content directly in each file (self-contained, no external references)
|
|
61
67
|
- Include 5-15 lines of key rules with concrete examples
|
|
62
68
|
- Do NOT use @import — it is not a Claude Code feature and does not work
|
|
63
|
-
-
|
|
69
|
+
- Each rule file MUST end with a `## Reference` section linking to the corresponding standard file(s):
|
|
70
|
+
```
|
|
71
|
+
## Reference
|
|
72
|
+
> For detailed patterns and examples, Read: claudeos-core/standard/10.backend-api/01.router-endpoint-patterns.md
|
|
73
|
+
```
|
|
74
|
+
- `paths:` frontmatter per rule category:
|
|
75
|
+
- `00.core/*` rules: `paths: ["**/*"]` — always loaded (architecture, naming are universally needed)
|
|
76
|
+
- `10.backend/*` rules: `paths: ["**/*"]` — always loaded (backend rules needed for any source editing)
|
|
77
|
+
- `30.security-db/*` rules: `paths: ["**/*"]` — always loaded (cross-cutting concerns)
|
|
78
|
+
- `40.infra/*` rules: `paths: ["**/*.toml", "**/*.env*", "**/config/**", "**/Dockerfile*", "**/*.yml", "**/*.yaml"]` — loaded only for config/infra files
|
|
79
|
+
- `50.sync/*` rules: `paths: ["**/claudeos-core/**", "**/.claude/**"]` — loaded only when editing claudeos-core files
|
|
80
|
+
- MUST generate `.claude/rules/00.core/00.standard-reference.md` — a directory of all standard files. This is NOT a "read all" instruction. Claude should Read ONLY the standards relevant to the current task. Structure it as:
|
|
64
81
|
```
|
|
65
82
|
---
|
|
66
83
|
paths:
|
|
67
84
|
- "**/*"
|
|
68
85
|
---
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
##
|
|
86
|
+
# Standard Documents Directory
|
|
87
|
+
Below is the complete list of standard files. Read ONLY the ones relevant to your current task — do NOT read all files.
|
|
88
|
+
Each rule file in .claude/rules/ links to its corresponding standard in the ## Reference section. Follow those links first.
|
|
89
|
+
This directory is for discovering standards that have no corresponding rule file.
|
|
90
|
+
## Core
|
|
72
91
|
- claudeos-core/standard/00.core/01.project-overview.md
|
|
73
92
|
- claudeos-core/standard/00.core/02.architecture.md
|
|
74
93
|
- claudeos-core/standard/00.core/03.naming-conventions.md
|
|
@@ -47,28 +47,21 @@ function determineActiveDomains(stack) {
|
|
|
47
47
|
function selectTemplates(stack) {
|
|
48
48
|
const templates = { backend: null, frontend: null };
|
|
49
49
|
|
|
50
|
-
// Backend template
|
|
50
|
+
// Backend template (requires a backend framework; language-only fallback skipped for pure frontend projects)
|
|
51
51
|
if (stack.language === "kotlin") templates.backend = "kotlin-spring";
|
|
52
52
|
else if (stack.language === "java") templates.backend = "java-spring";
|
|
53
53
|
else if (stack.framework === "express" || stack.framework === "nestjs") templates.backend = "node-express";
|
|
54
54
|
else if (stack.framework === "django") templates.backend = "python-django";
|
|
55
55
|
else if (stack.framework === "fastapi" || stack.framework === "flask") templates.backend = "python-fastapi";
|
|
56
|
-
else if (stack.language === "typescript" || stack.language === "javascript") templates.backend = "node-express";
|
|
57
|
-
else if (stack.language === "python") templates.backend = "python-fastapi";
|
|
56
|
+
else if ((stack.language === "typescript" || stack.language === "javascript") && stack.framework) templates.backend = "node-express";
|
|
57
|
+
else if (stack.language === "python" && stack.framework) templates.backend = "python-fastapi";
|
|
58
58
|
|
|
59
59
|
// Frontend template
|
|
60
60
|
if (stack.frontend === "nextjs" || stack.frontend === "react" || stack.frontend === "vue") {
|
|
61
61
|
templates.frontend = "node-nextjs";
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// Pure frontend project with no backend
|
|
65
|
-
if (!templates.backend && templates.frontend) {
|
|
66
|
-
templates.backend = null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
64
|
return templates;
|
|
70
65
|
}
|
|
71
66
|
|
|
72
|
-
// ─── Dynamic prompt generation (multi-stack) ──────────────────────
|
|
73
|
-
|
|
74
67
|
module.exports = { splitDomainGroups, determineActiveDomains, selectTemplates };
|
|
@@ -56,11 +56,6 @@ function generatePrompts(templates, lang, templatesDir, generatedDir) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
if (primaryTemplate) {
|
|
60
|
-
const body = readTemplate(primaryTemplate, "pass1");
|
|
61
|
-
if (body) writeFileSafe(path.join(generatedDir, "pass1-prompt.md"), header + body);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
59
|
if (primaryTemplate) {
|
|
65
60
|
const body = readTemplate(primaryTemplate, "pass2");
|
|
66
61
|
if (body) {
|
|
@@ -186,9 +186,9 @@ async function detectStack(ROOT) {
|
|
|
186
186
|
else if (deps.react) { stack.frontend = "react"; stack.detected.push("react"); stack.frontendVersion = deps.react.replace(/[^0-9.]/g, ""); }
|
|
187
187
|
else if (deps.vue) { stack.frontend = "vue"; stack.detected.push("vue"); stack.frontendVersion = deps.vue.replace(/[^0-9.]/g, ""); }
|
|
188
188
|
|
|
189
|
-
// Backend framework
|
|
189
|
+
// Backend framework (NestJS checked first — more specific than express, which NestJS includes as a dependency)
|
|
190
|
+
if (deps["@nestjs/core"] && !stack.framework) { stack.framework = "nestjs"; stack.detected.push("nestjs"); stack.frameworkVersion = deps["@nestjs/core"].replace(/[^0-9.]/g, ""); }
|
|
190
191
|
if (deps.express && !stack.framework) { stack.framework = "express"; stack.detected.push("express"); }
|
|
191
|
-
if (deps["@nestjs/core"]) { stack.framework = "nestjs"; stack.detected.push("nestjs"); stack.frameworkVersion = deps["@nestjs/core"].replace(/[^0-9.]/g, ""); }
|
|
192
192
|
|
|
193
193
|
// ORM
|
|
194
194
|
if ((deps["@prisma/client"] || deps.prisma) && !stack.orm) { stack.orm = "prisma"; stack.detected.push("prisma"); }
|
|
@@ -413,7 +413,7 @@ async function scanStructure(stack, ROOT) {
|
|
|
413
413
|
for (const dir of allDirs) {
|
|
414
414
|
const name = path.basename(dir);
|
|
415
415
|
if (skipPages.includes(name) || name.startsWith("(") || name.startsWith("[") || name.startsWith("_") || name.startsWith(".")) continue;
|
|
416
|
-
const files = await glob(`${dir}**/*.{tsx,jsx,ts,js}`, { cwd: ROOT });
|
|
416
|
+
const files = await glob(`${dir}**/*.{tsx,jsx,ts,js,vue}`, { cwd: ROOT });
|
|
417
417
|
if (files.length > 0) {
|
|
418
418
|
const pages = files.filter(f => /page\.|index\./.test(f)).length;
|
|
419
419
|
const layouts = files.filter(f => /layout\./.test(f)).length;
|
|
@@ -434,7 +434,7 @@ async function scanStructure(stack, ROOT) {
|
|
|
434
434
|
for (const dir of fsdDirs) {
|
|
435
435
|
const name = path.basename(dir);
|
|
436
436
|
if (["ui", "common", "shared", "lib", "config", "index"].includes(name)) continue;
|
|
437
|
-
const files = await glob(`${dir}**/*.{tsx,jsx,ts,js}`, { cwd: ROOT, ignore: ["**/*.spec.*", "**/*.test.*", "**/*.stories.*"] });
|
|
437
|
+
const files = await glob(`${dir}**/*.{tsx,jsx,ts,js,vue}`, { cwd: ROOT, ignore: ["**/*.spec.*", "**/*.test.*", "**/*.stories.*"] });
|
|
438
438
|
if (files.length > 0) {
|
|
439
439
|
const uiFiles = files.filter(f => /\bui\b/.test(f)).length;
|
|
440
440
|
const modelFiles = files.filter(f => /model|store|hook/.test(f)).length;
|
|
@@ -448,14 +448,15 @@ async function scanStructure(stack, ROOT) {
|
|
|
448
448
|
for (const dir of compDirs) {
|
|
449
449
|
const name = path.basename(dir);
|
|
450
450
|
if (["ui", "common", "shared", "layout", "icons"].includes(name)) continue;
|
|
451
|
-
const files = await glob(`${dir}**/*.{tsx,jsx}`, { cwd: ROOT });
|
|
451
|
+
const files = await glob(`${dir}**/*.{tsx,jsx,vue}`, { cwd: ROOT });
|
|
452
452
|
if (files.length >= 2) {
|
|
453
453
|
frontendDomains.push({ name: `comp-${name}`, type: "frontend", components: files.length, totalFiles: files.length });
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
// ── Fallback: extract domains
|
|
457
|
+
// ── Fallback: extract domains when primary scanners return 0 ──
|
|
458
458
|
if (frontendDomains.length === 0) {
|
|
459
|
+
// Fallback A: Next.js page.tsx / client.tsx based detection
|
|
459
460
|
const pageFiles = await glob("**/page.{tsx,jsx}", { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**"] });
|
|
460
461
|
const domainSet = {};
|
|
461
462
|
const skipNames = ["app", "src", "pages", "api", "_app", "_document"];
|
|
@@ -473,7 +474,6 @@ async function scanStructure(stack, ROOT) {
|
|
|
473
474
|
}
|
|
474
475
|
}
|
|
475
476
|
}
|
|
476
|
-
// Count client.tsx as well
|
|
477
477
|
const clientFiles = await glob("**/client.{tsx,jsx}", { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**"] });
|
|
478
478
|
for (const f of clientFiles) {
|
|
479
479
|
const parts = f.replace(/\\/g, "/").split("/");
|
|
@@ -494,9 +494,9 @@ async function scanStructure(stack, ROOT) {
|
|
|
494
494
|
});
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
//
|
|
497
|
+
// Fallback B: FSD widgets/features/entities
|
|
498
498
|
for (const layer of ["widgets", "features", "entities"]) {
|
|
499
|
-
const layerFiles = await glob(`**/${layer}/*/**/*.{tsx,jsx,ts,js}`, { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**", "**/*.spec.*", "**/*.test.*"] });
|
|
499
|
+
const layerFiles = await glob(`**/${layer}/*/**/*.{tsx,jsx,ts,js,vue}`, { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**", "**/*.spec.*", "**/*.test.*"] });
|
|
500
500
|
const layerDomains = {};
|
|
501
501
|
for (const f of layerFiles) {
|
|
502
502
|
const parts = f.replace(/\\/g, "/").split("/");
|
|
@@ -513,6 +513,57 @@ async function scanStructure(stack, ROOT) {
|
|
|
513
513
|
frontendDomains.push({ name: `${layer}/${name}`, type: "frontend", totalFiles: count });
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
+
|
|
517
|
+
// Fallback C: Deep components/**/components/*/ detection (React/CRA/Vite projects)
|
|
518
|
+
// Scans for components/ directories at any depth (e.g., src/desktop/app/components/order/)
|
|
519
|
+
if (frontendDomains.length === 0) {
|
|
520
|
+
const deepCompDirs = await glob("**/components/*/", { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**", "**/build/**", "**/dist/**", "**/.git/**", "**/vendor/**", "**/__pycache__/**", "**/coverage/**"] });
|
|
521
|
+
const deepDomains = {};
|
|
522
|
+
const skipDomainNames = ["ui", "common", "shared", "layout", "layouts", "icons", "assets", "config", "utils", "lib", "error", "footer", "header", "inputs", "template"];
|
|
523
|
+
for (const dir of deepCompDirs) {
|
|
524
|
+
const name = path.basename(dir.replace(/\/$/, ""));
|
|
525
|
+
if (skipDomainNames.includes(name) || name.startsWith("_") || name.startsWith(".")) continue;
|
|
526
|
+
const files = await glob(`${dir.replace(/\\/g, "/")}**/*.{tsx,jsx,ts,js,vue}`, { cwd: ROOT, ignore: ["**/*.spec.*", "**/*.test.*", "**/*.stories.*"] });
|
|
527
|
+
if (files.length >= 2) {
|
|
528
|
+
if (!deepDomains[name]) deepDomains[name] = { components: 0, totalFiles: 0 };
|
|
529
|
+
deepDomains[name].components += files.length;
|
|
530
|
+
deepDomains[name].totalFiles += files.length;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
for (const [name, data] of Object.entries(deepDomains)) {
|
|
534
|
+
frontendDomains.push({ name, type: "frontend", components: data.components, totalFiles: data.totalFiles });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Fallback D: views/screens/containers/pages/routes deep detection
|
|
539
|
+
// Covers: Vue (views/), React Native (screens/), legacy React (containers/),
|
|
540
|
+
// CRA/Vite (pages/ at any depth), React Router (routes/)
|
|
541
|
+
if (frontendDomains.length === 0) {
|
|
542
|
+
const domainDirPatterns = ["views", "screens", "containers", "pages", "routes", "modules", "domains"];
|
|
543
|
+
const deepDirDomains = {};
|
|
544
|
+
const skipDirNames = ["api", "auth", "_app", "_document", "index", "ui", "common", "shared",
|
|
545
|
+
"layout", "layouts", "lib", "config", "utils", "assets", "hooks", "store", "types",
|
|
546
|
+
"constants", "helpers", "services", "middleware", "interceptors", "guards", "decorators"];
|
|
547
|
+
|
|
548
|
+
for (const pattern of domainDirPatterns) {
|
|
549
|
+
const dirs = await glob(`**/${pattern}/*/`, { cwd: ROOT, ignore: ["**/node_modules/**", "**/.next/**", "**/build/**", "**/dist/**", "**/.git/**", "**/vendor/**", "**/__pycache__/**", "**/coverage/**"] });
|
|
550
|
+
for (const dir of dirs) {
|
|
551
|
+
const name = path.basename(dir.replace(/\/$/, ""));
|
|
552
|
+
if (skipDirNames.includes(name) || name.startsWith("_") || name.startsWith(".") || name.startsWith("(") || name.startsWith("[")) continue;
|
|
553
|
+
const files = await glob(`${dir.replace(/\\/g, "/")}**/*.{tsx,jsx,ts,js,vue}`, { cwd: ROOT, ignore: ["**/*.spec.*", "**/*.test.*", "**/*.stories.*"] });
|
|
554
|
+
if (files.length >= 2) {
|
|
555
|
+
if (!deepDirDomains[name]) deepDirDomains[name] = { components: 0, pages: 0, totalFiles: 0, sources: [] };
|
|
556
|
+
const tsx = files.filter(f => /\.(tsx|jsx|vue)$/.test(f)).length;
|
|
557
|
+
deepDirDomains[name].components += tsx;
|
|
558
|
+
deepDirDomains[name].totalFiles += files.length;
|
|
559
|
+
if (!deepDirDomains[name].sources.includes(pattern)) deepDirDomains[name].sources.push(pattern);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
for (const [name, data] of Object.entries(deepDirDomains)) {
|
|
564
|
+
frontendDomains.push({ name, type: "frontend", components: data.components, totalFiles: data.totalFiles, sources: data.sources });
|
|
565
|
+
}
|
|
566
|
+
}
|
|
516
567
|
}
|
|
517
568
|
}
|
|
518
569
|
|
package/plan-validator/index.js
CHANGED
|
@@ -173,8 +173,10 @@ async function main() {
|
|
|
173
173
|
total++;
|
|
174
174
|
const abs = path.join(ROOT, b.path);
|
|
175
175
|
|
|
176
|
-
// Block path traversal attempts
|
|
177
|
-
|
|
176
|
+
// Block path traversal attempts (allow files at ROOT level and below)
|
|
177
|
+
const resolvedAbs = path.resolve(abs);
|
|
178
|
+
const resolvedRoot = path.resolve(ROOT);
|
|
179
|
+
if (resolvedAbs !== resolvedRoot && !resolvedAbs.startsWith(resolvedRoot + path.sep)) {
|
|
178
180
|
console.log(` ⚠️ SKIPPED: ${b.path} (path traversal blocked)`);
|
|
179
181
|
continue;
|
|
180
182
|
}
|
package/sync-checker/index.js
CHANGED
|
@@ -81,8 +81,10 @@ async function main() {
|
|
|
81
81
|
console.log(" [2/2] Plan → Disk...");
|
|
82
82
|
for (const m of sm.mappings) {
|
|
83
83
|
const abs = path.join(ROOT, m.sourcePath);
|
|
84
|
-
// Skip path traversal attempts
|
|
85
|
-
|
|
84
|
+
// Skip path traversal attempts (allow files at ROOT level and below)
|
|
85
|
+
const resolvedAbs = path.resolve(abs);
|
|
86
|
+
const resolvedRoot = path.resolve(ROOT);
|
|
87
|
+
if (resolvedAbs !== resolvedRoot && !resolvedAbs.startsWith(resolvedRoot + path.sep)) continue;
|
|
86
88
|
if (!fs.existsSync(abs)) {
|
|
87
89
|
issues.orphan.push({ path: m.sourcePath, plan: m.planFile });
|
|
88
90
|
}
|