@zeyue0329/xiaoma-cli 1.0.36 → 1.0.38
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/.idea/workspace.xml +27 -26
- package/JAVA-BACKEND-COMMANDS-REFERENCE.md +62 -52
- package/JAVA-BACKEND-ITERATION-GUIDE.md +125 -18
- package/README.md +1 -1
- package/common/utils/bmad-doc-template.md +5 -5
- package/dist/agents/analyst.txt +35 -5
- package/dist/agents/architect.txt +217 -31
- package/dist/agents/automation-orchestrator.txt +4 -4
- package/dist/agents/dev.txt +3 -3
- package/dist/agents/full-requirement-orchestrator.txt +11 -11
- package/dist/agents/qa.txt +102 -102
- package/dist/agents/sm.txt +6 -6
- package/dist/agents/ux-expert.txt +6 -1
- package/dist/agents/workflow-executor.txt +879 -0
- package/dist/agents/xiaoma-master.txt +258 -37
- package/dist/teams/team-all.txt +1223 -445
- package/dist/teams/team-fullstack-with-database.txt +384 -446
- package/dist/teams/team-fullstack.txt +258 -37
- package/dist/teams/team-ide-minimal.txt +111 -111
- package/dist/teams/team-no-ui.txt +252 -36
- package/docs/architecture-sharding-modification.md +623 -0
- package/docs/automated-requirements-analysis-outputs.md +896 -0
- package/package.json +1 -1
- package/tools/builders/web-builder.js +292 -142
- package/tools/bump-all-versions.js +50 -32
- package/tools/cli.js +52 -47
- package/tools/flattener/aggregate.js +30 -12
- package/tools/flattener/binary.js +46 -43
- package/tools/flattener/discovery.js +23 -15
- package/tools/flattener/files.js +6 -6
- package/tools/flattener/ignoreRules.js +122 -121
- package/tools/flattener/main.js +249 -144
- package/tools/flattener/projectRoot.js +74 -69
- package/tools/flattener/prompts.js +12 -10
- package/tools/flattener/stats.helpers.js +90 -61
- package/tools/flattener/stats.js +1 -1
- package/tools/flattener/test-matrix.js +225 -170
- package/tools/flattener/xml.js +31 -23
- package/tools/installer/bin/xiaoma.js +199 -153
- package/tools/installer/lib/config-loader.js +76 -47
- package/tools/installer/lib/file-manager.js +101 -44
- package/tools/installer/lib/ide-base-setup.js +49 -39
- package/tools/installer/lib/ide-setup.js +694 -380
- package/tools/installer/lib/installer.js +802 -469
- package/tools/installer/lib/memory-profiler.js +22 -12
- package/tools/installer/lib/module-manager.js +16 -14
- package/tools/installer/lib/resource-locator.js +61 -35
- package/tools/lib/dependency-resolver.js +34 -23
- package/tools/lib/yaml-utils.js +7 -2
- package/tools/preview-release-notes.js +33 -25
- package/tools/shared/bannerArt.js +3 -3
- package/tools/sync-installer-version.js +16 -7
- package/tools/upgraders/v3-to-v4-upgrader.js +244 -163
- package/tools/version-bump.js +24 -18
- package/tools/xiaoma-npx-wrapper.js +15 -10
- package/tools/yaml-format.js +60 -36
- package/xiaoma-core/agent-teams/team-fullstack-with-database.yaml +0 -1
- package/xiaoma-core/agents/automated-fix-validator.yaml +2 -1
- package/xiaoma-core/agents/automated-quality-validator.yaml +10 -5
- package/xiaoma-core/agents/automation-orchestrator.md +4 -4
- package/xiaoma-core/agents/dev.md +4 -4
- package/xiaoma-core/agents/enhanced-workflow-orchestrator.yaml +2 -1
- package/xiaoma-core/agents/full-requirement-orchestrator.md +11 -11
- package/xiaoma-core/agents/global-requirements-auditor.yaml +11 -3
- package/xiaoma-core/agents/intelligent-template-adapter.yaml +19 -5
- package/xiaoma-core/agents/master-execution-engine.yaml +19 -5
- package/xiaoma-core/agents/workflow-executor.md +126 -18
- package/xiaoma-core/agents/xiaoma-master.md +1 -1
- package/xiaoma-core/data/test-levels-framework.md +12 -12
- package/xiaoma-core/tasks/analyze-existing-database.md +1 -1
- package/xiaoma-core/tasks/apply-qa-fixes.md +3 -3
- package/xiaoma-core/tasks/batch-story-generation.md +22 -22
- package/xiaoma-core/tasks/create-enhanced-story-with-database.md +6 -6
- package/xiaoma-core/tasks/nfr-assess.md +6 -6
- package/xiaoma-core/tasks/project-integration-testing.md +42 -42
- package/xiaoma-core/tasks/qa-gate.md +23 -23
- package/xiaoma-core/tasks/review-story.md +18 -18
- package/xiaoma-core/tasks/risk-profile.md +25 -25
- package/xiaoma-core/tasks/serial-development-orchestration.md +51 -51
- package/xiaoma-core/tasks/test-design.md +9 -9
- package/xiaoma-core/tasks/trace-requirements.md +21 -21
- package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +35 -5
- package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +77 -11
- package/xiaoma-core/templates/front-end-spec-tmpl.yaml +6 -1
- package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +140 -20
- package/xiaoma-core/templates/global-qa-monitoring-tmpl.yaml +2 -1
- package/xiaoma-core/templates/requirements-coverage-audit.yaml +2 -1
- package/xiaoma-core/workflows/automated-requirements-analysis.yaml +4 -4
- package/dist/agents/database-architect.txt +0 -322
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const yaml = require(
|
|
1
|
+
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const yaml = require("js-yaml");
|
|
4
4
|
|
|
5
5
|
const arguments_ = process.argv.slice(2);
|
|
6
|
-
const bumpType = arguments_[0] ||
|
|
6
|
+
const bumpType = arguments_[0] || "minor"; // default to minor
|
|
7
7
|
|
|
8
|
-
if (![
|
|
9
|
-
console.log(
|
|
10
|
-
console.log(
|
|
8
|
+
if (!["major", "minor", "patch"].includes(bumpType)) {
|
|
9
|
+
console.log("Usage: node bump-all-versions.js [major|minor|patch]");
|
|
10
|
+
console.log("Default: minor");
|
|
11
11
|
process.exit(1);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function bumpVersion(currentVersion, type) {
|
|
15
|
-
const [major, minor, patch] = currentVersion.split(
|
|
15
|
+
const [major, minor, patch] = currentVersion.split(".").map(Number);
|
|
16
16
|
|
|
17
17
|
switch (type) {
|
|
18
|
-
case
|
|
18
|
+
case "major": {
|
|
19
19
|
return `${major + 1}.0.0`;
|
|
20
20
|
}
|
|
21
|
-
case
|
|
21
|
+
case "minor": {
|
|
22
22
|
return `${major}.${minor + 1}.0`;
|
|
23
23
|
}
|
|
24
|
-
case
|
|
24
|
+
case "patch": {
|
|
25
25
|
return `${major}.${minor}.${patch + 1}`;
|
|
26
26
|
}
|
|
27
27
|
default: {
|
|
@@ -34,44 +34,50 @@ async function bumpAllVersions() {
|
|
|
34
34
|
const updatedItems = [];
|
|
35
35
|
|
|
36
36
|
// First, bump the core version (package.json)
|
|
37
|
-
const packagePath = path.join(__dirname,
|
|
37
|
+
const packagePath = path.join(__dirname, "..", "package.json");
|
|
38
38
|
try {
|
|
39
|
-
const packageContent = fs.readFileSync(packagePath,
|
|
39
|
+
const packageContent = fs.readFileSync(packagePath, "utf8");
|
|
40
40
|
const packageJson = JSON.parse(packageContent);
|
|
41
|
-
const oldCoreVersion = packageJson.version ||
|
|
41
|
+
const oldCoreVersion = packageJson.version || "1.0.0";
|
|
42
42
|
const newCoreVersion = bumpVersion(oldCoreVersion, bumpType);
|
|
43
43
|
|
|
44
44
|
packageJson.version = newCoreVersion;
|
|
45
45
|
|
|
46
|
-
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) +
|
|
46
|
+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
47
47
|
|
|
48
48
|
updatedItems.push({
|
|
49
|
-
type:
|
|
50
|
-
name:
|
|
49
|
+
type: "core",
|
|
50
|
+
name: "BMad Core",
|
|
51
51
|
oldVersion: oldCoreVersion,
|
|
52
52
|
newVersion: newCoreVersion,
|
|
53
53
|
});
|
|
54
|
-
console.log(
|
|
54
|
+
console.log(
|
|
55
|
+
`✓ BMad Core (package.json): ${oldCoreVersion} → ${newCoreVersion}`,
|
|
56
|
+
);
|
|
55
57
|
} catch (error) {
|
|
56
58
|
console.error(`✗ Failed to update BMad Core: ${error.message}`);
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
// Then, bump all expansion packs
|
|
60
|
-
const expansionPacksDir = path.join(__dirname,
|
|
62
|
+
const expansionPacksDir = path.join(__dirname, "..", "expansion-packs");
|
|
61
63
|
|
|
62
64
|
try {
|
|
63
65
|
const entries = fs.readdirSync(expansionPacksDir, { withFileTypes: true });
|
|
64
66
|
|
|
65
67
|
for (const entry of entries) {
|
|
66
|
-
if (
|
|
68
|
+
if (
|
|
69
|
+
entry.isDirectory() &&
|
|
70
|
+
!entry.name.startsWith(".") &&
|
|
71
|
+
entry.name !== "README.md"
|
|
72
|
+
) {
|
|
67
73
|
const packId = entry.name;
|
|
68
|
-
const configPath = path.join(expansionPacksDir, packId,
|
|
74
|
+
const configPath = path.join(expansionPacksDir, packId, "config.yaml");
|
|
69
75
|
|
|
70
76
|
if (fs.existsSync(configPath)) {
|
|
71
77
|
try {
|
|
72
|
-
const configContent = fs.readFileSync(configPath,
|
|
78
|
+
const configContent = fs.readFileSync(configPath, "utf8");
|
|
73
79
|
const config = yaml.load(configContent);
|
|
74
|
-
const oldVersion = config.version ||
|
|
80
|
+
const oldVersion = config.version || "1.0.0";
|
|
75
81
|
const newVersion = bumpVersion(oldVersion, bumpType);
|
|
76
82
|
|
|
77
83
|
config.version = newVersion;
|
|
@@ -79,7 +85,12 @@ async function bumpAllVersions() {
|
|
|
79
85
|
const updatedYaml = yaml.dump(config, { indent: 2 });
|
|
80
86
|
fs.writeFileSync(configPath, updatedYaml);
|
|
81
87
|
|
|
82
|
-
updatedItems.push({
|
|
88
|
+
updatedItems.push({
|
|
89
|
+
type: "expansion",
|
|
90
|
+
name: packId,
|
|
91
|
+
oldVersion,
|
|
92
|
+
newVersion,
|
|
93
|
+
});
|
|
83
94
|
console.log(`✓ ${packId}: ${oldVersion} → ${newVersion}`);
|
|
84
95
|
} catch (error) {
|
|
85
96
|
console.error(`✗ Failed to update ${packId}: ${error.message}`);
|
|
@@ -89,25 +100,32 @@ async function bumpAllVersions() {
|
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
if (updatedItems.length > 0) {
|
|
92
|
-
const coreCount = updatedItems.filter(
|
|
93
|
-
|
|
103
|
+
const coreCount = updatedItems.filter(
|
|
104
|
+
(index) => index.type === "core",
|
|
105
|
+
).length;
|
|
106
|
+
const expansionCount = updatedItems.filter(
|
|
107
|
+
(index) => index.type === "expansion",
|
|
108
|
+
).length;
|
|
94
109
|
|
|
95
110
|
console.log(
|
|
96
111
|
`\n✓ Successfully bumped ${updatedItems.length} item(s) with ${bumpType} version bump`,
|
|
97
112
|
);
|
|
98
113
|
if (coreCount > 0) console.log(` - ${coreCount} core`);
|
|
99
|
-
if (expansionCount > 0)
|
|
114
|
+
if (expansionCount > 0)
|
|
115
|
+
console.log(` - ${expansionCount} expansion pack(s)`);
|
|
100
116
|
|
|
101
|
-
console.log(
|
|
102
|
-
console.log(
|
|
117
|
+
console.log("\nNext steps:");
|
|
118
|
+
console.log("1. Test the changes");
|
|
103
119
|
console.log(
|
|
104
|
-
'2. Commit: git add -A && git commit -m "chore: bump all versions (' +
|
|
120
|
+
'2. Commit: git add -A && git commit -m "chore: bump all versions (' +
|
|
121
|
+
bumpType +
|
|
122
|
+
')"',
|
|
105
123
|
);
|
|
106
124
|
} else {
|
|
107
|
-
console.log(
|
|
125
|
+
console.log("No items found to update");
|
|
108
126
|
}
|
|
109
127
|
} catch (error) {
|
|
110
|
-
console.error(
|
|
128
|
+
console.error("Error reading expansion packs directory:", error.message);
|
|
111
129
|
process.exit(1);
|
|
112
130
|
}
|
|
113
131
|
}
|
package/tools/cli.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
const { Command } = require(
|
|
2
|
-
const WebBuilder = require(
|
|
3
|
-
const V3ToV4Upgrader = require(
|
|
4
|
-
const IdeSetup = require(
|
|
5
|
-
const path = require(
|
|
1
|
+
const { Command } = require("commander");
|
|
2
|
+
const WebBuilder = require("./builders/web-builder");
|
|
3
|
+
const V3ToV4Upgrader = require("./upgraders/v3-to-v4-upgrader");
|
|
4
|
+
const IdeSetup = require("./installer/lib/ide-setup");
|
|
5
|
+
const path = require("node:path");
|
|
6
6
|
|
|
7
7
|
const program = new Command();
|
|
8
8
|
|
|
9
9
|
program
|
|
10
|
-
.name(
|
|
11
|
-
.description(
|
|
12
|
-
.version(
|
|
10
|
+
.name("bmad-build")
|
|
11
|
+
.description("XIAOMA-CLI™ build tool for creating web bundles")
|
|
12
|
+
.version("4.0.0");
|
|
13
13
|
|
|
14
14
|
program
|
|
15
|
-
.command(
|
|
16
|
-
.description(
|
|
17
|
-
.option(
|
|
18
|
-
.option(
|
|
19
|
-
.option(
|
|
20
|
-
.option(
|
|
21
|
-
.option(
|
|
15
|
+
.command("build")
|
|
16
|
+
.description("Build web bundles for agents and teams")
|
|
17
|
+
.option("-a, --agents-only", "Build only agent bundles")
|
|
18
|
+
.option("-t, --teams-only", "Build only team bundles")
|
|
19
|
+
.option("-e, --expansions-only", "Build only expansion pack bundles")
|
|
20
|
+
.option("--no-expansions", "Skip building expansion packs")
|
|
21
|
+
.option("--no-clean", "Skip cleaning output directories")
|
|
22
22
|
.action(async (options) => {
|
|
23
23
|
const builder = new WebBuilder({
|
|
24
24
|
rootDir: process.cwd(),
|
|
@@ -26,42 +26,42 @@ program
|
|
|
26
26
|
|
|
27
27
|
try {
|
|
28
28
|
if (options.clean) {
|
|
29
|
-
console.log(
|
|
29
|
+
console.log("Cleaning output directories...");
|
|
30
30
|
await builder.cleanOutputDirs();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if (options.expansionsOnly) {
|
|
34
|
-
console.log(
|
|
34
|
+
console.log("Building expansion pack bundles...");
|
|
35
35
|
await builder.buildAllExpansionPacks({ clean: false });
|
|
36
36
|
} else {
|
|
37
37
|
if (!options.teamsOnly) {
|
|
38
|
-
console.log(
|
|
38
|
+
console.log("Building agent bundles...");
|
|
39
39
|
await builder.buildAgents();
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (!options.agentsOnly) {
|
|
43
|
-
console.log(
|
|
43
|
+
console.log("Building team bundles...");
|
|
44
44
|
await builder.buildTeams();
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
if (!options.noExpansions) {
|
|
48
|
-
console.log(
|
|
48
|
+
console.log("Building expansion pack bundles...");
|
|
49
49
|
await builder.buildAllExpansionPacks({ clean: false });
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
console.log(
|
|
53
|
+
console.log("Build completed successfully!");
|
|
54
54
|
} catch (error) {
|
|
55
|
-
console.error(
|
|
55
|
+
console.error("Build failed:", error.message);
|
|
56
56
|
process.exit(1);
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
program
|
|
61
|
-
.command(
|
|
62
|
-
.description(
|
|
63
|
-
.option(
|
|
64
|
-
.option(
|
|
61
|
+
.command("build:expansions")
|
|
62
|
+
.description("Build web bundles for all expansion packs")
|
|
63
|
+
.option("--expansion <name>", "Build specific expansion pack only")
|
|
64
|
+
.option("--no-clean", "Skip cleaning output directories")
|
|
65
65
|
.action(async (options) => {
|
|
66
66
|
const builder = new WebBuilder({
|
|
67
67
|
rootDir: process.cwd(),
|
|
@@ -70,44 +70,46 @@ program
|
|
|
70
70
|
try {
|
|
71
71
|
if (options.expansion) {
|
|
72
72
|
console.log(`Building expansion pack: ${options.expansion}`);
|
|
73
|
-
await builder.buildExpansionPack(options.expansion, {
|
|
73
|
+
await builder.buildExpansionPack(options.expansion, {
|
|
74
|
+
clean: options.clean,
|
|
75
|
+
});
|
|
74
76
|
} else {
|
|
75
|
-
console.log(
|
|
77
|
+
console.log("Building all expansion packs...");
|
|
76
78
|
await builder.buildAllExpansionPacks({ clean: options.clean });
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
console.log(
|
|
81
|
+
console.log("Expansion pack build completed successfully!");
|
|
80
82
|
} catch (error) {
|
|
81
|
-
console.error(
|
|
83
|
+
console.error("Expansion pack build failed:", error.message);
|
|
82
84
|
process.exit(1);
|
|
83
85
|
}
|
|
84
86
|
});
|
|
85
87
|
|
|
86
88
|
program
|
|
87
|
-
.command(
|
|
88
|
-
.description(
|
|
89
|
+
.command("list:agents")
|
|
90
|
+
.description("List all available agents")
|
|
89
91
|
.action(async () => {
|
|
90
92
|
const builder = new WebBuilder({ rootDir: process.cwd() });
|
|
91
93
|
const agents = await builder.resolver.listAgents();
|
|
92
|
-
console.log(
|
|
94
|
+
console.log("Available agents:");
|
|
93
95
|
for (const agent of agents) console.log(` - ${agent}`);
|
|
94
96
|
process.exit(0);
|
|
95
97
|
});
|
|
96
98
|
|
|
97
99
|
program
|
|
98
|
-
.command(
|
|
99
|
-
.description(
|
|
100
|
+
.command("list:expansions")
|
|
101
|
+
.description("List all available expansion packs")
|
|
100
102
|
.action(async () => {
|
|
101
103
|
const builder = new WebBuilder({ rootDir: process.cwd() });
|
|
102
104
|
const expansions = await builder.listExpansionPacks();
|
|
103
|
-
console.log(
|
|
105
|
+
console.log("Available expansion packs:");
|
|
104
106
|
for (const expansion of expansions) console.log(` - ${expansion}`);
|
|
105
107
|
process.exit(0);
|
|
106
108
|
});
|
|
107
109
|
|
|
108
110
|
program
|
|
109
|
-
.command(
|
|
110
|
-
.description(
|
|
111
|
+
.command("validate")
|
|
112
|
+
.description("Validate agent and team configurations")
|
|
111
113
|
.action(async () => {
|
|
112
114
|
const builder = new WebBuilder({ rootDir: process.cwd() });
|
|
113
115
|
try {
|
|
@@ -115,31 +117,34 @@ program
|
|
|
115
117
|
const agents = await builder.resolver.listAgents();
|
|
116
118
|
const teams = await builder.resolver.listTeams();
|
|
117
119
|
|
|
118
|
-
console.log(
|
|
120
|
+
console.log("Validating agents...");
|
|
119
121
|
for (const agent of agents) {
|
|
120
122
|
await builder.resolver.resolveAgentDependencies(agent);
|
|
121
123
|
console.log(` ✓ ${agent}`);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
console.log(
|
|
126
|
+
console.log("\nValidating teams...");
|
|
125
127
|
for (const team of teams) {
|
|
126
128
|
await builder.resolver.resolveTeamDependencies(team);
|
|
127
129
|
console.log(` ✓ ${team}`);
|
|
128
130
|
}
|
|
129
131
|
|
|
130
|
-
console.log(
|
|
132
|
+
console.log("\nAll configurations are valid!");
|
|
131
133
|
} catch (error) {
|
|
132
|
-
console.error(
|
|
134
|
+
console.error("Validation failed:", error.message);
|
|
133
135
|
process.exit(1);
|
|
134
136
|
}
|
|
135
137
|
});
|
|
136
138
|
|
|
137
139
|
program
|
|
138
|
-
.command(
|
|
139
|
-
.description(
|
|
140
|
-
.option(
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
.command("upgrade")
|
|
141
|
+
.description("Upgrade a XIAOMA-CLI™ V3 project to V4")
|
|
142
|
+
.option(
|
|
143
|
+
"-p, --project <path>",
|
|
144
|
+
"Path to V3 project (defaults to current directory)",
|
|
145
|
+
)
|
|
146
|
+
.option("--dry-run", "Show what would be changed without making changes")
|
|
147
|
+
.option("--no-backup", "Skip creating backup (not recommended)")
|
|
143
148
|
.action(async (options) => {
|
|
144
149
|
const upgrader = new V3ToV4Upgrader();
|
|
145
150
|
await upgrader.upgrade({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const os = require(
|
|
4
|
-
const { isBinaryFile } = require(
|
|
1
|
+
const fs = require("fs-extra");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const os = require("node:os");
|
|
4
|
+
const { isBinaryFile } = require("./binary.js");
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Aggregate file contents with bounded concurrency.
|
|
@@ -22,10 +22,16 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
|
|
|
22
22
|
// Automatic concurrency selection based on CPU count and workload size.
|
|
23
23
|
// - Base on 2x logical CPUs, clamped to [2, 64]
|
|
24
24
|
// - For very small workloads, avoid excessive parallelism
|
|
25
|
-
const cpuCount =
|
|
25
|
+
const cpuCount =
|
|
26
|
+
os.cpus && Array.isArray(os.cpus())
|
|
27
|
+
? os.cpus().length
|
|
28
|
+
: os.cpus?.length || 4;
|
|
26
29
|
let concurrency = Math.min(64, Math.max(2, (Number(cpuCount) || 4) * 2));
|
|
27
30
|
if (files.length > 0 && files.length < concurrency) {
|
|
28
|
-
concurrency = Math.max(
|
|
31
|
+
concurrency = Math.max(
|
|
32
|
+
1,
|
|
33
|
+
Math.min(concurrency, Math.ceil(files.length / 2)),
|
|
34
|
+
);
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
async function processOne(filePath) {
|
|
@@ -38,25 +44,37 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
|
|
|
38
44
|
const binary = await isBinaryFile(filePath);
|
|
39
45
|
if (binary) {
|
|
40
46
|
const { size } = await fs.stat(filePath);
|
|
41
|
-
results.binaryFiles.push({
|
|
47
|
+
results.binaryFiles.push({
|
|
48
|
+
path: relativePath,
|
|
49
|
+
absolutePath: filePath,
|
|
50
|
+
size,
|
|
51
|
+
});
|
|
42
52
|
} else {
|
|
43
|
-
const content = await fs.readFile(filePath,
|
|
53
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
44
54
|
results.textFiles.push({
|
|
45
55
|
path: relativePath,
|
|
46
56
|
absolutePath: filePath,
|
|
47
57
|
content,
|
|
48
58
|
size: content.length,
|
|
49
|
-
lines: content.split(
|
|
59
|
+
lines: content.split("\n").length,
|
|
50
60
|
});
|
|
51
61
|
}
|
|
52
62
|
} catch (error) {
|
|
53
63
|
const relativePath = path.relative(rootDir, filePath);
|
|
54
|
-
const errorInfo = {
|
|
64
|
+
const errorInfo = {
|
|
65
|
+
path: relativePath,
|
|
66
|
+
absolutePath: filePath,
|
|
67
|
+
error: error.message,
|
|
68
|
+
};
|
|
55
69
|
results.errors.push(errorInfo);
|
|
56
70
|
if (spinner) {
|
|
57
|
-
spinner.warn(
|
|
71
|
+
spinner.warn(
|
|
72
|
+
`Warning: Could not read file ${relativePath}: ${error.message}`,
|
|
73
|
+
);
|
|
58
74
|
} else {
|
|
59
|
-
console.warn(
|
|
75
|
+
console.warn(
|
|
76
|
+
`Warning: Could not read file ${relativePath}: ${error.message}`,
|
|
77
|
+
);
|
|
60
78
|
}
|
|
61
79
|
} finally {
|
|
62
80
|
results.processedFiles++;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const fsp = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const { Buffer } = require(
|
|
1
|
+
const fsp = require("node:fs/promises");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const { Buffer } = require("node:buffer");
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Efficiently determine if a file is binary without reading the whole file.
|
|
@@ -13,46 +13,46 @@ async function isBinaryFile(filePath) {
|
|
|
13
13
|
try {
|
|
14
14
|
const stats = await fsp.stat(filePath);
|
|
15
15
|
if (stats.isDirectory()) {
|
|
16
|
-
throw new Error(
|
|
16
|
+
throw new Error("EISDIR: illegal operation on a directory");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const binaryExtensions = new Set([
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
20
|
+
".jpg",
|
|
21
|
+
".jpeg",
|
|
22
|
+
".png",
|
|
23
|
+
".gif",
|
|
24
|
+
".bmp",
|
|
25
|
+
".ico",
|
|
26
|
+
".svg",
|
|
27
|
+
".pdf",
|
|
28
|
+
".doc",
|
|
29
|
+
".docx",
|
|
30
|
+
".xls",
|
|
31
|
+
".xlsx",
|
|
32
|
+
".ppt",
|
|
33
|
+
".pptx",
|
|
34
|
+
".zip",
|
|
35
|
+
".tar",
|
|
36
|
+
".gz",
|
|
37
|
+
".rar",
|
|
38
|
+
".7z",
|
|
39
|
+
".exe",
|
|
40
|
+
".dll",
|
|
41
|
+
".so",
|
|
42
|
+
".dylib",
|
|
43
|
+
".mp3",
|
|
44
|
+
".mp4",
|
|
45
|
+
".avi",
|
|
46
|
+
".mov",
|
|
47
|
+
".wav",
|
|
48
|
+
".ttf",
|
|
49
|
+
".otf",
|
|
50
|
+
".woff",
|
|
51
|
+
".woff2",
|
|
52
|
+
".bin",
|
|
53
|
+
".dat",
|
|
54
|
+
".db",
|
|
55
|
+
".sqlite",
|
|
56
56
|
]);
|
|
57
57
|
|
|
58
58
|
const extension = path.extname(filePath).toLowerCase();
|
|
@@ -60,17 +60,20 @@ async function isBinaryFile(filePath) {
|
|
|
60
60
|
if (stats.size === 0) return false;
|
|
61
61
|
|
|
62
62
|
const sampleSize = Math.min(4096, stats.size);
|
|
63
|
-
const fd = await fsp.open(filePath,
|
|
63
|
+
const fd = await fsp.open(filePath, "r");
|
|
64
64
|
try {
|
|
65
65
|
const buffer = Buffer.allocUnsafe(sampleSize);
|
|
66
66
|
const { bytesRead } = await fd.read(buffer, 0, sampleSize, 0);
|
|
67
|
-
const slice =
|
|
67
|
+
const slice =
|
|
68
|
+
bytesRead === sampleSize ? buffer : buffer.subarray(0, bytesRead);
|
|
68
69
|
return slice.includes(0);
|
|
69
70
|
} finally {
|
|
70
71
|
await fd.close();
|
|
71
72
|
}
|
|
72
73
|
} catch (error) {
|
|
73
|
-
console.warn(
|
|
74
|
+
console.warn(
|
|
75
|
+
`Warning: Could not determine if file is binary: ${filePath} - ${error.message}`,
|
|
76
|
+
);
|
|
74
77
|
return false;
|
|
75
78
|
}
|
|
76
79
|
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const { execFile } = require(
|
|
3
|
-
const { promisify } = require(
|
|
4
|
-
const { glob } = require(
|
|
5
|
-
const { loadIgnore } = require(
|
|
1
|
+
const path = require("node:path");
|
|
2
|
+
const { execFile } = require("node:child_process");
|
|
3
|
+
const { promisify } = require("node:util");
|
|
4
|
+
const { glob } = require("glob");
|
|
5
|
+
const { loadIgnore } = require("./ignoreRules.js");
|
|
6
6
|
|
|
7
7
|
const pExecFile = promisify(execFile);
|
|
8
8
|
|
|
9
9
|
async function isGitRepo(rootDir) {
|
|
10
10
|
try {
|
|
11
|
-
const { stdout } = await pExecFile(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const { stdout } = await pExecFile(
|
|
12
|
+
"git",
|
|
13
|
+
["rev-parse", "--is-inside-work-tree"],
|
|
14
|
+
{
|
|
15
|
+
cwd: rootDir,
|
|
16
|
+
},
|
|
17
|
+
);
|
|
14
18
|
return (
|
|
15
|
-
String(stdout ||
|
|
19
|
+
String(stdout || "")
|
|
16
20
|
.toString()
|
|
17
|
-
.trim() ===
|
|
21
|
+
.trim() === "true"
|
|
18
22
|
);
|
|
19
23
|
} catch {
|
|
20
24
|
return false;
|
|
@@ -23,10 +27,14 @@ async function isGitRepo(rootDir) {
|
|
|
23
27
|
|
|
24
28
|
async function gitListFiles(rootDir) {
|
|
25
29
|
try {
|
|
26
|
-
const { stdout } = await pExecFile(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
const { stdout } = await pExecFile(
|
|
31
|
+
"git",
|
|
32
|
+
["ls-files", "-co", "--exclude-standard"],
|
|
33
|
+
{
|
|
34
|
+
cwd: rootDir,
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
return String(stdout || "")
|
|
30
38
|
.split(/\r?\n/)
|
|
31
39
|
.map((s) => s.trim())
|
|
32
40
|
.filter(Boolean);
|
|
@@ -56,7 +64,7 @@ async function discoverFiles(rootDir, options = {}) {
|
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
// Glob fallback
|
|
59
|
-
const globbed = await glob(
|
|
67
|
+
const globbed = await glob("**/*", {
|
|
60
68
|
cwd: rootDir,
|
|
61
69
|
nodir: true,
|
|
62
70
|
dot: true,
|
package/tools/flattener/files.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const discovery = require(
|
|
3
|
-
const ignoreRules = require(
|
|
4
|
-
const { isBinaryFile } = require(
|
|
5
|
-
const { aggregateFileContents } = require(
|
|
1
|
+
const path = require("node:path");
|
|
2
|
+
const discovery = require("./discovery.js");
|
|
3
|
+
const ignoreRules = require("./ignoreRules.js");
|
|
4
|
+
const { isBinaryFile } = require("./binary.js");
|
|
5
|
+
const { aggregateFileContents } = require("./aggregate.js");
|
|
6
6
|
|
|
7
7
|
// Backward-compatible signature; delegate to central loader
|
|
8
8
|
async function parseGitignore(gitignorePath) {
|
|
@@ -14,7 +14,7 @@ async function discoverFiles(rootDir) {
|
|
|
14
14
|
// Delegate to discovery module which respects .gitignore and defaults
|
|
15
15
|
return await discovery.discoverFiles(rootDir, { preferGit: true });
|
|
16
16
|
} catch (error) {
|
|
17
|
-
console.error(
|
|
17
|
+
console.error("Error discovering files:", error.message);
|
|
18
18
|
return [];
|
|
19
19
|
}
|
|
20
20
|
}
|