pkg-scaffold 1.0.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.
Files changed (3) hide show
  1. package/README.md +27 -0
  2. package/index.js +538 -0
  3. package/package.json +25 -0
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # pkg-scaffold
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/pkg-scaffold.svg?style=flat&color=brightgreen)](https://www.npmjs.com/package/pkg-scaffold)
4
+ [![License](https://img.shields.io/npm/l/pkg-scaffold.svg?style=flat&color=blue)](https://www.npmjs.com/package/pkg-scaffold)
5
+ [![NPM Downloads](https://img.shields.io/npm/dm/pkg-scaffold.svg?style=flat&color=blueviolet)](https://www.npmjs.com/package/pkg-scaffold)
6
+
7
+ `pkg-scaffold` is a zero-config, intelligent **Workspace Genesis Engine**. Instead of forcing you to configure infrastructure *before* writing code, it crawls your raw scratchpads or prototypes, diagnoses the ecosystem, automatically generates structural runtime configurations, repairs unimported statements, provisions legal licenses from remote registries, and runs deep compatibility audits.
8
+
9
+ ---
10
+
11
+ ## šŸš€ Core Features
12
+
13
+ * **Reverse Workspace Generation:** Analyzes your raw source files (`.js`, `.ts`, `.jsx`, `.tsx`) to instantly construct a tailored, valid `package.json`.
14
+ * **Phantom Dependency Remediation:** Detects modules used in code paths (like `fs.` or `axios.`) that were never explicitly imported, and automatically injects the proper `import` or `require` headers.
15
+ * **On-Demand Legal Provisioning:** Connects directly to the GitHub Licenses API to dynamically download, year-stamp, and author-sign standard licenses (`MIT`, `Apache-2.0`, `GPL-3.0`).
16
+ * **Adaptive Code Mirroring:** Learns your codebase formatting preferences (tabs vs. spaces, semicolon termination configurations) and outputs matching `.prettierrc` manifests.
17
+ * **Ecosystem-Aware Setup:** Automatically drops clean `.gitignore` files, standard `tsconfig.json` foundations if TypeScript dominates, and maps test parameters cleanly.
18
+ * **Integrated Deprecation Guard:** Runs an isolated local layer audit to intercept obsolete, abandoned, or heavily bloated imports.
19
+
20
+ ---
21
+
22
+ ## šŸ“¦ Installation & Immediate Usage
23
+
24
+ You do not even need to install it locally to weaponize a folder. Simply open your terminal in any directory of raw source code files and run:
25
+
26
+ ```bash
27
+ npx pkg-scaffold
package/index.js ADDED
@@ -0,0 +1,538 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { builtinModules, createRequire } from 'module';
6
+ import { execSync } from 'child_process';
7
+ import readline from 'readline/promises';
8
+
9
+ const IGNORED_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.turbo', 'coverage', 'out']);
10
+ const VALID_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']);
11
+
12
+ // --- High Performance Structural Analysis Engine ---
13
+ const REGEX_PATTERNS = {
14
+ imports: /import\s+(?:[\w\s{},*]*\s+from\s+)?['"]([^'"]+)['"]/g,
15
+ cjs: /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
16
+ dynamic: /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
17
+ exports: /export\s+(?:[\w\s{},*]*\s+from\s+)?['"]([^'"]+)['"]/g,
18
+ env: /(?:process\.env|import\.meta\.env)\.([A-Z_][A-Z0-9_]*)/g,
19
+ testFile: /\.(test|spec)\.(js|ts|jsx|tsx)$/i,
20
+
21
+ // Quality & Code Smell Checks
22
+ legacyVar: /\bvar\s+[a-zA-Z_]/g,
23
+ dangerousEval: /\beval\s*\(/g,
24
+ syncFsCalls: /\.readFileSync|\.writeFileSync|\.mkdirSync|\.existsSync/g,
25
+ objAccessor: /\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\./g
26
+ };
27
+
28
+ const COMMON_EXTERNAL_TOKENS = new Set(['axios', 'lodash', 'dotenv', 'cors', 'zod', 'mongoose', 'jsonwebtoken', 'chalk', 'helmet', 'prisma', 'redis', 'pg']);
29
+
30
+ function getGitIdentity() {
31
+ const identity = { name: "Developer", author: "", repository: "" };
32
+ try {
33
+ const name = execSync('git config user.name', { encoding: 'utf8', stdio: 'pipe' }).trim();
34
+ const email = execSync('git config user.email', { encoding: 'utf8', stdio: 'pipe' }).trim();
35
+ if (name) {
36
+ identity.name = name;
37
+ identity.author = `${name}${email ? ` <${email}>` : ''}`;
38
+ }
39
+
40
+ const url = execSync('git config --get remote.origin.url', { encoding: 'utf8', stdio: 'pipe' }).trim();
41
+ if (url) identity.repository = url.replace(/\.git$/, '');
42
+ } catch (e) {}
43
+ return identity;
44
+ }
45
+
46
+ function detectPackageManager(targetDir) {
47
+ if (fs.existsSync(path.join(targetDir, 'pnpm-lock.yaml'))) return 'pnpm';
48
+ if (fs.existsSync(path.join(targetDir, 'yarn.lock'))) return 'yarn';
49
+ if (fs.existsSync(path.join(targetDir, 'package-lock.json'))) return 'npm';
50
+
51
+ try { execSync('pnpm --version', { stdio: 'ignore' }); return 'pnpm'; } catch {}
52
+ try { execSync('yarn --version', { stdio: 'ignore' }); return 'yarn'; } catch {}
53
+ return 'npm';
54
+ }
55
+
56
+ function analyzeCodeStyle(content, stats) {
57
+ const lines = content.split('\n');
58
+ for (const line of lines) {
59
+ const trimmed = line.trim();
60
+ if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) continue;
61
+
62
+ if (trimmed.endsWith(';')) stats.style.semiCount++;
63
+ else if (!/[{}:,\[\]]/.test(trimmed.slice(-1))) stats.style.noSemiCount++;
64
+
65
+ if (line.startsWith('\t')) stats.style.tabCount++;
66
+ else if (line.startsWith(' ')) {
67
+ const spaces = line.match(/^(\s+)/)?.[1]?.length || 0;
68
+ if (spaces === 2) stats.style.space2Count++;
69
+ if (spaces === 4) stats.style.space4Count++;
70
+ }
71
+ }
72
+
73
+ if (REGEX_PATTERNS.legacyVar.test(content)) stats.quality.varCount += (content.match(REGEX_PATTERNS.legacyVar) || []).length;
74
+ if (REGEX_PATTERNS.dangerousEval.test(content)) stats.quality.hasEval = true;
75
+ if (REGEX_PATTERNS.syncFsCalls.test(content)) stats.quality.syncFsCount += (content.match(REGEX_PATTERNS.syncFsCalls) || []).length;
76
+ }
77
+
78
+ function cleanPackageName(importString) {
79
+ if (!importString || /^[./~\\]/.test(importString)) return null;
80
+ if (importString.startsWith('@')) return importString.split('/').slice(0, 2).join('/');
81
+ return importString.split('/')[0];
82
+ }
83
+
84
+ async function inspectNpmPackage(pkgName) {
85
+ try {
86
+ const response = await fetch(`https://registry.npmjs.org/${pkgName}/latest`, {
87
+ headers: { 'User-Agent': 'pkg-scaffold-dx-client/2.7' },
88
+ signal: AbortSignal.timeout(4000)
89
+ });
90
+ if (response.status === 200) {
91
+ const data = await response.json();
92
+ return { version: data.version, error: null };
93
+ }
94
+ if (response.status === 404) return { version: null, error: 'NOT_FOUND' };
95
+ } catch (e) {
96
+ return { version: 'latest', error: 'NETWORK_FAIL' };
97
+ }
98
+ return null;
99
+ }
100
+
101
+ async function fetchRemoteLicense(licenseKey) {
102
+ try {
103
+ const response = await fetch(`https://api.github.com/licenses/${licenseKey.toLowerCase()}`, {
104
+ headers: { 'User-Agent': 'pkg-scaffold-dx-client/2.7' },
105
+ signal: AbortSignal.timeout(5000)
106
+ });
107
+ if (response.status === 200) {
108
+ const data = await response.json();
109
+ return data.body;
110
+ }
111
+ } catch (e) {}
112
+ return null;
113
+ }
114
+
115
+ function readFileSyncNormalized(fullPath) {
116
+ const buffer = fs.readFileSync(fullPath);
117
+ if (buffer[0] === 0xFF && buffer[1] === 0xFE) return buffer.toString('utf16le');
118
+ if (buffer[0] === 0xFE && buffer[1] === 0xFF) return buffer.toString('utf16be');
119
+ return buffer.toString('utf8');
120
+ }
121
+
122
+ function scanWorkspace(dir, stats) {
123
+ const files = fs.readdirSync(dir);
124
+
125
+ for (const file of files) {
126
+ const fullPath = path.join(dir, file);
127
+ const stat = fs.statSync(fullPath);
128
+
129
+ if (stat.isDirectory()) {
130
+ if (!IGNORED_DIRS.has(file) && !file.startsWith('.')) scanWorkspace(fullPath, stats);
131
+ } else {
132
+ const ext = path.extname(file);
133
+
134
+ if (file === 'index.html' || file.startsWith('vite.config.')) stats.hasHtml = true;
135
+ if (REGEX_PATTERNS.testFile.test(file)) stats.hasTests = true;
136
+ if (ext === '.ts' || ext === '.tsx') stats.tsFiles++;
137
+ if (ext === '.js' || ext === '.jsx' || ext === '.mjs') stats.jsFiles++;
138
+
139
+ if (VALID_EXTENSIONS.has(ext)) {
140
+ const content = readFileSyncNormalized(fullPath);
141
+ if (content.includes('import ') || content.includes('export ')) stats.usesEsm = true;
142
+
143
+ analyzeCodeStyle(content, stats);
144
+
145
+ const explicitlyImported = new Set();
146
+ let match;
147
+
148
+ for (const key of ['imports', 'cjs', 'dynamic', 'exports']) {
149
+ REGEX_PATTERNS[key].lastIndex = 0;
150
+ while ((match = REGEX_PATTERNS[key].exec(content)) !== null) {
151
+ const cleaned = cleanPackageName(match[1]);
152
+ if (cleaned && !builtinModules.includes(cleaned)) stats.rawDeps.add(cleaned);
153
+ if (cleaned) explicitlyImported.add(cleaned);
154
+ }
155
+ }
156
+
157
+ const usedTokens = new Set();
158
+ REGEX_PATTERNS.objAccessor.lastIndex = 0;
159
+ while ((match = REGEX_PATTERNS.objAccessor.exec(content)) !== null) {
160
+ usedTokens.add(match[1]);
161
+ }
162
+
163
+ for (const token of usedTokens) {
164
+ if (!explicitlyImported.has(token)) {
165
+ const isCoreBuiltin = builtinModules.includes(token);
166
+ const isKnownExternal = COMMON_EXTERNAL_TOKENS.has(token);
167
+
168
+ if (isCoreBuiltin || isKnownExternal) {
169
+ if (isKnownExternal) stats.rawDeps.add(token);
170
+ if (!stats.phantomInjections.has(fullPath)) stats.phantomInjections.set(fullPath, new Set());
171
+ stats.phantomInjections.get(fullPath).add(token);
172
+ }
173
+ }
174
+ }
175
+
176
+ REGEX_PATTERNS.env.lastIndex = 0;
177
+ while ((match = REGEX_PATTERNS.env.exec(content)) !== null) stats.envVars.add(match[1]);
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ function buildAsciiTree(dir, prefix = '') {
184
+ let treeLines = [];
185
+ try {
186
+ const files = fs.readdirSync(dir).filter(f => !IGNORED_DIRS.has(f) && !f.startsWith('.'));
187
+ files.forEach((file, idx) => {
188
+ const isLast = idx === files.length - 1;
189
+ const fullPath = path.join(dir, file);
190
+ const stat = fs.statSync(fullPath);
191
+
192
+ treeLines.push(`${prefix}${isLast ? '└── ' : 'ā”œā”€ā”€ '}${file}`);
193
+ if (stat.isDirectory()) {
194
+ treeLines = treeLines.concat(buildAsciiTree(fullPath, prefix + (isLast ? ' ' : '│ ')));
195
+ }
196
+ });
197
+ } catch (e) {}
198
+ return treeLines;
199
+ }
200
+
201
+ async function main() {
202
+ const targetDir = process.cwd();
203
+ const folderName = path.basename(targetDir);
204
+ const gitInfo = getGitIdentity();
205
+ const activePkgManager = detectPackageManager(targetDir);
206
+ const pkgPath = path.join(targetDir, 'package.json');
207
+ let preExistingLicense = null;
208
+
209
+ console.log(`\n===================================================================`);
210
+ console.log(`šŸš€ pkg-scaffold v2.7: Deep Intelligence Workspace Diagnostic Run`);
211
+ console.log(`===================================================================\n`);
212
+
213
+ // --- Package.json Pre-existing Interceptor Subsystem ---
214
+ if (fs.existsSync(pkgPath)) {
215
+ console.log(`āš ļø An existing package.json was found in this working directory.`);
216
+ console.log(`šŸ“” Analyzing existing installation arrays for invalid metrics...`);
217
+ try {
218
+ const existingData = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
219
+
220
+ // Capture license choice from the pre-existing package definition profile
221
+ if (existingData.license && typeof existingData.license === 'string' && existingData.license.toLowerCase() !== 'none') {
222
+ preExistingLicense = existingData.license;
223
+ }
224
+
225
+ const combinedDeps = Object.keys({ ...existingData.dependencies, ...existingData.devDependencies });
226
+ let brokenEcosystem = combinedDeps.length === 0;
227
+
228
+ for (const dep of combinedDeps) {
229
+ const check = await inspectNpmPackage(dep);
230
+ if (check && check.error === 'NOT_FOUND') {
231
+ brokenEcosystem = true;
232
+ console.log(` āŒ Identified non-existent package on registry tracks: "${dep}"`);
233
+ }
234
+ }
235
+
236
+ if (brokenEcosystem) {
237
+ console.log(`\nšŸ›‘ CRITICAL COMPLIANCE BREAK: Your current package.json is empty or contains non-existent packages.`);
238
+ console.log(`šŸ‘‰ Action Required: Please remove or backup the existing 'package.json' from this folder.`);
239
+ console.log(` Once removed, re-run 'pkg-scaffold' to synthesize a verified configuration profile.\n`);
240
+ return;
241
+ } else {
242
+ console.log(` ā„¹ļø Existing package.json appears structurally sound. Skipping generation arrays to prevent asset loss.`);
243
+ }
244
+ } catch (err) {
245
+ console.log(`\nšŸ›‘ CRITICAL: Existing package.json is malformed or corrupt.`);
246
+ console.log(`šŸ‘‰ Action Required: Please remove it from the workspace so pkg-scaffold can compile a clean matrix.\n`);
247
+ return;
248
+ }
249
+ }
250
+
251
+ const stats = {
252
+ tsFiles: 0, jsFiles: 0, usesEsm: false, hasHtml: false, hasTests: false,
253
+ rawDeps: new Set(), envVars: new Set(),
254
+ style: { semiCount: 0, noSemiCount: 0, tabCount: 0, space2Count: 0, space4Count: 0 },
255
+ quality: { varCount: 0, hasEval: false, syncFsCount: 0 },
256
+ phantomInjections: new Map()
257
+ };
258
+
259
+ scanWorkspace(targetDir, stats);
260
+
261
+ const isTypeScript = stats.tsFiles > stats.jsFiles;
262
+ const isFrontendWeb = stats.hasHtml || stats.rawDeps.has('react') || stats.rawDeps.has('vue') || stats.rawDeps.has('vite');
263
+
264
+ const packageJson = {
265
+ name: folderName.toLowerCase().replace(/[^a-z0-9-_]/g, '-'),
266
+ version: '1.0.0',
267
+ description: `Automated ${isFrontendWeb ? 'frontend layout application' : 'backend infrastructure runtime'}.`,
268
+ type: (stats.usesEsm || isTypeScript || isFrontendWeb) ? 'module' : 'commonjs',
269
+ author: gitInfo.author || undefined,
270
+ repository: gitInfo.repository ? { type: "git", url: `git+${gitInfo.repository}.git` } : undefined,
271
+ scripts: { test: stats.hasTests ? (isFrontendWeb ? 'vitest' : 'jest') : 'echo "No workspace test vectors specified" && exit 0' },
272
+ dependencies: {},
273
+ devDependencies: {}
274
+ };
275
+
276
+ if (isFrontendWeb) {
277
+ packageJson.scripts.dev = 'vite';
278
+ packageJson.scripts.build = 'vite build';
279
+ packageJson.scripts.preview = 'vite preview';
280
+ stats.rawDeps.add('vite');
281
+ if (stats.hasTests) stats.rawDeps.add('vitest');
282
+ } else {
283
+ if (isTypeScript) {
284
+ packageJson.scripts.build = 'tsc';
285
+ packageJson.scripts.start = 'node dist/index.js';
286
+ packageJson.scripts.dev = 'node --watch dist/index.js';
287
+ } else {
288
+ packageJson.scripts.start = 'node index.js';
289
+ }
290
+ }
291
+
292
+ if (isTypeScript) {
293
+ packageJson.devDependencies.typescript = '^5.4.0';
294
+ if (!isFrontendWeb) packageJson.devDependencies['@types/node'] = '^20.11.0';
295
+ }
296
+
297
+ if (stats.rawDeps.size > 0) {
298
+ console.log(`šŸ“” Resolving baseline package registry definitions...`);
299
+ for (const pkg of stats.rawDeps) {
300
+ const cleaned = cleanPackageName(pkg);
301
+ if (cleaned && !builtinModules.includes(cleaned)) {
302
+ const check = await inspectNpmPackage(cleaned);
303
+ if (check && check.error !== 'NOT_FOUND') {
304
+ const version = check.version || 'latest';
305
+ const devRegistry = ['vite', 'vitest', 'typescript', 'eslint', 'prettier', 'jest'];
306
+ if (devRegistry.includes(cleaned)) {
307
+ packageJson.devDependencies[cleaned] = `^${version}`;
308
+ } else {
309
+ packageJson.dependencies[cleaned] = `^${version}`;
310
+ }
311
+ console.log(` āœ… Synced verified package parameters: ${cleaned}@^${version}`);
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ if (stats.phantomInjections.size > 0) {
318
+ console.log(`\nšŸ‘» PHANTOM STRUCTURE ALERT: UNIMPORTED EXECUTIONS DETECTED`);
319
+ console.log(`───────────────────────────────────────────────────────────────────`);
320
+ for (const [filePath, missingModules] of stats.phantomInjections.entries()) {
321
+ console.log(`šŸ“‚ File: ${path.relative(targetDir, filePath)}`);
322
+ console.log(` āŒ Used but never imported: ${Array.from(missingModules).map(m => `"${m}"`).join(', ')}`);
323
+ }
324
+ console.log(`───────────────────────────────────────────────────────────────────`);
325
+ }
326
+
327
+ if (stats.quality.varCount > 0 || stats.quality.hasEval || stats.quality.syncFsCount > 0) {
328
+ console.log(`\nāš ļø CODE ARCHITECTURE & MODERNIZATION COMPLIANCE WARNINGS:`);
329
+ console.log(`───────────────────────────────────────────────────────────────────`);
330
+ if (stats.quality.varCount > 0) console.log(` ⚔ Found ${stats.quality.varCount} instances of legacy 'var' statements. Transition to blocks ('let' / 'const').`);
331
+ if (stats.quality.hasEval) console.log(` šŸ”„ DANGER: 'eval()' invocation structures detected! Refactor to mitigate critical remote code execution vectors.`);
332
+ if (stats.quality.syncFsCount > 0) console.log(` šŸ“‰ Performance Alert: Found ${stats.quality.syncFsCount} block-level Sync filesystem configurations inside threads. Transition to promises ('fs/promises').`);
333
+ console.log(`───────────────────────────────────────────────────────────────────`);
334
+ }
335
+
336
+ // ─── INTERACTIVE ON-DEMAND REMOTE LICENSE PROVISIONER ───────────────────
337
+ const licensePath = path.join(targetDir, 'LICENSE');
338
+ let chosenLicenseType = preExistingLicense || 'None';
339
+
340
+ if (!fs.existsSync(licensePath) && !preExistingLicense) {
341
+ console.log(`\nāš–ļø Legal Compliance Auditor: No LICENSE file or package.json license descriptor located.`);
342
+ const rlLicense = readline.createInterface({ input: process.stdin, output: process.stdout });
343
+ const licInput = await rlLicense.question(`ā“ Select an Open Source License to pull from registry (mit / apache-2.0 / gpl-3.0 / skip): `);
344
+ rlLicense.close();
345
+
346
+ const cleanedInput = licInput.trim().toLowerCase();
347
+ if (['mit', 'apache-2.0', 'gpl-3.0'].includes(cleanedInput)) {
348
+ console.log(` šŸ“” Querying GitHub Legal Databases for "${cleanedInput.toUpperCase()}" template...`);
349
+ const rawTemplate = await fetchRemoteLicense(cleanedInput);
350
+
351
+ if (rawTemplate) {
352
+ const parsedText = rawTemplate
353
+ .replace(/\[year\]|<year>/gi, '2026')
354
+ .replace(/\[fullname\]|\[name of copyright owner\]|<copyright holders>|<name of author>/gi, gitInfo.name);
355
+
356
+ fs.writeFileSync(licensePath, parsedText);
357
+ chosenLicenseType = cleanedInput.toUpperCase();
358
+ packageJson.license = cleanedInput.toUpperCase();
359
+ console.log(` āš–ļø Successfully provisioned, stamped, and generated legal asset: LICENSE`);
360
+ } else {
361
+ console.log(` āŒ Connection boundary dropped. Skipping live license file provisioning.`);
362
+ }
363
+ }
364
+ } else {
365
+ // Skip prompt routing because metadata parameter indicators exist
366
+ if (preExistingLicense) {
367
+ console.log(`\nāš–ļø Legal Compliance Auditor: License "${preExistingLicense}" detected in package.json. Skipping interactive step.`);
368
+ chosenLicenseType = preExistingLicense;
369
+
370
+ // Auto-provisioning loop if the descriptor is preset but the physical asset is absent
371
+ if (!fs.existsSync(licensePath) && ['mit', 'apache-2.0', 'gpl-3.0'].includes(preExistingLicense.toLowerCase())) {
372
+ console.log(` šŸ“” Auto-provisioning missing physical LICENSE layer text files for "${preExistingLicense.toUpperCase()}"...`);
373
+ const rawTemplate = await fetchRemoteLicense(preExistingLicense);
374
+ if (rawTemplate) {
375
+ const parsedText = rawTemplate
376
+ .replace(/\[year\]|<year>/gi, '2026')
377
+ .replace(/\[fullname\]|\[name of copyright owner\]|<copyright holders>|<name of author>/gi, gitInfo.name);
378
+ fs.writeFileSync(licensePath, parsedText);
379
+ console.log(` āš–ļø Successfully mirrored and synthesized missing license file artifacts.`);
380
+ }
381
+ }
382
+ } else if (fs.existsSync(licensePath)) {
383
+ console.log(`\nāš–ļø Legal Compliance Auditor: Existing physical LICENSE file detected. Skipping interactive step.`);
384
+ try {
385
+ const currentLicenseContent = fs.readFileSync(licensePath, 'utf8');
386
+ if (currentLicenseContent.includes('MIT')) chosenLicenseType = 'MIT';
387
+ else if (currentLicenseContent.includes('Apache')) chosenLicenseType = 'Apache-2.0';
388
+ else chosenLicenseType = 'Custom';
389
+ } catch(e) {}
390
+ }
391
+ packageJson.license = chosenLicenseType;
392
+ }
393
+
394
+ console.log(`\nāš™ļø Writing ecosystem configuration artifacts...`);
395
+
396
+ if (!fs.existsSync(pkgPath)) {
397
+ fs.writeFileSync(pkgPath, JSON.stringify(packageJson, null, 2));
398
+ console.log(` šŸ“ Injected: package.json`);
399
+ }
400
+
401
+ const prettierPath = path.join(targetDir, '.prettierrc');
402
+ if (!fs.existsSync(prettierPath)) {
403
+ const useTabs = stats.style.tabCount > (stats.style.space2Count + stats.style.space4Count);
404
+ const useSemi = stats.style.semiCount >= stats.style.noSemiCount;
405
+ const tabWidth = stats.style.space4Count > stats.style.space2Count ? 4 : 2;
406
+ fs.writeFileSync(prettierPath, JSON.stringify({ semi: useSemi, useTabs: useTabs, tabWidth: tabWidth, singleQuote: true, trailingComma: "es5" }, null, 2));
407
+ console.log(` šŸŽØ Code formatting mirror locked: .prettierrc`);
408
+ }
409
+
410
+ if (stats.envVars.size > 0) {
411
+ const envExamplePath = path.join(targetDir, '.env.example');
412
+ if (!fs.existsSync(envExamplePath)) {
413
+ fs.writeFileSync(envExamplePath, Array.from(stats.envVars).map(v => `${v}=`).join('\n') + '\n');
414
+ console.log(` šŸ”’ Extracted environmental configurations: .env.example`);
415
+ }
416
+ }
417
+
418
+ const gitignorePath = path.join(targetDir, '.gitignore');
419
+ if (!fs.existsSync(gitignorePath)) { fs.writeFileSync(gitignorePath, `node_modules/\ndist/\nbuild/\n.env\n.env.local\n.DS_Store\n`); console.log(` w Structural default configurations locked: .gitignore`); }
420
+
421
+ if (isTypeScript) {
422
+ const tsconfigPath = path.join(targetDir, 'tsconfig.json');
423
+ if (!fs.existsSync(tsconfigPath)) {
424
+ fs.writeFileSync(tsconfigPath, JSON.stringify({ compilerOptions: { target: "ES2022", module: "NodeNext", moduleResolution: "NodeNext", esModuleInterop: true, strict: true, skipLibCheck: true, outDir: "./dist" }, include: ["src/**/*", "**/*.ts"] }, null, 2));
425
+ console.log(` # Structural default configurations locked: tsconfig.json`);
426
+ }
427
+ }
428
+
429
+ // --- Adaptive Flat Shields.io README Layout ---
430
+ const readmePath = path.join(targetDir, 'README.md');
431
+ if (!fs.existsSync(readmePath)) {
432
+ const pName = packageJson.name;
433
+ const layoutTree = buildAsciiTree(targetDir).join('\n');
434
+
435
+ const displayDeps = Object.keys(packageJson.dependencies).map(d => `* \`${d}\``).join('\n') || '* None extracted';
436
+ const displayDevDeps = Object.keys(packageJson.devDependencies).map(d => `* \`${d}\``).join('\n') || '* None extracted';
437
+
438
+ const documentationTemplate =
439
+ `# ${pName}
440
+
441
+ [![NPM Version](https://img.shields.io/npm/v/${pName}.svg?style=flat)](https://www.npmjs.com/package/${pName})
442
+ [![License](https://img.shields.io/npm/l/${pName}.svg?style=flat)](https://www.npmjs.com/package/${pName})
443
+
444
+ ${packageJson.description}
445
+
446
+ ## Workspace Dependency Landscapes
447
+
448
+ ### Core Infrastructure Runtimes (\`dependencies\`)
449
+ ${displayDeps}
450
+
451
+ ### System Tooling Engines (\`devDependencies\`)
452
+ ${displayDevDeps}
453
+
454
+ ### Underlying Tooling Architecture
455
+ This project environment layout maps out core metadata elements dynamically using:
456
+ * \`npm-deprecated-check\` (Bundled internal core validation system for dependency deprecation checking routines)
457
+
458
+ ---
459
+
460
+ ## Project Architecture Layout
461
+ \`\`\`text
462
+ ${layoutTree}
463
+ \`\`\`
464
+
465
+ ## Installation & Launch Procedures
466
+ Initialize the workspace tracking structures via your active system package engine:
467
+
468
+ \`\`\`bash
469
+ ${activePkgManager} install
470
+ \`\`\`
471
+ `;
472
+ fs.writeFileSync(readmePath, documentationTemplate);
473
+ console.log(` šŸ“– Auto-generated system asset metrics: README.md`);
474
+ }
475
+
476
+ // --- Interactive Code Mutation Pipeline ---
477
+ if (stats.phantomInjections.size > 0) {
478
+ console.log(`\nšŸ’” Source Code Modification Subsystem:`);
479
+ const rlPhantom = readline.createInterface({ input: process.stdin, output: process.stdout });
480
+ const injectChoice = await rlPhantom.question(`ā“ Found unimported dependencies in code execution chains. Inject statements automatically? (y/N): `);
481
+ rlPhantom.close();
482
+
483
+ if (injectChoice.trim().toLowerCase() === 'y' || injectChoice.trim().toLowerCase() === 'yes') {
484
+ for (const [filePath, missingModules] of stats.phantomInjections.entries()) {
485
+ const originalCode = readFileSyncNormalized(filePath);
486
+ let declarationBlock = '';
487
+
488
+ for (const mod of missingModules) {
489
+ if (packageJson.type === 'module') {
490
+ declarationBlock += `import ${mod} from '${mod}';\n`;
491
+ } else {
492
+ declarationBlock += `const ${mod} = require('${mod}');\n`;
493
+ }
494
+ }
495
+ fs.writeFileSync(filePath, declarationBlock + originalCode);
496
+ console.log(` ⚔ Injected declarations into top header row: ${path.relative(targetDir, filePath)}`);
497
+ }
498
+ }
499
+ }
500
+
501
+ // --- Dynamic Self-Contained Local Auditing via npm-deprecated-check ---
502
+ console.log(`\nšŸ›‘ INITIALIZING LIVE ECOSYSTEM DEPRECATION SECURITY SCAN...`);
503
+ console.log(` Running integrated npm-deprecated-check validation algorithms:\n`);
504
+ try {
505
+ const localRequire = createRequire(import.meta.url);
506
+ const dependencyPkgJsonPath = localRequire.resolve('npm-deprecated-check/package.json');
507
+ const dependencyPkgJson = JSON.parse(fs.readFileSync(dependencyPkgJsonPath, 'utf8'));
508
+
509
+ const binRelativeMapping = typeof dependencyPkgJson.bin === 'string'
510
+ ? dependencyPkgJson.bin
511
+ : (dependencyPkgJson.bin['npm-deprecated-check'] || dependencyPkgJson.bin['ndc']);
512
+
513
+ const absoluteExecutablePath = path.join(path.dirname(dependencyPkgJsonPath), binRelativeMapping);
514
+ execSync(`node "${absoluteExecutablePath}" current`, { stdio: 'inherit', cwd: targetDir });
515
+ } catch (err) {}
516
+
517
+ // --- Automated Asset Installation Pipeline ---
518
+ console.log(`\nšŸ“¦ Auto-scaffolding pipeline complete!`);
519
+ const rlInstall = readline.createInterface({ input: process.stdin, output: process.stdout });
520
+ const userPromptChoice = await rlInstall.question(`ā“ Detected system default manager: "${activePkgManager}". Run "${activePkgManager} install" automatically now? (y/N): `);
521
+ rlInstall.close();
522
+
523
+ const normalizedAnswer = userPromptChoice.trim().toLowerCase();
524
+ if (normalizedAnswer === 'y' || normalizedAnswer === 'yes') {
525
+ console.log(`\nā³ Executing automated asset installations via background child processes...`);
526
+ try {
527
+ console.log(` Running: "${activePkgManager} install" inside current folder...`);
528
+ execSync(`${activePkgManager} install`, { stdio: 'inherit', cwd: targetDir });
529
+ console.log(`\nšŸŽ‰ Project fully mapped, configurations customized, and environments installed successfully!`);
530
+ } catch (err) {
531
+ console.error(`\nāŒ Automatic package extraction successful, but target installation shell returned an issue.`);
532
+ }
533
+ } else {
534
+ console.log(`\nā–¶ļø Skipping automated setup execution. Workspace configured! Run "${activePkgManager} install" manually whenever you're ready.`);
535
+ }
536
+ }
537
+
538
+ main();
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "pkg-scaffold",
3
+ "version": "1.0.0",
4
+ "description": "Zero-config workspace initializer that scans your source code, generates modern configuration layers, corrects missing imports, and automatically audits legacy dependencies.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "pkg-scaffold": "./index.js"
9
+ },
10
+ "keywords": [
11
+ "scaffold",
12
+ "init",
13
+ "package.json",
14
+ "setup",
15
+ "dx",
16
+ "cli",
17
+ "deprecated-check",
18
+ "automation"
19
+ ],
20
+ "author": "DreamLongYT",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "npm-deprecated-check": "^1.4.0"
24
+ }
25
+ }