stackscan 0.1.6 → 0.1.9
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/dist/add.js +2 -2
- package/dist/add.mjs +1 -1
- package/dist/chunk-4WANII4B.mjs +158 -0
- package/dist/chunk-ACCTMJVS.mjs +49 -0
- package/dist/chunk-DYBWKLM7.mjs +158 -0
- package/dist/chunk-GI46Z5RR.mjs +158 -0
- package/dist/chunk-UJM3S22V.mjs +179 -0
- package/dist/chunk-WAXGOBY2.mjs +0 -0
- package/dist/chunk-XS2LU2MN.mjs +158 -0
- package/dist/cli.js +7 -7
- package/dist/cli.mjs +7 -7
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5956 -0
- package/dist/index.mjs +37 -0
- package/dist/output.mjs +2 -2
- package/dist/scan.js +3 -3
- package/dist/scan.mjs +4 -4
- package/dist/sync.js +3 -3
- package/dist/sync.mjs +6 -154
- package/dist/types.mjs +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_CATEGORY_ICONS
|
|
3
|
+
} from "./chunk-NGEKE4DQ.mjs";
|
|
4
|
+
import {
|
|
5
|
+
__dirname
|
|
6
|
+
} from "./chunk-EOKQCSHI.mjs";
|
|
7
|
+
import {
|
|
8
|
+
simple_icons_hex_default
|
|
9
|
+
} from "./chunk-EH2SEQZP.mjs";
|
|
10
|
+
|
|
11
|
+
// src/output.ts
|
|
12
|
+
import fs from "fs-extra";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { createRequire } from "module";
|
|
16
|
+
var require2 = createRequire(import.meta.url);
|
|
17
|
+
async function writeOutput(outPath, techs, config, format = "json", assetsOutPath) {
|
|
18
|
+
const outDirectory = path.dirname(outPath);
|
|
19
|
+
await fs.ensureDir(outDirectory);
|
|
20
|
+
let availableLogos = /* @__PURE__ */ new Set();
|
|
21
|
+
if (assetsOutPath) {
|
|
22
|
+
availableLogos = await copyAssets(techs, assetsOutPath, config);
|
|
23
|
+
}
|
|
24
|
+
if (format === "json") {
|
|
25
|
+
await fs.writeJSON(
|
|
26
|
+
outPath,
|
|
27
|
+
{
|
|
28
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29
|
+
tech: techs
|
|
30
|
+
},
|
|
31
|
+
{ spaces: 2 }
|
|
32
|
+
);
|
|
33
|
+
console.log(chalk.blue(`\u2192 Saved ${techs.length} tech entries to ${outPath}`));
|
|
34
|
+
} else if (format === "markdown") {
|
|
35
|
+
const relativeAssetsPath = assetsOutPath ? path.relative(outDirectory, assetsOutPath).replace(/\\/g, "/") : void 0;
|
|
36
|
+
const mdContent = generateMarkdown(techs, relativeAssetsPath, availableLogos);
|
|
37
|
+
const mdPath = outPath.endsWith(".json") ? outPath.replace(/\.json$/, ".md") : outPath;
|
|
38
|
+
await fs.writeFile(mdPath, mdContent);
|
|
39
|
+
console.log(chalk.blue(`\u2192 Saved markdown to ${mdPath}`));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function copyAssets(techs, dest, config) {
|
|
43
|
+
const srcDir = path.resolve(__dirname, "../public/assets/logos");
|
|
44
|
+
let lucideDir;
|
|
45
|
+
try {
|
|
46
|
+
lucideDir = path.join(path.dirname(require2.resolve("lucide-static/package.json")), "icons");
|
|
47
|
+
} catch (e) {
|
|
48
|
+
lucideDir = path.resolve(__dirname, "../node_modules/lucide-static/icons");
|
|
49
|
+
}
|
|
50
|
+
const copied = /* @__PURE__ */ new Set();
|
|
51
|
+
let count = 0;
|
|
52
|
+
for (const t of techs) {
|
|
53
|
+
let srcFile = t.logo ? path.join(srcDir, t.logo) : null;
|
|
54
|
+
let destFile = t.logo ? path.join(dest, t.logo) : null;
|
|
55
|
+
let isDefault = false;
|
|
56
|
+
if (!srcFile || !await fs.pathExists(srcFile)) {
|
|
57
|
+
const defaultIconName = DEFAULT_CATEGORY_ICONS[t.type];
|
|
58
|
+
if (defaultIconName) {
|
|
59
|
+
const lucideFile = path.join(lucideDir, `${defaultIconName}.svg`);
|
|
60
|
+
if (await fs.pathExists(lucideFile)) {
|
|
61
|
+
srcFile = lucideFile;
|
|
62
|
+
const newLogoPath = `defaults/${defaultIconName}.svg`;
|
|
63
|
+
destFile = path.join(dest, newLogoPath);
|
|
64
|
+
t.logo = newLogoPath;
|
|
65
|
+
isDefault = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (srcFile && destFile && await fs.pathExists(srcFile)) {
|
|
70
|
+
await fs.ensureDir(path.dirname(destFile));
|
|
71
|
+
let svgContent = await fs.readFile(srcFile, "utf8");
|
|
72
|
+
let color;
|
|
73
|
+
if (config.iconColors && config.iconColors[t.name]) {
|
|
74
|
+
color = config.iconColors[t.name];
|
|
75
|
+
} else if (config.colorMode === "white") {
|
|
76
|
+
color = "#FFFFFF";
|
|
77
|
+
} else if (config.colorMode === "black") {
|
|
78
|
+
color = "#000000";
|
|
79
|
+
} else if (config.colorMode === "custom" && config.customColor) {
|
|
80
|
+
color = config.customColor;
|
|
81
|
+
} else if (config.colorMode === "default" || !config.colorMode || config.colorMode === "brand") {
|
|
82
|
+
if (!isDefault) {
|
|
83
|
+
const slug = path.basename(t.logo, ".svg");
|
|
84
|
+
const brandHex = simple_icons_hex_default[slug] || simple_icons_hex_default[slug.toLowerCase()];
|
|
85
|
+
if (brandHex) {
|
|
86
|
+
color = `#${brandHex}`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (color) {
|
|
91
|
+
if (isDefault) {
|
|
92
|
+
if (svgContent.includes("stroke=")) {
|
|
93
|
+
svgContent = svgContent.replace(/stroke="[^"]*"/g, `stroke="${color}"`);
|
|
94
|
+
} else {
|
|
95
|
+
svgContent = svgContent.replace("<svg", `<svg stroke="${color}"`);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
if (svgContent.includes("fill=")) {
|
|
99
|
+
svgContent = svgContent.replace(/fill="[^"]*"/g, `fill="${color}"`);
|
|
100
|
+
} else {
|
|
101
|
+
svgContent = svgContent.replace("<svg", `<svg fill="${color}"`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
await fs.writeFile(destFile, svgContent);
|
|
106
|
+
copied.add(t.logo);
|
|
107
|
+
if (!isDefault) count++;
|
|
108
|
+
} else {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (count > 0) {
|
|
112
|
+
console.log(chalk.blue(`\u2192 Copied ${count} logos to ${dest}`));
|
|
113
|
+
}
|
|
114
|
+
return copied;
|
|
115
|
+
}
|
|
116
|
+
function generateMarkdown(techs, assetsPath, availableLogos) {
|
|
117
|
+
const grouped = {};
|
|
118
|
+
for (const t of techs) {
|
|
119
|
+
const type = t.type || "misc";
|
|
120
|
+
if (!grouped[type]) grouped[type] = [];
|
|
121
|
+
grouped[type].push(t);
|
|
122
|
+
}
|
|
123
|
+
let md = "# Tech Stack\n\n";
|
|
124
|
+
const order = [
|
|
125
|
+
"language",
|
|
126
|
+
"frontend",
|
|
127
|
+
"backend",
|
|
128
|
+
"framework",
|
|
129
|
+
"library",
|
|
130
|
+
"database",
|
|
131
|
+
"orm",
|
|
132
|
+
"auth",
|
|
133
|
+
"api",
|
|
134
|
+
"cloud",
|
|
135
|
+
"hosting",
|
|
136
|
+
"ci",
|
|
137
|
+
"devops",
|
|
138
|
+
"container",
|
|
139
|
+
"testing",
|
|
140
|
+
"build",
|
|
141
|
+
"tooling",
|
|
142
|
+
"misc"
|
|
143
|
+
];
|
|
144
|
+
const sortedKeys = Object.keys(grouped).sort((a, b) => {
|
|
145
|
+
const idxA = order.indexOf(a);
|
|
146
|
+
const idxB = order.indexOf(b);
|
|
147
|
+
if (idxA === -1 && idxB === -1) return a.localeCompare(b);
|
|
148
|
+
if (idxA === -1) return 1;
|
|
149
|
+
if (idxB === -1) return -1;
|
|
150
|
+
return idxA - idxB;
|
|
151
|
+
});
|
|
152
|
+
for (const type of sortedKeys) {
|
|
153
|
+
const title = type.charAt(0).toUpperCase() + type.slice(1);
|
|
154
|
+
md += `## ${title}
|
|
155
|
+
|
|
156
|
+
`;
|
|
157
|
+
for (const t of grouped[type]) {
|
|
158
|
+
if (t.logo && (t.logo.startsWith("http") || t.logo.startsWith("//"))) {
|
|
159
|
+
md += `- <img src="${t.logo}" alt="${t.name}" width="24" height="24" /> **${t.name}**
|
|
160
|
+
`;
|
|
161
|
+
} else if (assetsPath && t.logo && availableLogos?.has(t.logo)) {
|
|
162
|
+
const logoUrl = `${assetsPath}/${t.logo}`;
|
|
163
|
+
md += `- <img src="${logoUrl}" alt="${t.name}" width="24" height="24" /> **${t.name}**
|
|
164
|
+
`;
|
|
165
|
+
} else {
|
|
166
|
+
md += `- **${t.name}**
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
md += "\n";
|
|
171
|
+
}
|
|
172
|
+
return md;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export {
|
|
176
|
+
writeOutput,
|
|
177
|
+
copyAssets,
|
|
178
|
+
generateMarkdown
|
|
179
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
techMap
|
|
3
|
+
} from "./chunk-LSUI3VI4.mjs";
|
|
4
|
+
import {
|
|
5
|
+
copyAssets,
|
|
6
|
+
generateMarkdown
|
|
7
|
+
} from "./chunk-UJM3S22V.mjs";
|
|
8
|
+
import {
|
|
9
|
+
simple_icons_hex_default
|
|
10
|
+
} from "./chunk-EH2SEQZP.mjs";
|
|
11
|
+
|
|
12
|
+
// src/sync.ts
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import path from "path";
|
|
15
|
+
var BASE_DIR = path.join(process.cwd(), "public", "stackscan");
|
|
16
|
+
var SKIPPED_TECHS = [
|
|
17
|
+
"react-dom"
|
|
18
|
+
];
|
|
19
|
+
async function sync(options = {}) {
|
|
20
|
+
console.log("\u{1F680} Starting Sync...");
|
|
21
|
+
if (options.color) {
|
|
22
|
+
console.log(`\u{1F3A8} Color mode: ${options.color}`);
|
|
23
|
+
}
|
|
24
|
+
if (!fs.existsSync(BASE_DIR)) {
|
|
25
|
+
console.log(`Creating stackscan directory at: ${BASE_DIR}`);
|
|
26
|
+
fs.mkdirSync(BASE_DIR, { recursive: true });
|
|
27
|
+
console.log('Please place your project folders inside "public/stackscan/" and run this command again.');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
const entries = fs.readdirSync(BASE_DIR, { withFileTypes: true });
|
|
31
|
+
const projectDirs = entries.filter((dirent) => dirent.isDirectory() && dirent.name !== "input" && dirent.name !== "output");
|
|
32
|
+
if (projectDirs.length === 0) {
|
|
33
|
+
console.log('\u26A0\uFE0F No project directories found in "public/stackscan/".');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(`Found ${projectDirs.length} projects to process.
|
|
37
|
+
`);
|
|
38
|
+
const allProjects = [];
|
|
39
|
+
const allTechs = [];
|
|
40
|
+
for (const dir of projectDirs) {
|
|
41
|
+
const projectPath = path.join(BASE_DIR, dir.name);
|
|
42
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
43
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
44
|
+
try {
|
|
45
|
+
const content = fs.readFileSync(packageJsonPath, "utf-8");
|
|
46
|
+
const pkg = JSON.parse(content);
|
|
47
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
48
|
+
const detectedTechs = [];
|
|
49
|
+
Object.keys(allDeps).forEach((dep) => {
|
|
50
|
+
if (SKIPPED_TECHS.includes(dep)) return;
|
|
51
|
+
if (techMap[dep]) {
|
|
52
|
+
const tech = techMap[dep];
|
|
53
|
+
let color = null;
|
|
54
|
+
if (options.color === "white") color = "#FFFFFF";
|
|
55
|
+
else if (options.color === "black") color = "#000000";
|
|
56
|
+
else if (options.color && options.color.startsWith("#")) color = options.color;
|
|
57
|
+
else {
|
|
58
|
+
const depSlug = dep.toLowerCase();
|
|
59
|
+
const nameSlug = tech.name.toLowerCase();
|
|
60
|
+
const nameSlugNoSpaces = tech.name.toLowerCase().replace(/\s+/g, "");
|
|
61
|
+
const hex = simple_icons_hex_default[depSlug] || simple_icons_hex_default[nameSlug] || simple_icons_hex_default[nameSlugNoSpaces];
|
|
62
|
+
if (hex) color = `#${hex}`;
|
|
63
|
+
}
|
|
64
|
+
detectedTechs.push({
|
|
65
|
+
name: tech.name,
|
|
66
|
+
slug: dep,
|
|
67
|
+
logo: tech.logo,
|
|
68
|
+
// Raw path for resolution
|
|
69
|
+
color
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
let uniqueTechs = Array.from(new Set(detectedTechs.map((t) => t.slug))).map((slug) => detectedTechs.find((t) => t.slug === slug));
|
|
74
|
+
const seenLogos = /* @__PURE__ */ new Set();
|
|
75
|
+
uniqueTechs = uniqueTechs.filter((t) => {
|
|
76
|
+
if (seenLogos.has(t.logo)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
seenLogos.add(t.logo);
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
const assetsDir = path.join(process.cwd(), "public", "assets", "logos");
|
|
83
|
+
if (options.copyAssets !== false) {
|
|
84
|
+
await copyAssets(uniqueTechs, assetsDir, { colorMode: options.color });
|
|
85
|
+
}
|
|
86
|
+
const techsWithUrls = uniqueTechs.map((t) => ({
|
|
87
|
+
...t,
|
|
88
|
+
logo: `https://raw.githubusercontent.com/benjamindotdev/stackscan/main/public/assets/logos/${t.logo}`,
|
|
89
|
+
relativePath: `./public/assets/logos/${t.logo}`
|
|
90
|
+
}));
|
|
91
|
+
allTechs.push(...techsWithUrls);
|
|
92
|
+
fs.writeFileSync(
|
|
93
|
+
path.join(projectPath, "stack.json"),
|
|
94
|
+
JSON.stringify(techsWithUrls, null, 2)
|
|
95
|
+
);
|
|
96
|
+
const mdContent = generateMarkdown(techsWithUrls);
|
|
97
|
+
fs.writeFileSync(path.join(projectPath, "stack.md"), mdContent);
|
|
98
|
+
allProjects.push({
|
|
99
|
+
name: dir.name,
|
|
100
|
+
techs: techsWithUrls
|
|
101
|
+
});
|
|
102
|
+
console.log(`\u2705 ${dir.name.padEnd(20)} -> stack.json (${uniqueTechs.length} techs)`);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.error(`\u274C Error processing ${dir.name}:`, err.message);
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
console.warn(`\u26A0\uFE0F Skipping "${dir.name}": No package.json found.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (allProjects.length > 0) {
|
|
111
|
+
updateRootReadme(allProjects);
|
|
112
|
+
}
|
|
113
|
+
console.log("\n\u2728 Sync complete.");
|
|
114
|
+
}
|
|
115
|
+
function updateRootReadme(projects) {
|
|
116
|
+
const readmePath = path.join(process.cwd(), "README.md");
|
|
117
|
+
if (!fs.existsSync(readmePath)) {
|
|
118
|
+
console.log("\u26A0\uFE0F No root README.md found to update.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
122
|
+
const startMarker = "<!-- STACKSYNC_START -->";
|
|
123
|
+
const endMarker = "<!-- STACKSYNC_END -->";
|
|
124
|
+
let newSection = `${startMarker}
|
|
125
|
+
## My Projects
|
|
126
|
+
|
|
127
|
+
`;
|
|
128
|
+
for (const p of projects) {
|
|
129
|
+
newSection += `### ${p.name}
|
|
130
|
+
`;
|
|
131
|
+
newSection += `<p>
|
|
132
|
+
`;
|
|
133
|
+
for (const t of p.techs) {
|
|
134
|
+
const src = t.relativePath || t.logo;
|
|
135
|
+
newSection += ` <img src="${src}" alt="${t.name}" height="25" style="margin-right: 10px;" />
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
newSection += `</p>
|
|
139
|
+
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
newSection += `${endMarker}`;
|
|
143
|
+
if (readmeContent.includes(startMarker) && readmeContent.includes(endMarker)) {
|
|
144
|
+
const regex = new RegExp(`${startMarker}[\\s\\S]*?${endMarker}`);
|
|
145
|
+
readmeContent = readmeContent.replace(regex, newSection);
|
|
146
|
+
console.log(`\u{1F4DD} Updated root README.md with ${projects.length} projects.`);
|
|
147
|
+
} else {
|
|
148
|
+
readmeContent += `
|
|
149
|
+
|
|
150
|
+
${newSection}`;
|
|
151
|
+
console.log(`\u{1F4DD} Appended projects to root README.md.`);
|
|
152
|
+
}
|
|
153
|
+
fs.writeFileSync(readmePath, readmeContent);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
sync
|
|
158
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -5571,7 +5571,7 @@ function generateMarkdown(techs, assetsPath, availableLogos) {
|
|
|
5571
5571
|
}
|
|
5572
5572
|
|
|
5573
5573
|
// src/scan.ts
|
|
5574
|
-
var BASE_DIR = import_path2.default.join(process.cwd(), "stackscan");
|
|
5574
|
+
var BASE_DIR = import_path2.default.join(process.cwd(), "public", "stackscan");
|
|
5575
5575
|
var SKIPPED_TECHS = [
|
|
5576
5576
|
"react-dom"
|
|
5577
5577
|
];
|
|
@@ -5583,13 +5583,13 @@ async function scan(options = {}) {
|
|
|
5583
5583
|
if (!import_fs.default.existsSync(BASE_DIR)) {
|
|
5584
5584
|
console.log(`Creating stackscan directory at: ${BASE_DIR}`);
|
|
5585
5585
|
import_fs.default.mkdirSync(BASE_DIR, { recursive: true });
|
|
5586
|
-
console.log('Please place your project folders inside "stackscan/" and run this command again.');
|
|
5586
|
+
console.log('Please place your project folders inside "public/stackscan/" and run this command again.');
|
|
5587
5587
|
process.exit(0);
|
|
5588
5588
|
}
|
|
5589
5589
|
const entries = import_fs.default.readdirSync(BASE_DIR, { withFileTypes: true });
|
|
5590
5590
|
const projectDirs = entries.filter((dirent) => dirent.isDirectory() && dirent.name !== "input" && dirent.name !== "output");
|
|
5591
5591
|
if (projectDirs.length === 0) {
|
|
5592
|
-
console.log('\u26A0\uFE0F No project directories found in "stackscan/".');
|
|
5592
|
+
console.log('\u26A0\uFE0F No project directories found in "public/stackscan/".');
|
|
5593
5593
|
return;
|
|
5594
5594
|
}
|
|
5595
5595
|
console.log(`Found ${projectDirs.length} projects to process.
|
|
@@ -5716,7 +5716,7 @@ ${newSection}`;
|
|
|
5716
5716
|
var import_fs_extra2 = __toESM(require("fs-extra"));
|
|
5717
5717
|
var import_path3 = __toESM(require("path"));
|
|
5718
5718
|
var import_chalk2 = __toESM(require("chalk"));
|
|
5719
|
-
var BASE_DIR2 = import_path3.default.join(process.cwd(), "stackscan");
|
|
5719
|
+
var BASE_DIR2 = import_path3.default.join(process.cwd(), "public", "stackscan");
|
|
5720
5720
|
async function add(sourcePath) {
|
|
5721
5721
|
let absoluteSourcePath = import_path3.default.resolve(sourcePath);
|
|
5722
5722
|
if (!import_fs_extra2.default.existsSync(absoluteSourcePath)) {
|
|
@@ -5751,7 +5751,7 @@ async function add(sourcePath) {
|
|
|
5751
5751
|
import_fs_extra2.default.mkdirSync(targetDir, { recursive: true });
|
|
5752
5752
|
}
|
|
5753
5753
|
import_fs_extra2.default.copyFileSync(absoluteSourcePath, targetFile);
|
|
5754
|
-
console.log(import_chalk2.default.green(`\u2705 Added project "${pkg.name}" to stackscan/${folderName}`));
|
|
5754
|
+
console.log(import_chalk2.default.green(`\u2705 Added project "${pkg.name}" to public/stackscan/${folderName}`));
|
|
5755
5755
|
} catch (error) {
|
|
5756
5756
|
console.error(import_chalk2.default.red(`\u274C Error processing ${sourcePath}:`), error);
|
|
5757
5757
|
process.exit(1);
|
|
@@ -5761,10 +5761,10 @@ async function add(sourcePath) {
|
|
|
5761
5761
|
// src/cli.ts
|
|
5762
5762
|
var program = new import_commander.Command();
|
|
5763
5763
|
program.name("stackscan").description("Auto-detect tech stacks and generate tech.json or markdown.").version("0.1.0");
|
|
5764
|
-
program.command("scan", { isDefault: true }).description("Scan stacks from multiple projects in stackscan/").option("--color <mode>", "Color mode (brand, white, black, or hex)", "brand").action(async (options) => {
|
|
5764
|
+
program.command("scan", { isDefault: true }).description("Scan stacks from multiple projects in public/stackscan/").option("--color <mode>", "Color mode (brand, white, black, or hex)", "brand").action(async (options) => {
|
|
5765
5765
|
await scan(options);
|
|
5766
5766
|
});
|
|
5767
|
-
program.command("add <path>").description("Add a project (folder or package.json) to the stackscan workspace").action(async (path4) => {
|
|
5767
|
+
program.command("add <path>").description("Add a project (folder or package.json) to the public/stackscan workspace").action(async (path4) => {
|
|
5768
5768
|
await add(path4);
|
|
5769
5769
|
});
|
|
5770
5770
|
program.parse();
|
package/dist/cli.mjs
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
add
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ACCTMJVS.mjs";
|
|
5
5
|
import {
|
|
6
6
|
scan
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DYBWKLM7.mjs";
|
|
8
8
|
import "./chunk-LSUI3VI4.mjs";
|
|
9
|
-
import "./chunk-ZH22D4SN.mjs";
|
|
10
|
-
import "./chunk-NGEKE4DQ.mjs";
|
|
11
|
-
import "./chunk-EH2SEQZP.mjs";
|
|
12
9
|
import "./chunk-LB3L25FS.mjs";
|
|
10
|
+
import "./chunk-UJM3S22V.mjs";
|
|
11
|
+
import "./chunk-NGEKE4DQ.mjs";
|
|
13
12
|
import "./chunk-EOKQCSHI.mjs";
|
|
13
|
+
import "./chunk-EH2SEQZP.mjs";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
16
16
|
import { Command } from "commander";
|
|
17
17
|
var program = new Command();
|
|
18
18
|
program.name("stackscan").description("Auto-detect tech stacks and generate tech.json or markdown.").version("0.1.0");
|
|
19
|
-
program.command("scan", { isDefault: true }).description("Scan stacks from multiple projects in stackscan/").option("--color <mode>", "Color mode (brand, white, black, or hex)", "brand").action(async (options) => {
|
|
19
|
+
program.command("scan", { isDefault: true }).description("Scan stacks from multiple projects in public/stackscan/").option("--color <mode>", "Color mode (brand, white, black, or hex)", "brand").action(async (options) => {
|
|
20
20
|
await scan(options);
|
|
21
21
|
});
|
|
22
|
-
program.command("add <path>").description("Add a project (folder or package.json) to the stackscan workspace").action(async (path) => {
|
|
22
|
+
program.command("add <path>").description("Add a project (folder or package.json) to the public/stackscan workspace").action(async (path) => {
|
|
23
23
|
await add(path);
|
|
24
24
|
});
|
|
25
25
|
program.parse();
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { add } from './add.mjs';
|
|
2
|
+
export { DEFAULT_CATEGORY_ICONS } from './defaults.mjs';
|
|
3
|
+
export { copyAssets, generateMarkdown, writeOutput } from './output.mjs';
|
|
4
|
+
export { scan } from './scan.mjs';
|
|
5
|
+
export { sync } from './sync.mjs';
|
|
6
|
+
export { techDefinitions } from './techDefinitions.mjs';
|
|
7
|
+
export { techMap } from './techMap.mjs';
|
|
8
|
+
export { DetectorResult, StackSyncConfig, TechDefinition } from './types.mjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { add } from './add.js';
|
|
2
|
+
export { DEFAULT_CATEGORY_ICONS } from './defaults.js';
|
|
3
|
+
export { copyAssets, generateMarkdown, writeOutput } from './output.js';
|
|
4
|
+
export { scan } from './scan.js';
|
|
5
|
+
export { sync } from './sync.js';
|
|
6
|
+
export { techDefinitions } from './techDefinitions.js';
|
|
7
|
+
export { techMap } from './techMap.js';
|
|
8
|
+
export { DetectorResult, StackSyncConfig, TechDefinition } from './types.js';
|