claudeos-core 2.1.1 → 2.3.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.
- package/CHANGELOG.md +1649 -481
- package/CONTRIBUTING.md +92 -92
- package/README.de.md +64 -5
- package/README.es.md +64 -5
- package/README.fr.md +64 -5
- package/README.hi.md +64 -5
- package/README.ja.md +64 -5
- package/README.ko.md +1018 -959
- package/README.md +1020 -960
- package/README.ru.md +66 -5
- package/README.vi.md +1019 -960
- package/README.zh-CN.md +64 -5
- package/bin/cli.js +152 -148
- package/bin/commands/init.js +1673 -1518
- package/bin/commands/lint.js +62 -0
- package/bin/commands/memory.js +438 -438
- package/bin/lib/cli-utils.js +206 -206
- package/claude-md-validator/index.js +184 -0
- package/claude-md-validator/reporter.js +66 -0
- package/claude-md-validator/structural-checks.js +528 -0
- package/content-validator/index.js +666 -436
- package/lib/env-parser.js +317 -0
- package/lib/expected-guides.js +23 -23
- package/lib/expected-outputs.js +90 -90
- package/lib/language-config.js +35 -35
- package/lib/memory-scaffold.js +1058 -1052
- package/lib/plan-parser.js +165 -165
- package/lib/staged-rules.js +118 -118
- package/manifest-generator/index.js +174 -174
- package/package.json +90 -87
- package/pass-json-validator/index.js +337 -337
- package/pass-prompts/templates/angular/pass3.md +28 -13
- package/pass-prompts/templates/common/claude-md-scaffold.md +686 -0
- package/pass-prompts/templates/common/pass3-footer.md +402 -39
- package/pass-prompts/templates/common/pass3b-core-header.md +43 -0
- package/pass-prompts/templates/common/pass4.md +375 -302
- package/pass-prompts/templates/common/staging-override.md +26 -26
- package/pass-prompts/templates/java-spring/pass3.md +31 -21
- package/pass-prompts/templates/kotlin-spring/pass3.md +34 -22
- package/pass-prompts/templates/node-express/pass3.md +30 -21
- package/pass-prompts/templates/node-fastify/pass3.md +28 -14
- package/pass-prompts/templates/node-nestjs/pass3.md +29 -14
- package/pass-prompts/templates/node-nextjs/pass3.md +34 -21
- package/pass-prompts/templates/node-vite/pass1.md +117 -117
- package/pass-prompts/templates/node-vite/pass2.md +78 -78
- package/pass-prompts/templates/node-vite/pass3.md +30 -13
- package/pass-prompts/templates/python-django/pass3.md +32 -21
- package/pass-prompts/templates/python-fastapi/pass3.md +33 -21
- package/pass-prompts/templates/python-flask/pass1.md +119 -119
- package/pass-prompts/templates/python-flask/pass2.md +85 -85
- package/pass-prompts/templates/python-flask/pass3.md +31 -13
- package/pass-prompts/templates/vue-nuxt/pass3.md +32 -13
- package/plan-installer/domain-grouper.js +76 -76
- package/plan-installer/index.js +137 -129
- package/plan-installer/prompt-generator.js +188 -128
- package/plan-installer/scanners/scan-frontend.js +505 -473
- package/plan-installer/scanners/scan-java.js +226 -226
- package/plan-installer/scanners/scan-node.js +57 -57
- package/plan-installer/scanners/scan-python.js +85 -85
- package/plan-installer/stack-detector.js +482 -466
- package/plan-installer/structure-scanner.js +65 -65
- package/sync-checker/index.js +177 -177
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ClaudeOS-Core — Domain Grouper
|
|
3
|
-
*
|
|
4
|
-
* Splits domains into analysis groups, determines active domains,
|
|
5
|
-
* and selects appropriate templates based on detected stack.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
function splitDomainGroups(domains, type, template) {
|
|
9
|
-
const MAX_FILES_PER_GROUP = 40;
|
|
10
|
-
const MAX_DOMAINS_PER_GROUP = 4;
|
|
11
|
-
const groups = [];
|
|
12
|
-
let current = [];
|
|
13
|
-
let fileCount = 0;
|
|
14
|
-
|
|
15
|
-
for (const d of domains) {
|
|
16
|
-
// Flush current group before adding if it would exceed limits
|
|
17
|
-
if (current.length > 0 && (fileCount + d.totalFiles > MAX_FILES_PER_GROUP || current.length >= MAX_DOMAINS_PER_GROUP)) {
|
|
18
|
-
groups.push({ type, template, domains: [...current], estimatedFiles: fileCount });
|
|
19
|
-
current = [];
|
|
20
|
-
fileCount = 0;
|
|
21
|
-
}
|
|
22
|
-
current.push(d.name);
|
|
23
|
-
fileCount += d.totalFiles;
|
|
24
|
-
}
|
|
25
|
-
if (current.length > 0) {
|
|
26
|
-
groups.push({ type, template, domains: [...current], estimatedFiles: fileCount });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return groups;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// ─── Determine active domains ───────────────────────────────────
|
|
33
|
-
function determineActiveDomains(stack) {
|
|
34
|
-
const isBackend = !!stack.framework && stack.framework !== "vite";
|
|
35
|
-
return {
|
|
36
|
-
"00.core": true,
|
|
37
|
-
"10.backend": !!isBackend,
|
|
38
|
-
"20.frontend": !!stack.frontend,
|
|
39
|
-
"30.security-db": !!(stack.database || isBackend || stack.frontend),
|
|
40
|
-
"40.infra": true,
|
|
41
|
-
"50.verification": true,
|
|
42
|
-
"90.optional": true,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ─── Template selection (multi-stack) ──────────────────────────────
|
|
47
|
-
function selectTemplates(stack) {
|
|
48
|
-
const templates = { backend: null, frontend: null };
|
|
49
|
-
|
|
50
|
-
// Backend template (requires a backend framework; language-only fallback skipped for pure frontend projects)
|
|
51
|
-
if (stack.language === "kotlin") templates.backend = "kotlin-spring";
|
|
52
|
-
else if (stack.language === "java") templates.backend = "java-spring";
|
|
53
|
-
else if (stack.framework === "nestjs") templates.backend = "node-nestjs";
|
|
54
|
-
else if (stack.framework === "express") templates.backend = "node-express";
|
|
55
|
-
else if (stack.framework === "fastify") templates.backend = "node-fastify";
|
|
56
|
-
else if (stack.framework === "django") templates.backend = "python-django";
|
|
57
|
-
else if (stack.framework === "fastapi") templates.backend = "python-fastapi";
|
|
58
|
-
else if (stack.framework === "flask") templates.backend = "python-flask";
|
|
59
|
-
else if ((stack.language === "typescript" || stack.language === "javascript") && stack.framework && stack.framework !== "vite") templates.backend = "node-express";
|
|
60
|
-
else if (stack.language === "python" && stack.framework) templates.backend = "python-fastapi";
|
|
61
|
-
|
|
62
|
-
// Frontend template
|
|
63
|
-
if (stack.frontend === "nextjs") {
|
|
64
|
-
templates.frontend = "node-nextjs";
|
|
65
|
-
} else if (stack.frontend === "react") {
|
|
66
|
-
templates.frontend = stack.framework === "vite" ? "node-vite" : "node-nextjs";
|
|
67
|
-
} else if (stack.frontend === "vue") {
|
|
68
|
-
templates.frontend = "vue-nuxt";
|
|
69
|
-
} else if (stack.frontend === "angular") {
|
|
70
|
-
templates.frontend = "angular";
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return templates;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = { splitDomainGroups, determineActiveDomains, selectTemplates };
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeOS-Core — Domain Grouper
|
|
3
|
+
*
|
|
4
|
+
* Splits domains into analysis groups, determines active domains,
|
|
5
|
+
* and selects appropriate templates based on detected stack.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
function splitDomainGroups(domains, type, template) {
|
|
9
|
+
const MAX_FILES_PER_GROUP = 40;
|
|
10
|
+
const MAX_DOMAINS_PER_GROUP = 4;
|
|
11
|
+
const groups = [];
|
|
12
|
+
let current = [];
|
|
13
|
+
let fileCount = 0;
|
|
14
|
+
|
|
15
|
+
for (const d of domains) {
|
|
16
|
+
// Flush current group before adding if it would exceed limits
|
|
17
|
+
if (current.length > 0 && (fileCount + d.totalFiles > MAX_FILES_PER_GROUP || current.length >= MAX_DOMAINS_PER_GROUP)) {
|
|
18
|
+
groups.push({ type, template, domains: [...current], estimatedFiles: fileCount });
|
|
19
|
+
current = [];
|
|
20
|
+
fileCount = 0;
|
|
21
|
+
}
|
|
22
|
+
current.push(d.name);
|
|
23
|
+
fileCount += d.totalFiles;
|
|
24
|
+
}
|
|
25
|
+
if (current.length > 0) {
|
|
26
|
+
groups.push({ type, template, domains: [...current], estimatedFiles: fileCount });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return groups;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Determine active domains ───────────────────────────────────
|
|
33
|
+
function determineActiveDomains(stack) {
|
|
34
|
+
const isBackend = !!stack.framework && stack.framework !== "vite";
|
|
35
|
+
return {
|
|
36
|
+
"00.core": true,
|
|
37
|
+
"10.backend": !!isBackend,
|
|
38
|
+
"20.frontend": !!stack.frontend,
|
|
39
|
+
"30.security-db": !!(stack.database || isBackend || stack.frontend),
|
|
40
|
+
"40.infra": true,
|
|
41
|
+
"50.verification": true,
|
|
42
|
+
"90.optional": true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── Template selection (multi-stack) ──────────────────────────────
|
|
47
|
+
function selectTemplates(stack) {
|
|
48
|
+
const templates = { backend: null, frontend: null };
|
|
49
|
+
|
|
50
|
+
// Backend template (requires a backend framework; language-only fallback skipped for pure frontend projects)
|
|
51
|
+
if (stack.language === "kotlin") templates.backend = "kotlin-spring";
|
|
52
|
+
else if (stack.language === "java") templates.backend = "java-spring";
|
|
53
|
+
else if (stack.framework === "nestjs") templates.backend = "node-nestjs";
|
|
54
|
+
else if (stack.framework === "express") templates.backend = "node-express";
|
|
55
|
+
else if (stack.framework === "fastify") templates.backend = "node-fastify";
|
|
56
|
+
else if (stack.framework === "django") templates.backend = "python-django";
|
|
57
|
+
else if (stack.framework === "fastapi") templates.backend = "python-fastapi";
|
|
58
|
+
else if (stack.framework === "flask") templates.backend = "python-flask";
|
|
59
|
+
else if ((stack.language === "typescript" || stack.language === "javascript") && stack.framework && stack.framework !== "vite") templates.backend = "node-express";
|
|
60
|
+
else if (stack.language === "python" && stack.framework) templates.backend = "python-fastapi";
|
|
61
|
+
|
|
62
|
+
// Frontend template
|
|
63
|
+
if (stack.frontend === "nextjs") {
|
|
64
|
+
templates.frontend = "node-nextjs";
|
|
65
|
+
} else if (stack.frontend === "react") {
|
|
66
|
+
templates.frontend = stack.framework === "vite" ? "node-vite" : "node-nextjs";
|
|
67
|
+
} else if (stack.frontend === "vue") {
|
|
68
|
+
templates.frontend = "vue-nuxt";
|
|
69
|
+
} else if (stack.frontend === "angular") {
|
|
70
|
+
templates.frontend = "angular";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return templates;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { splitDomainGroups, determineActiveDomains, selectTemplates };
|
package/plan-installer/index.js
CHANGED
|
@@ -1,129 +1,137 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ClaudeOS-Core — plan-installer (orchestrator)
|
|
5
|
-
*
|
|
6
|
-
* Modules:
|
|
7
|
-
* - stack-detector.js — detectStack()
|
|
8
|
-
* - structure-scanner.js — scanStructure(), resolveSharedQueryDomains()
|
|
9
|
-
* - domain-grouper.js — splitDomainGroups(), determineActiveDomains(), selectTemplates()
|
|
10
|
-
* - prompt-generator.js — generatePrompts()
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const path = require("path");
|
|
14
|
-
const { ensureDir, writeFileSafe } = require("../lib/safe-fs");
|
|
15
|
-
const { detectStack } = require("./stack-detector");
|
|
16
|
-
const { scanStructure } = require("./structure-scanner");
|
|
17
|
-
const { splitDomainGroups, determineActiveDomains, selectTemplates } = require("./domain-grouper");
|
|
18
|
-
const { generatePrompts } = require("./prompt-generator");
|
|
19
|
-
|
|
20
|
-
const ROOT = process.env.CLAUDEOS_ROOT || path.resolve(__dirname, "../..");
|
|
21
|
-
const GENERATED_DIR = path.join(ROOT, "claudeos-core/generated");
|
|
22
|
-
const TEMPLATES_DIR = path.join(__dirname, "../pass-prompts/templates");
|
|
23
|
-
|
|
24
|
-
async function main() {
|
|
25
|
-
console.log("\n╔═══════════════════════════════════════╗");
|
|
26
|
-
console.log("║ ClaudeOS-Core — Plan Installer ║");
|
|
27
|
-
console.log("╚═══════════════════════════════════════╝\n");
|
|
28
|
-
|
|
29
|
-
ensureDir(GENERATED_DIR);
|
|
30
|
-
|
|
31
|
-
// Phase 1: Stack detection
|
|
32
|
-
console.log(" [Phase 1] Detecting stack...");
|
|
33
|
-
const stack = await detectStack(ROOT);
|
|
34
|
-
console.log(` Language: ${stack.language || "unknown"} ${stack.languageVersion || ""}`);
|
|
35
|
-
console.log(` Framework: ${stack.framework || "none"} ${stack.frameworkVersion || ""}`);
|
|
36
|
-
if (!stack.language && !stack.framework) {
|
|
37
|
-
console.warn("\n ⚠️ No language or framework detected.");
|
|
38
|
-
console.warn(" Supported: Java, Kotlin, TypeScript, JavaScript, Python");
|
|
39
|
-
console.warn(" Ensure you have build.gradle, package.json, pyproject.toml, or requirements.txt in the project root.\n");
|
|
40
|
-
}
|
|
41
|
-
console.log(` Frontend: ${stack.frontend || "none"} ${stack.frontendVersion || ""}`);
|
|
42
|
-
console.log(` Database: ${stack.database || "none"}`);
|
|
43
|
-
console.log(` ORM: ${stack.orm || "none"}`);
|
|
44
|
-
console.log(` PackageMgr: ${stack.packageManager || "none"}\n`);
|
|
45
|
-
|
|
46
|
-
// Phase 2: Structure scan
|
|
47
|
-
console.log(" [Phase 2] Scanning structure...");
|
|
48
|
-
const { domains, backendDomains, frontendDomains, rootPackage, frontend } = await scanStructure(stack, ROOT);
|
|
49
|
-
console.log(` Backend: ${backendDomains.length} domains`);
|
|
50
|
-
console.log(` Frontend: ${frontendDomains.length} domains`);
|
|
51
|
-
console.log(` Total: ${domains.length} domains`);
|
|
52
|
-
if (rootPackage) console.log(` Package: ${rootPackage}`);
|
|
53
|
-
if (frontend.exists) console.log(` Components: ${frontend.components} components, ${frontend.pages} pages, ${frontend.hooks} hooks`);
|
|
54
|
-
if (backendDomains.length === 0 && frontendDomains.length === 0) {
|
|
55
|
-
console.warn("\n ⚠️ No domains detected.");
|
|
56
|
-
console.warn(" Pass 1 will be skipped. Generated output may be minimal.\n");
|
|
57
|
-
}
|
|
58
|
-
console.log();
|
|
59
|
-
|
|
60
|
-
// Phase 3: Template selection
|
|
61
|
-
console.log(" [Phase 3] Selecting templates...");
|
|
62
|
-
const templates = selectTemplates(stack);
|
|
63
|
-
const isMultiStack = !!(templates.backend && templates.frontend);
|
|
64
|
-
if (templates.backend) console.log(` Backend: ${templates.backend}`);
|
|
65
|
-
if (templates.frontend) console.log(` Frontend: ${templates.frontend}`);
|
|
66
|
-
console.log(` Mode: ${isMultiStack ? "🔀 Multi-stack" : "Single-stack"}`);
|
|
67
|
-
console.log();
|
|
68
|
-
|
|
69
|
-
// Phase 4: Domain group splitting
|
|
70
|
-
console.log(" [Phase 4] Splitting domain groups...");
|
|
71
|
-
const allGroups = [];
|
|
72
|
-
if (templates.backend && backendDomains.length > 0) allGroups.push(...splitDomainGroups(backendDomains, "backend", templates.backend));
|
|
73
|
-
if (templates.frontend && frontendDomains.length > 0) allGroups.push(...splitDomainGroups(frontendDomains, "frontend", templates.frontend));
|
|
74
|
-
allGroups.forEach((g, i) => { g.passNum = i + 1; });
|
|
75
|
-
allGroups.forEach((g, i) => {
|
|
76
|
-
const icon = g.type === "backend" ? "⚙️" : "🎨";
|
|
77
|
-
console.log(` ${icon} Group ${i + 1}: [${g.domains.join(", ")}] (${g.type}, ~${g.estimatedFiles} files)`);
|
|
78
|
-
});
|
|
79
|
-
console.log();
|
|
80
|
-
|
|
81
|
-
// Phase 5: Active domains
|
|
82
|
-
console.log(" [Phase 5] Active domains...");
|
|
83
|
-
const active = determineActiveDomains(stack);
|
|
84
|
-
Object.entries(active).forEach(([k, v]) => console.log(` ${v ? "✅" : "⏭️"} ${k}`));
|
|
85
|
-
console.log();
|
|
86
|
-
|
|
87
|
-
// Phase 6: Prompt generation
|
|
88
|
-
const lang = process.env.CLAUDEOS_LANG || "en";
|
|
89
|
-
console.log(` [Phase 6] Generating prompts (lang: ${lang})...`);
|
|
90
|
-
generatePrompts(templates, lang, TEMPLATES_DIR, GENERATED_DIR);
|
|
91
|
-
console.log();
|
|
92
|
-
|
|
93
|
-
// Save outputs
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
};
|
|
120
|
-
writeFileSafe(path.join(GENERATED_DIR, "
|
|
121
|
-
console.log(" 💾
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ClaudeOS-Core — plan-installer (orchestrator)
|
|
5
|
+
*
|
|
6
|
+
* Modules:
|
|
7
|
+
* - stack-detector.js — detectStack()
|
|
8
|
+
* - structure-scanner.js — scanStructure(), resolveSharedQueryDomains()
|
|
9
|
+
* - domain-grouper.js — splitDomainGroups(), determineActiveDomains(), selectTemplates()
|
|
10
|
+
* - prompt-generator.js — generatePrompts()
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const { ensureDir, writeFileSafe } = require("../lib/safe-fs");
|
|
15
|
+
const { detectStack } = require("./stack-detector");
|
|
16
|
+
const { scanStructure } = require("./structure-scanner");
|
|
17
|
+
const { splitDomainGroups, determineActiveDomains, selectTemplates } = require("./domain-grouper");
|
|
18
|
+
const { generatePrompts } = require("./prompt-generator");
|
|
19
|
+
|
|
20
|
+
const ROOT = process.env.CLAUDEOS_ROOT || path.resolve(__dirname, "../..");
|
|
21
|
+
const GENERATED_DIR = path.join(ROOT, "claudeos-core/generated");
|
|
22
|
+
const TEMPLATES_DIR = path.join(__dirname, "../pass-prompts/templates");
|
|
23
|
+
|
|
24
|
+
async function main() {
|
|
25
|
+
console.log("\n╔═══════════════════════════════════════╗");
|
|
26
|
+
console.log("║ ClaudeOS-Core — Plan Installer ║");
|
|
27
|
+
console.log("╚═══════════════════════════════════════╝\n");
|
|
28
|
+
|
|
29
|
+
ensureDir(GENERATED_DIR);
|
|
30
|
+
|
|
31
|
+
// Phase 1: Stack detection
|
|
32
|
+
console.log(" [Phase 1] Detecting stack...");
|
|
33
|
+
const stack = await detectStack(ROOT);
|
|
34
|
+
console.log(` Language: ${stack.language || "unknown"} ${stack.languageVersion || ""}`);
|
|
35
|
+
console.log(` Framework: ${stack.framework || "none"} ${stack.frameworkVersion || ""}`);
|
|
36
|
+
if (!stack.language && !stack.framework) {
|
|
37
|
+
console.warn("\n ⚠️ No language or framework detected.");
|
|
38
|
+
console.warn(" Supported: Java, Kotlin, TypeScript, JavaScript, Python");
|
|
39
|
+
console.warn(" Ensure you have build.gradle, package.json, pyproject.toml, or requirements.txt in the project root.\n");
|
|
40
|
+
}
|
|
41
|
+
console.log(` Frontend: ${stack.frontend || "none"} ${stack.frontendVersion || ""}`);
|
|
42
|
+
console.log(` Database: ${stack.database || "none"}`);
|
|
43
|
+
console.log(` ORM: ${stack.orm || "none"}`);
|
|
44
|
+
console.log(` PackageMgr: ${stack.packageManager || "none"}\n`);
|
|
45
|
+
|
|
46
|
+
// Phase 2: Structure scan
|
|
47
|
+
console.log(" [Phase 2] Scanning structure...");
|
|
48
|
+
const { domains, backendDomains, frontendDomains, rootPackage, frontend } = await scanStructure(stack, ROOT);
|
|
49
|
+
console.log(` Backend: ${backendDomains.length} domains`);
|
|
50
|
+
console.log(` Frontend: ${frontendDomains.length} domains`);
|
|
51
|
+
console.log(` Total: ${domains.length} domains`);
|
|
52
|
+
if (rootPackage) console.log(` Package: ${rootPackage}`);
|
|
53
|
+
if (frontend.exists) console.log(` Components: ${frontend.components} components, ${frontend.pages} pages, ${frontend.hooks} hooks`);
|
|
54
|
+
if (backendDomains.length === 0 && frontendDomains.length === 0) {
|
|
55
|
+
console.warn("\n ⚠️ No domains detected.");
|
|
56
|
+
console.warn(" Pass 1 will be skipped. Generated output may be minimal.\n");
|
|
57
|
+
}
|
|
58
|
+
console.log();
|
|
59
|
+
|
|
60
|
+
// Phase 3: Template selection
|
|
61
|
+
console.log(" [Phase 3] Selecting templates...");
|
|
62
|
+
const templates = selectTemplates(stack);
|
|
63
|
+
const isMultiStack = !!(templates.backend && templates.frontend);
|
|
64
|
+
if (templates.backend) console.log(` Backend: ${templates.backend}`);
|
|
65
|
+
if (templates.frontend) console.log(` Frontend: ${templates.frontend}`);
|
|
66
|
+
console.log(` Mode: ${isMultiStack ? "🔀 Multi-stack" : "Single-stack"}`);
|
|
67
|
+
console.log();
|
|
68
|
+
|
|
69
|
+
// Phase 4: Domain group splitting
|
|
70
|
+
console.log(" [Phase 4] Splitting domain groups...");
|
|
71
|
+
const allGroups = [];
|
|
72
|
+
if (templates.backend && backendDomains.length > 0) allGroups.push(...splitDomainGroups(backendDomains, "backend", templates.backend));
|
|
73
|
+
if (templates.frontend && frontendDomains.length > 0) allGroups.push(...splitDomainGroups(frontendDomains, "frontend", templates.frontend));
|
|
74
|
+
allGroups.forEach((g, i) => { g.passNum = i + 1; });
|
|
75
|
+
allGroups.forEach((g, i) => {
|
|
76
|
+
const icon = g.type === "backend" ? "⚙️" : "🎨";
|
|
77
|
+
console.log(` ${icon} Group ${i + 1}: [${g.domains.join(", ")}] (${g.type}, ~${g.estimatedFiles} files)`);
|
|
78
|
+
});
|
|
79
|
+
console.log();
|
|
80
|
+
|
|
81
|
+
// Phase 5: Active domains
|
|
82
|
+
console.log(" [Phase 5] Active domains...");
|
|
83
|
+
const active = determineActiveDomains(stack);
|
|
84
|
+
Object.entries(active).forEach(([k, v]) => console.log(` ${v ? "✅" : "⏭️"} ${k}`));
|
|
85
|
+
console.log();
|
|
86
|
+
|
|
87
|
+
// Phase 6: Prompt generation
|
|
88
|
+
const lang = process.env.CLAUDEOS_LANG || "en";
|
|
89
|
+
console.log(` [Phase 6] Generating prompts (lang: ${lang})...`);
|
|
90
|
+
generatePrompts(templates, lang, TEMPLATES_DIR, GENERATED_DIR);
|
|
91
|
+
console.log();
|
|
92
|
+
|
|
93
|
+
// Save outputs
|
|
94
|
+
//
|
|
95
|
+
// Port resolution precedence (stack.port):
|
|
96
|
+
// 1. stack.port already set by stack-detector (Spring application.yml
|
|
97
|
+
// server.port, or .env file PORT variable) — highest authority.
|
|
98
|
+
// 2. defaultPort fallback below — framework convention, only used when
|
|
99
|
+
// the project declares no port of its own. This is a last-resort
|
|
100
|
+
// default; prefer that stack-detector extract it from .env.example
|
|
101
|
+
// to keep CLAUDE.md truthful to what the project actually runs.
|
|
102
|
+
const defaultPort = (stack.framework === "fastapi" || stack.framework === "django") ? 8000
|
|
103
|
+
: stack.framework === "flask" ? 5000
|
|
104
|
+
: stack.framework === "vite" ? 5173
|
|
105
|
+
: stack.frontend === "angular" ? 4200
|
|
106
|
+
: stack.frontend === "nextjs" ? 3000
|
|
107
|
+
: (stack.framework === "express" || stack.framework === "nestjs" || stack.framework === "fastify") ? 3000 : 8080;
|
|
108
|
+
const analysis = {
|
|
109
|
+
analyzedAt: new Date().toISOString(), lang,
|
|
110
|
+
stack: { ...stack, port: stack.port || defaultPort },
|
|
111
|
+
templates, isMultiStack, rootPackage,
|
|
112
|
+
domains, backendDomains, frontendDomains, frontend,
|
|
113
|
+
activeDomains: active,
|
|
114
|
+
summary: {
|
|
115
|
+
totalDomains: domains.length, backendDomains: backendDomains.length,
|
|
116
|
+
frontendDomains: frontendDomains.length,
|
|
117
|
+
totalFiles: domains.reduce((s, d) => s + d.totalFiles, 0),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
writeFileSafe(path.join(GENERATED_DIR, "project-analysis.json"), JSON.stringify(analysis, null, 2));
|
|
121
|
+
console.log(" 💾 project-analysis.json saved");
|
|
122
|
+
|
|
123
|
+
const domainGroups = {
|
|
124
|
+
generatedAt: new Date().toISOString(), isMultiStack, templates,
|
|
125
|
+
totalDomains: domains.length, totalGroups: allGroups.length,
|
|
126
|
+
maxDomainsPerGroup: 4, maxFilesPerGroup: 40, groups: allGroups,
|
|
127
|
+
};
|
|
128
|
+
writeFileSafe(path.join(GENERATED_DIR, "domain-groups.json"), JSON.stringify(domainGroups, null, 2));
|
|
129
|
+
console.log(" 💾 domain-groups.json saved\n");
|
|
130
|
+
console.log(" ✅ Plan Installer complete\n");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
main().catch(e => {
|
|
134
|
+
console.error(`\n ❌ Plan Installer failed: ${e.message || e}`);
|
|
135
|
+
if (e.code === "EACCES" || e.code === "EPERM") console.error(" Check file/directory permissions.");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
});
|