pkg-scaffold 1.0.0 → 1.1.1

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 +1 -1
  2. package/index.js +523 -141
  3. package/package.json +6 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # pkg-scaffold
2
2
 
3
- [![NPM Version](https://img.shields.io/npm/v/pkg-scaffold.svg?style=flat&color=brightgreen)](https://www.npmjs.com/package/pkg-scaffold)
3
+ [![NPM Version](https://img.shields.io/npm/v/pkg-scaffold.svg?style=flat&color=brightgreen&label=version)](https://www.npmjs.com/package/pkg-scaffold)
4
4
  [![License](https://img.shields.io/npm/l/pkg-scaffold.svg?style=flat&color=blue)](https://www.npmjs.com/package/pkg-scaffold)
5
5
  [![NPM Downloads](https://img.shields.io/npm/dm/pkg-scaffold.svg?style=flat&color=blueviolet)](https://www.npmjs.com/package/pkg-scaffold)
6
6
 
package/index.js CHANGED
@@ -6,47 +6,55 @@ import { builtinModules, createRequire } from 'module';
6
6
  import { execSync } from 'child_process';
7
7
  import readline from 'readline/promises';
8
8
 
9
+ // --- Bulletproof AST Infrastructure Engines ---
10
+ import * as acorn from 'acorn';
11
+ import * as walk from 'acorn-walk';
12
+
9
13
  const IGNORED_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.turbo', 'coverage', 'out']);
10
14
  const VALID_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']);
11
15
 
12
- // --- High Performance Structural Analysis Engine ---
16
+ // --- Refined Target Signature Dictionaries ---
13
17
  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
18
  env: /(?:process\.env|import\.meta\.env)\.([A-Z_][A-Z0-9_]*)/g,
19
19
  testFile: /\.(test|spec)\.(js|ts|jsx|tsx)$/i,
20
20
 
21
- // Quality & Code Smell Checks
21
+ // Modern Quality & Structural Code Smell Monitors
22
22
  legacyVar: /\bvar\s+[a-zA-Z_]/g,
23
23
  dangerousEval: /\beval\s*\(/g,
24
24
  syncFsCalls: /\.readFileSync|\.writeFileSync|\.mkdirSync|\.existsSync/g,
25
- objAccessor: /\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\./g
25
+
26
+ // Cryptographic Risk & Hardcoded Keyholes
27
+ secretKeys: /\b(secret|passwd|password|token|api_?key|private_?key)\s*=\s*['"`]([a-zA-Z0-9_\-\.]{8,})['"`]/gi
26
28
  };
27
29
 
28
30
  const COMMON_EXTERNAL_TOKENS = new Set(['axios', 'lodash', 'dotenv', 'cors', 'zod', 'mongoose', 'jsonwebtoken', 'chalk', 'helmet', 'prisma', 'redis', 'pg']);
29
31
 
30
32
  function getGitIdentity() {
31
- const identity = { name: "Developer", author: "", repository: "" };
33
+ const identity = { name: "Developer", author: "Developer", repository: "" };
32
34
  try {
33
35
  const name = execSync('git config user.name', { encoding: 'utf8', stdio: 'pipe' }).trim();
34
36
  const email = execSync('git config user.email', { encoding: 'utf8', stdio: 'pipe' }).trim();
35
37
  if (name) {
36
38
  identity.name = name;
37
- identity.author = `${name}${email ? ` <${email}>` : ''}`;
39
+ identity.author = email ? `${name} <${email}>` : name;
38
40
  }
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
41
  } catch (e) {}
43
42
  return identity;
44
43
  }
45
44
 
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';
45
+ function detectPackageManager(targetDir, stats = null) {
46
+ const detectedLockfiles = [];
47
+ if (fs.existsSync(path.join(targetDir, 'pnpm-lock.yaml'))) detectedLockfiles.push('pnpm-lock.yaml');
48
+ if (fs.existsSync(path.join(targetDir, 'yarn.lock'))) detectedLockfiles.push('yarn.lock');
49
+ if (fs.existsSync(path.join(targetDir, 'package-lock.json'))) detectedLockfiles.push('package-lock.json');
50
+
51
+ if (detectedLockfiles.length > 1 && stats) {
52
+ stats.conflictingLockfiles = detectedLockfiles;
53
+ }
54
+
55
+ if (detectedLockfiles.includes('pnpm-lock.yaml')) return 'pnpm';
56
+ if (detectedLockfiles.includes('yarn.lock')) return 'yarn';
57
+ if (detectedLockfiles.includes('package-lock.json')) return 'npm';
50
58
 
51
59
  try { execSync('pnpm --version', { stdio: 'ignore' }); return 'pnpm'; } catch {}
52
60
  try { execSync('yarn --version', { stdio: 'ignore' }); return 'yarn'; } catch {}
@@ -81,10 +89,29 @@ function cleanPackageName(importString) {
81
89
  return importString.split('/')[0];
82
90
  }
83
91
 
92
+ function smartPrepend(originalCode, declarationBlock) {
93
+ const lines = originalCode.split(/\r?\n/);
94
+ let insertIdx = 0;
95
+
96
+ while (insertIdx < lines.length) {
97
+ const line = lines[insertIdx].trim();
98
+ if (line.startsWith('#!') || line === '"use strict";' || line === "'use strict';" || line === '`use strict`;') {
99
+ insertIdx++;
100
+ } else if (line === '') {
101
+ insertIdx++;
102
+ } else {
103
+ break;
104
+ }
105
+ }
106
+
107
+ lines.splice(insertIdx, 0, declarationBlock);
108
+ return lines.join('\n');
109
+ }
110
+
84
111
  async function inspectNpmPackage(pkgName) {
85
112
  try {
86
113
  const response = await fetch(`https://registry.npmjs.org/${pkgName}/latest`, {
87
- headers: { 'User-Agent': 'pkg-scaffold-dx-client/2.7' },
114
+ headers: { 'User-Agent': 'pkg-scaffold-dx-client/1.1' },
88
115
  signal: AbortSignal.timeout(4000)
89
116
  });
90
117
  if (response.status === 200) {
@@ -101,7 +128,7 @@ async function inspectNpmPackage(pkgName) {
101
128
  async function fetchRemoteLicense(licenseKey) {
102
129
  try {
103
130
  const response = await fetch(`https://api.github.com/licenses/${licenseKey.toLowerCase()}`, {
104
- headers: { 'User-Agent': 'pkg-scaffold-dx-client/2.7' },
131
+ headers: { 'User-Agent': 'pkg-scaffold-dx-client/1.1' },
105
132
  signal: AbortSignal.timeout(5000)
106
133
  });
107
134
  if (response.status === 200) {
@@ -115,11 +142,33 @@ async function fetchRemoteLicense(licenseKey) {
115
142
  function readFileSyncNormalized(fullPath) {
116
143
  const buffer = fs.readFileSync(fullPath);
117
144
  if (buffer[0] === 0xFF && buffer[1] === 0xFE) return buffer.toString('utf16le');
118
- if (buffer[0] === 0xFE && buffer[1] === 0xFF) return buffer.toString('utf16be');
145
+ if (buffer[0] === 0xFE && buffer[1] === 0xFF) return buffer.toString('utf8');
119
146
  return buffer.toString('utf8');
120
147
  }
121
148
 
122
- function scanWorkspace(dir, stats) {
149
+ function buildAsciiTree(dir, prefix = '') {
150
+ const results = [];
151
+ try {
152
+ const files = fs.readdirSync(dir);
153
+ const filtered = files.filter(f => !IGNORED_DIRS.has(f) && !f.startsWith('.'));
154
+
155
+ filtered.forEach((file, index) => {
156
+ const isLast = index === filtered.length - 1;
157
+ const marker = isLast ? '└── ' : 'ā”œā”€ā”€ ';
158
+ results.push(`${prefix}${marker}${file}`);
159
+
160
+ const fullPath = path.join(dir, file);
161
+ if (fs.statSync(fullPath).isDirectory()) {
162
+ const newPrefix = prefix + (isLast ? ' ' : '│ ');
163
+ results.push(...buildAsciiTree(fullPath, newPrefix));
164
+ }
165
+ });
166
+ } catch (e) {}
167
+ return results;
168
+ }
169
+
170
+ // --- High Performance AST Workspace Parsing Engine ---
171
+ function scanWorkspace(dir, stats, rootNamespace) {
123
172
  const files = fs.readdirSync(dir);
124
173
 
125
174
  for (const file of files) {
@@ -127,7 +176,7 @@ function scanWorkspace(dir, stats) {
127
176
  const stat = fs.statSync(fullPath);
128
177
 
129
178
  if (stat.isDirectory()) {
130
- if (!IGNORED_DIRS.has(file) && !file.startsWith('.')) scanWorkspace(fullPath, stats);
179
+ if (!IGNORED_DIRS.has(file) && !file.startsWith('.')) scanWorkspace(fullPath, stats, rootNamespace);
131
180
  } else {
132
181
  const ext = path.extname(file);
133
182
 
@@ -137,94 +186,267 @@ function scanWorkspace(dir, stats) {
137
186
  if (ext === '.js' || ext === '.jsx' || ext === '.mjs') stats.jsFiles++;
138
187
 
139
188
  if (VALID_EXTENSIONS.has(ext)) {
140
- const content = readFileSyncNormalized(fullPath);
141
- if (content.includes('import ') || content.includes('export ')) stats.usesEsm = true;
189
+ const rawContent = readFileSyncNormalized(fullPath);
190
+ const content = rawContent.replace(/[^\x09\x0A\x0D\x20-\x7E]/g, '');
142
191
 
192
+ const codeLines = content.split(/\r?\n/);
193
+ const importedIdentifiers = new Map();
194
+ const fileRawDeps = new Set();
195
+
143
196
  analyzeCodeStyle(content, stats);
144
197
 
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
- }
198
+ // Universal Cryptographic Leak Interception
199
+ REGEX_PATTERNS.secretKeys.lastIndex = 0;
200
+ let secretMatch;
201
+ while ((secretMatch = REGEX_PATTERNS.secretKeys.exec(content)) !== null) {
202
+ const keyName = secretMatch[1];
203
+ const secretValue = secretMatch[2];
204
+ const envVarName = `${rootNamespace.toUpperCase().replace(/[^A-Z0-9]/g, '_')}_${keyName.toUpperCase()}`;
205
+ stats.discoveredSecrets.push({ filePath: fullPath, keyName, secretValue, envVarName });
206
+ stats.envVars.add(envVarName);
207
+ }
208
+
209
+ // --- Global Regex Environmental Extraction Module ---
210
+ let fileHasEnv = false;
211
+ let envMatch;
212
+ REGEX_PATTERNS.env.lastIndex = 0;
213
+ while ((envMatch = REGEX_PATTERNS.env.exec(content)) !== null) {
214
+ stats.envVars.add(envMatch[1]);
215
+ fileHasEnv = true;
155
216
  }
217
+ if (fileHasEnv) {
218
+ stats.filesWithEnvVars.add(fullPath);
219
+ }
220
+
221
+ if (content.includes('import ') || content.includes('export ')) stats.usesEsm = true;
156
222
 
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]);
223
+ // --- Abstract Syntax Tree Engine Execution Block ---
224
+ let ast = null;
225
+ try {
226
+ ast = acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'module', allowHashBang: true });
227
+ } catch (e) {
228
+ try {
229
+ ast = acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'script', allowHashBang: true });
230
+ } catch (err) {}
161
231
  }
162
232
 
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);
233
+ if (ast) {
234
+ walk.simple(ast, {
235
+ ImportDeclaration(node) {
236
+ const pkg = cleanPackageName(node.source.value);
237
+ if (pkg && !builtinModules.includes(pkg)) {
238
+ fileRawDeps.add(pkg);
239
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
240
+ node.specifiers.forEach(spec => importedIdentifiers.get(pkg).add(spec.local.name));
241
+ }
242
+ },
243
+ VariableDeclarator(node) {
244
+ if (node.init && node.init.type === 'CallExpression' &&
245
+ node.init.callee.type === 'Identifier' && node.init.callee.name === 'require') {
246
+ const arg = node.init.arguments[0];
247
+ if (arg && arg.type === 'Literal' && typeof arg.value === 'string') {
248
+ const pkg = cleanPackageName(arg.value);
249
+ if (pkg && !builtinModules.includes(pkg)) {
250
+ fileRawDeps.add(pkg);
251
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
252
+
253
+ const extractBindings = (idNode) => {
254
+ if (idNode.type === 'Identifier') {
255
+ importedIdentifiers.get(pkg).add(idNode.name);
256
+ } else if (idNode.type === 'ObjectPattern') {
257
+ idNode.properties.forEach(p => {
258
+ if (p.value && p.value.type === 'Identifier') importedIdentifiers.get(pkg).add(p.value.name);
259
+ });
260
+ }
261
+ };
262
+ extractBindings(node.id);
263
+ }
264
+ }
265
+ }
266
+ },
267
+ ImportExpression(node) {
268
+ if (node.source.type === 'Literal' && typeof node.source.value === 'string') {
269
+ const pkg = cleanPackageName(node.source.value);
270
+ if (pkg && !builtinModules.includes(pkg)) fileRawDeps.add(pkg);
271
+ }
272
+ },
273
+ ExportNamedDeclaration(node) {
274
+ if (node.source && node.source.type === 'Literal' && typeof node.source.value === 'string') {
275
+ const pkg = cleanPackageName(node.source.value);
276
+ if (pkg && !builtinModules.includes(pkg)) fileRawDeps.add(pkg);
277
+ }
278
+ },
279
+ ExportAllDeclaration(node) {
280
+ if (node.source && node.source.type === 'Literal' && typeof node.source.value === 'string') {
281
+ const pkg = cleanPackageName(node.source.value);
282
+ if (pkg && !builtinModules.includes(pkg)) fileRawDeps.add(pkg);
283
+ }
284
+ }
285
+ });
286
+ } else {
287
+ // --- Text-Isolated Fallback Track (TypeScript/TSX Support Matrix) ---
288
+ for (const line of codeLines) {
289
+ let esmMatch = line.match(/\bimport\s+(?:\*+\s+as\s+)?([a-zA-Z0-9_]+)\s+from\s+['"]([^'"]+)['"]/);
290
+ if (esmMatch) {
291
+ const id = esmMatch[1];
292
+ const pkg = cleanPackageName(esmMatch[2]);
293
+ if (pkg && !builtinModules.includes(pkg)) {
294
+ fileRawDeps.add(pkg);
295
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
296
+ importedIdentifiers.get(pkg).add(id);
297
+ }
298
+ continue;
299
+ }
300
+
301
+ let esmNamedMatch = line.match(/\bimport\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/);
302
+ if (esmNamedMatch) {
303
+ const pkg = cleanPackageName(esmNamedMatch[2]);
304
+ if (pkg && !builtinModules.includes(pkg)) {
305
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
306
+ fileRawDeps.add(pkg);
307
+ esmNamedMatch[1].split(',').forEach(part => {
308
+ const chunk = part.trim();
309
+ if (!chunk) return;
310
+ const id = chunk.includes(' as ') ? chunk.split(' as ')[1].trim() : chunk;
311
+ importedIdentifiers.get(pkg).add(id);
312
+ });
313
+ }
314
+ continue;
315
+ }
167
316
 
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);
317
+ let cjsMatch = line.match(/\b(?:const|let|var)\s+([a-zA-Z0-9_]+)\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)/);
318
+ if (cjsMatch) {
319
+ const id = cjsMatch[1];
320
+ const pkg = cleanPackageName(cjsMatch[2]);
321
+ if (pkg && !builtinModules.includes(pkg)) {
322
+ fileRawDeps.add(pkg);
323
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
324
+ importedIdentifiers.get(pkg).add(id);
325
+ }
326
+ continue;
327
+ }
328
+
329
+ let cjsDestructMatch = line.match(/\b(?:const|let|var)\s*\{([^}]+)\}\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)/);
330
+ if (cjsDestructMatch) {
331
+ const pkg = cleanPackageName(cjsDestructMatch[2]);
332
+ if (pkg && !builtinModules.includes(pkg)) {
333
+ if (!importedIdentifiers.has(pkg)) importedIdentifiers.set(pkg, new Set());
334
+ fileRawDeps.add(pkg);
335
+ cjsDestructMatch[1].split(',').forEach(part => {
336
+ const chunk = part.trim();
337
+ if (!chunk) return;
338
+ const id = chunk.includes(':') ? chunk.split(':')[1].trim() : chunk;
339
+ importedIdentifiers.get(pkg).add(id);
340
+ });
341
+ }
342
+ continue;
172
343
  }
173
344
  }
174
345
  }
175
346
 
176
- REGEX_PATTERNS.env.lastIndex = 0;
177
- while ((match = REGEX_PATTERNS.env.exec(content)) !== null) stats.envVars.add(match[1]);
347
+ fileRawDeps.forEach(dep => stats.rawDeps.add(dep));
348
+
349
+ const functionalExecutionCodeOnly = codeLines
350
+ .filter(l => !/\bimport\b/.test(l) && !/\brequire\s*\(/.test(l))
351
+ .join('\n');
352
+
353
+ for (const [pkg, identifiers] of importedIdentifiers.entries()) {
354
+ let tokenReferenced = false;
355
+ for (const identifier of identifiers) {
356
+ const usagePattern = new RegExp(`\\b${identifier}\\b`);
357
+ if (usagePattern.test(functionalExecutionCodeOnly)) {
358
+ tokenReferenced = true;
359
+ break;
360
+ }
361
+ }
362
+ if (!tokenReferenced && identifiers.size > 0) {
363
+ stats.unusedDepsInCode.add(pkg);
364
+ }
365
+ }
366
+
367
+ COMMON_EXTERNAL_TOKENS.forEach(token => {
368
+ const tokenPattern = new RegExp(`\\b${token}\\b`);
369
+ if (tokenPattern.test(functionalExecutionCodeOnly) && !importedIdentifiers.has(token)) {
370
+ stats.rawDeps.add(token);
371
+ if (!stats.phantomInjections.has(fullPath)) stats.phantomInjections.set(fullPath, new Set());
372
+ stats.phantomInjections.get(fullPath).add(token);
373
+ }
374
+ });
178
375
  }
179
376
  }
180
377
  }
181
378
  }
182
379
 
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
380
  async function main() {
202
381
  const targetDir = process.cwd();
203
382
  const folderName = path.basename(targetDir);
204
383
  const gitInfo = getGitIdentity();
205
- const activePkgManager = detectPackageManager(targetDir);
384
+
385
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
386
+
387
+ const stats = {
388
+ tsFiles: 0, jsFiles: 0, usesEsm: false, hasHtml: false, hasTests: false,
389
+ rawDeps: new Set(), envVars: new Set(),
390
+ style: { semiCount: 0, noSemiCount: 0, tabCount: 0, space2Count: 0, space4Count: 0 },
391
+ quality: { varCount: 0, hasEval: false, syncFsCount: 0 },
392
+ phantomInjections: new Map(),
393
+ discoveredSecrets: [],
394
+ subWorkspaces: [],
395
+ conflictingLockfiles: [],
396
+ unusedDepsInCode: new Set(),
397
+ filesWithEnvVars: new Set(),
398
+ injectDotenvEngine: false,
399
+ bootstrapEslintSuite: false
400
+ };
401
+
402
+ const activePkgManager = detectPackageManager(targetDir, stats);
206
403
  const pkgPath = path.join(targetDir, 'package.json');
207
404
  let preExistingLicense = null;
405
+ let preExistingDeps = [];
208
406
 
209
407
  console.log(`\n===================================================================`);
210
- console.log(`šŸš€ pkg-scaffold v2.7: Deep Intelligence Workspace Diagnostic Run`);
408
+ console.log(`šŸš€ pkg-scaffold v1.1: Deep Intelligence Workspace Diagnostic Run`);
211
409
  console.log(`===================================================================\n`);
212
410
 
213
- // --- Package.json Pre-existing Interceptor Subsystem ---
411
+ const topLevelItems = fs.readdirSync(targetDir);
412
+ const potentialSubModules = [];
413
+ for (const item of topLevelItems) {
414
+ const fullPath = path.join(targetDir, item);
415
+ if (!IGNORED_DIRS.has(item) && !item.startsWith('.') && fs.statSync(fullPath).isDirectory()) {
416
+ let containsSourceCode = false;
417
+ const examineDirectory = (d) => {
418
+ const subEntries = fs.readdirSync(d);
419
+ for (const entry of subEntries) {
420
+ const entryPath = path.join(d, entry);
421
+ if (fs.statSync(entryPath).isDirectory()) {
422
+ if (!IGNORED_DIRS.has(entry) && !entry.startsWith('.')) examineDirectory(entryPath);
423
+ } else if (VALID_EXTENSIONS.has(path.extname(entry))) {
424
+ containsSourceCode = true;
425
+ break;
426
+ }
427
+ }
428
+ };
429
+ try { examineDirectory(fullPath); } catch {}
430
+ if (containsSourceCode) potentialSubModules.push(item);
431
+ }
432
+ }
433
+ if (potentialSubModules.length > 1) {
434
+ stats.subWorkspaces = potentialSubModules;
435
+ }
436
+
214
437
  if (fs.existsSync(pkgPath)) {
215
438
  console.log(`āš ļø An existing package.json was found in this working directory.`);
216
439
  console.log(`šŸ“” Analyzing existing installation arrays for invalid metrics...`);
217
440
  try {
218
441
  const existingData = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
219
-
220
- // Capture license choice from the pre-existing package definition profile
221
442
  if (existingData.license && typeof existingData.license === 'string' && existingData.license.toLowerCase() !== 'none') {
222
443
  preExistingLicense = existingData.license;
223
444
  }
445
+ if (existingData.dependencies) preExistingDeps.push(...Object.keys(existingData.dependencies));
446
+ if (existingData.devDependencies) preExistingDeps.push(...Object.keys(existingData.devDependencies));
224
447
 
225
448
  const combinedDeps = Object.keys({ ...existingData.dependencies, ...existingData.devDependencies });
226
449
  let brokenEcosystem = combinedDeps.length === 0;
227
-
228
450
  for (const dep of combinedDeps) {
229
451
  const check = await inspectNpmPackage(dep);
230
452
  if (check && check.error === 'NOT_FOUND') {
@@ -232,35 +454,67 @@ async function main() {
232
454
  console.log(` āŒ Identified non-existent package on registry tracks: "${dep}"`);
233
455
  }
234
456
  }
235
-
236
457
  if (brokenEcosystem) {
237
458
  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`);
459
+ console.log(`šŸ‘‰ Action Required: Please remove or backup the existing 'package.json' from this folder.\n`);
460
+ rl.close();
240
461
  return;
241
- } else {
242
- console.log(` ā„¹ļø Existing package.json appears structurally sound. Skipping generation arrays to prevent asset loss.`);
243
462
  }
244
463
  } 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`);
464
+ console.log(`\nšŸ›‘ CRITICAL: Existing package.json is malformed or corrupt.\n`);
465
+ rl.close();
247
466
  return;
248
467
  }
249
468
  }
250
469
 
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
- };
470
+ scanWorkspace(targetDir, stats, folderName);
471
+
472
+ // --- Unused Dependency Filtration Matrix ---
473
+ const allDiscoveredUnused = new Set([...stats.unusedDepsInCode]);
474
+ if (preExistingDeps.length > 0) {
475
+ preExistingDeps.forEach(dep => { if (!stats.rawDeps.has(dep)) allDiscoveredUnused.add(dep); });
476
+ }
258
477
 
259
- scanWorkspace(targetDir, stats);
478
+ const devToolingEcosystem = new Set([
479
+ 'eslint', 'prettier', 'typescript', 'typescript-eslint', '@eslint/js',
480
+ 'nodemon', 'ts-node', 'tsup', 'vite', 'vitest', 'jest'
481
+ ]);
482
+ for (const dep of allDiscoveredUnused) {
483
+ if (devToolingEcosystem.has(dep) || dep.startsWith('@types/')) {
484
+ allDiscoveredUnused.delete(dep);
485
+ }
486
+ }
487
+
488
+ if (allDiscoveredUnused.size > 0) {
489
+ console.log(`\nšŸ“¦ UNUSED WORKSPACE DEPENDENCIES DETECTED`);
490
+ console.log(`───────────────────────────────────────────────────────────────────`);
491
+ console.log(` The following modules are imported or installed but never invoked inside executable code paths:`);
492
+ console.log(` ${Array.from(allDiscoveredUnused).map(d => `\x1b[33m"${d}"\x1b[0m`).join(', ')}`);
493
+ console.log(`───────────────────────────────────────────────────────────────────`);
494
+
495
+ const pruneChoice = await rl.question(`ā“ Exclude these unused dependencies from your package.json setup? (y/N): `);
496
+ if (pruneChoice.trim().toLowerCase() === 'y' || pruneChoice.trim().toLowerCase() === 'yes') {
497
+ for (const deadDep of allDiscoveredUnused) stats.rawDeps.delete(deadDep);
498
+ console.log(` šŸ—‘ļø Pruned unused dependencies from your configuration blueprint.`);
499
+ }
500
+ }
260
501
 
261
502
  const isTypeScript = stats.tsFiles > stats.jsFiles;
262
503
  const isFrontendWeb = stats.hasHtml || stats.rawDeps.has('react') || stats.rawDeps.has('vue') || stats.rawDeps.has('vite');
263
504
 
505
+ if (stats.envVars.size > 0 && !stats.rawDeps.has('dotenv') && !isFrontendWeb) {
506
+ console.log(`\nšŸ“” CONFIGURATION COMPLIANCE GAP: UNMANAGED ENVIRONMENT VARIABLES`);
507
+ console.log(`───────────────────────────────────────────────────────────────────`);
508
+ console.log(` Workspace utilizes 'process.env' variables but 'dotenv' is missing.`);
509
+ console.log(`───────────────────────────────────────────────────────────────────`);
510
+ const choiceEnv = await rl.question(`ā“ Add 'dotenv' and automatically wire initialization hooks into your files? (Y/n): `);
511
+
512
+ if (choiceEnv.trim().toLowerCase() !== 'n' && choiceEnv.trim().toLowerCase() !== 'no') {
513
+ stats.rawDeps.add('dotenv');
514
+ stats.injectDotenvEngine = true;
515
+ }
516
+ }
517
+
264
518
  const packageJson = {
265
519
  name: folderName.toLowerCase().replace(/[^a-z0-9-_]/g, '-'),
266
520
  version: '1.0.0',
@@ -273,6 +527,24 @@ async function main() {
273
527
  devDependencies: {}
274
528
  };
275
529
 
530
+ const eslintConfigFile = path.join(targetDir, 'eslint.config.js');
531
+ const linterPresent = fs.existsSync(eslintConfigFile) || fs.existsSync(path.join(targetDir, '.eslintrc.json')) || fs.existsSync(path.join(targetDir, '.eslintrc.js'));
532
+
533
+ if (!linterPresent && (stats.quality.varCount > 0 || stats.quality.hasEval || stats.phantomInjections.size > 0)) {
534
+ console.log(`\nšŸŽØ QUALITY LAYER AUDITOR: SYNTAX VALIDATION SYSTEM REQUIRED`);
535
+ console.log(`───────────────────────────────────────────────────────────────────`);
536
+ console.log(` Code anomalies (legacy 'var' choices or 'eval()') require static linter guards.`);
537
+ console.log(`───────────────────────────────────────────────────────────────────`);
538
+ const choiceLintSetup = await rl.question(`ā“ Bootstrap standard ESLint flat verification rules into workspace? (Y/n): `);
539
+
540
+ if (choiceLintSetup.trim().toLowerCase() !== 'n' && choiceLintSetup.trim().toLowerCase() !== 'no') {
541
+ stats.bootstrapEslintSuite = true;
542
+ stats.rawDeps.add('eslint');
543
+ if (isTypeScript) stats.rawDeps.add('typescript-eslint');
544
+ else stats.rawDeps.add('@eslint/js');
545
+ }
546
+ }
547
+
276
548
  if (isFrontendWeb) {
277
549
  packageJson.scripts.dev = 'vite';
278
550
  packageJson.scripts.build = 'vite build';
@@ -295,20 +567,22 @@ async function main() {
295
567
  }
296
568
 
297
569
  if (stats.rawDeps.size > 0) {
298
- console.log(`šŸ“” Resolving baseline package registry definitions...`);
570
+ console.log(`\nšŸ“” Resolving baseline package registry definitions...`);
299
571
  for (const pkg of stats.rawDeps) {
300
572
  const cleaned = cleanPackageName(pkg);
301
573
  if (cleaned && !builtinModules.includes(cleaned)) {
302
574
  const check = await inspectNpmPackage(cleaned);
303
575
  if (check && check.error !== 'NOT_FOUND') {
304
576
  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}`);
577
+
578
+ const isDevDep = [
579
+ 'vite', 'vitest', 'typescript', 'eslint', 'typescript-eslint',
580
+ '@eslint/js', 'prettier', 'jest', 'nodemon', 'ts-node', 'tsup'
581
+ ].includes(cleaned) || cleaned.startsWith('@types/');
582
+
583
+ if (isDevDep) packageJson.devDependencies[cleaned] = `^${version}`;
584
+ else packageJson.dependencies[cleaned] = `^${version}`;
585
+ console.log(` ¼ Synced verified package parameters: ${cleaned}@^${version}`);
312
586
  }
313
587
  }
314
588
  }
@@ -333,18 +607,64 @@ async function main() {
333
607
  console.log(`───────────────────────────────────────────────────────────────────`);
334
608
  }
335
609
 
336
- // ─── INTERACTIVE ON-DEMAND REMOTE LICENSE PROVISIONER ───────────────────
610
+ if (stats.discoveredSecrets.length > 0) {
611
+ console.log(`\n🚨 CRITICAL SECURITY COMPLIANCE ALERT: HARDCODED CREDENTIALS DETECTED`);
612
+ console.log(`───────────────────────────────────────────────────────────────────`);
613
+ for (const secretMeta of stats.discoveredSecrets) {
614
+ console.log(`šŸ“‚ File: ${path.relative(targetDir, secretMeta.filePath)}`);
615
+ console.log(` āš ļø Hardcoded raw credential instance found mapping to signature value [${secretMeta.keyName}]`);
616
+ }
617
+ console.log(`───────────────────────────────────────────────────────────────────`);
618
+
619
+ const fixSecrets = await rl.question(`ā“ Automatically extract credentials into environment mappings safely? (y/N): `);
620
+
621
+ if (fixSecrets.trim().toLowerCase() === 'y' || fixSecrets.trim().toLowerCase() === 'yes') {
622
+ const envPath = path.join(targetDir, '.env');
623
+ let envBuffer = fs.existsSync(envPath) ? readFileSyncNormalized(envPath) : '';
624
+
625
+ for (const secretMeta of stats.discoveredSecrets) {
626
+ let currentCodeContent = readFileSyncNormalized(secretMeta.filePath);
627
+ const envAccessor = isFrontendWeb ? `import.meta.env.${secretMeta.envVarName}` : `process.env.${secretMeta.envVarName}`;
628
+
629
+ const exactLiteralPattern = new RegExp(`\\b${secretMeta.keyName}\\s*=\\s*['"\`]${secretMeta.secretValue.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}['"\`]`, 'g');
630
+ currentCodeContent = currentCodeContent.replace(exactLiteralPattern, `${secretMeta.keyName} = ${envAccessor}`);
631
+ fs.writeFileSync(secretMeta.filePath, currentCodeContent);
632
+
633
+ if (!envBuffer.includes(`${secretMeta.envVarName}=`)) envBuffer += `${secretMeta.envVarName}=${secretMeta.secretValue}\n`;
634
+ console.log(` šŸ”’ Safely isolated credential string -> ${envAccessor} inside ${path.relative(targetDir, secretMeta.filePath)}`);
635
+ }
636
+ fs.writeFileSync(envPath, envBuffer);
637
+ }
638
+ }
639
+
640
+ if (stats.subWorkspaces && stats.subWorkspaces.length > 1) {
641
+ console.log(`\nšŸ“‚ MULTI-WORKSPACE SEGMENTATION DETECTED`);
642
+ console.log(` Identified independent sub-module paths: ${stats.subWorkspaces.map(w => `/${w}`).join(', ')}`);
643
+
644
+ const setupWorkspace = await rl.question(`ā“ Setup layout architecture as a multi-package Monorepo Workspace layout? (y/N): `);
645
+
646
+ if (setupWorkspace.trim().toLowerCase() === 'y' || setupWorkspace.trim().toLowerCase() === 'yes') {
647
+ if (activePkgManager === 'pnpm') {
648
+ const workspaceYamlPath = path.join(targetDir, 'pnpm-workspace.yaml');
649
+ const workspaceYamlTemplate = `packages:\n${stats.subWorkspaces.map(w => ` - '${w}'`).join('\n')}\n`;
650
+ fs.writeFileSync(workspaceYamlPath, workspaceYamlTemplate);
651
+ console.log(` šŸ—ļø Generated monorepo configuration layer: pnpm-workspace.yaml`);
652
+ } else {
653
+ packageJson.workspaces = stats.subWorkspaces.map(w => `${w}`);
654
+ console.log(` šŸ—ļø Injected 'workspaces' definitions directly into root layout blueprint.`);
655
+ }
656
+ }
657
+ }
658
+
337
659
  const licensePath = path.join(targetDir, 'LICENSE');
338
660
  let chosenLicenseType = preExistingLicense || 'None';
339
661
 
340
662
  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();
663
+ console.log(`\nāš–ļø Legal Compliance Auditor: No LICENSE file located.`);
664
+ const licInput = await rl.question(`ā“ Enter Open Source License to register (e.g. MIT, Apache-2.0, ISC, BSD-3-Clause, skip): `);
345
665
 
346
- const cleanedInput = licInput.trim().toLowerCase();
347
- if (['mit', 'apache-2.0', 'gpl-3.0'].includes(cleanedInput)) {
666
+ const cleanedInput = licInput.trim();
667
+ if (cleanedInput.toLowerCase() !== 'skip' && cleanedInput.toLowerCase() !== 'none' && cleanedInput !== '') {
348
668
  console.log(` šŸ“” Querying GitHub Legal Databases for "${cleanedInput.toUpperCase()}" template...`);
349
669
  const rawTemplate = await fetchRemoteLicense(cleanedInput);
350
670
 
@@ -355,32 +675,26 @@ async function main() {
355
675
 
356
676
  fs.writeFileSync(licensePath, parsedText);
357
677
  chosenLicenseType = cleanedInput.toUpperCase();
358
- packageJson.license = cleanedInput.toUpperCase();
359
- console.log(` āš–ļø Successfully provisioned, stamped, and generated legal asset: LICENSE`);
678
+ console.log(` āš–ļø Successfully provisioned legal asset: LICENSE`);
360
679
  } else {
361
- console.log(` āŒ Connection boundary dropped. Skipping live license file provisioning.`);
680
+ console.log(` āš ļø License model "${cleanedInput}" not indexed on GitHub database registers. Saving custom structural label configuration.`);
681
+ chosenLicenseType = cleanedInput;
362
682
  }
683
+ packageJson.license = chosenLicenseType;
363
684
  }
364
685
  } else {
365
- // Skip prompt routing because metadata parameter indicators exist
366
686
  if (preExistingLicense) {
367
- console.log(`\nāš–ļø Legal Compliance Auditor: License "${preExistingLicense}" detected in package.json. Skipping interactive step.`);
368
687
  chosenLicenseType = preExistingLicense;
369
-
370
- // Auto-provisioning loop if the descriptor is preset but the physical asset is absent
371
688
  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
689
  const rawTemplate = await fetchRemoteLicense(preExistingLicense);
374
690
  if (rawTemplate) {
375
691
  const parsedText = rawTemplate
376
692
  .replace(/\[year\]|<year>/gi, '2026')
377
693
  .replace(/\[fullname\]|\[name of copyright owner\]|<copyright holders>|<name of author>/gi, gitInfo.name);
378
694
  fs.writeFileSync(licensePath, parsedText);
379
- console.log(` āš–ļø Successfully mirrored and synthesized missing license file artifacts.`);
380
695
  }
381
696
  }
382
697
  } else if (fs.existsSync(licensePath)) {
383
- console.log(`\nāš–ļø Legal Compliance Auditor: Existing physical LICENSE file detected. Skipping interactive step.`);
384
698
  try {
385
699
  const currentLicenseContent = fs.readFileSync(licensePath, 'utf8');
386
700
  if (currentLicenseContent.includes('MIT')) chosenLicenseType = 'MIT';
@@ -391,9 +705,55 @@ async function main() {
391
705
  packageJson.license = chosenLicenseType;
392
706
  }
393
707
 
708
+ if (!stats.hasTests) {
709
+ const bootstrapTest = await rl.question(`\nā“ No test files detected. Scaffold a zero-bloat testing harness via Node native test runner? (y/N): `);
710
+
711
+ if (bootstrapTest.trim().toLowerCase() === 'y' || bootstrapTest.trim().toLowerCase() === 'yes') {
712
+ const isEsm = packageJson.type === 'module';
713
+ const testExt = isTypeScript ? '.test.ts' : '.test.js';
714
+ const targetTestFile = `index${testExt}`;
715
+ const testFilePath = path.join(targetDir, targetTestFile);
716
+
717
+ const testTemplate = isEsm
718
+ ? `import { test, describe } from 'node:test';\nimport assert from 'node:assert';\n\ndescribe('Core Architecture Testing Suite', () => {\n test('should verify systemic environmental execution health', () => {\n assert.strictEqual(1, 1);\n });\n});\n`
719
+ : `const { test, describe } = require('node:test');\nconst assert = require('node:assert');\n\ndescribe('Core Architecture Testing Suite', () => {\n test('should verify systemic environmental execution health', () => {\n assert.strictEqual(1, 1);\n });\n});\n`;
720
+
721
+ fs.writeFileSync(testFilePath, testTemplate);
722
+ packageJson.scripts.test = 'node --test';
723
+ stats.hasTests = true;
724
+ console.log(` 🧪 Generated native functional testing fixture: ${targetTestFile}`);
725
+ }
726
+ }
727
+
394
728
  console.log(`\nāš™ļø Writing ecosystem configuration artifacts...`);
395
729
 
396
- if (!fs.existsSync(pkgPath)) {
730
+ if (stats.bootstrapEslintSuite) {
731
+ packageJson.scripts.lint = 'eslint .';
732
+ let eslintConfigContent = '';
733
+ if (isTypeScript) {
734
+ eslintConfigContent = `import eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\n\nexport default tseslint.config(\n eslint.configs.recommended,\n ...tseslint.configs.recommended,\n);\n`;
735
+ } else {
736
+ if (packageJson.type === 'module') {
737
+ eslintConfigContent = `import js from "@eslint/js";\n\nexport default [\n js.configs.recommended,\n {\n rules: {\n "no-unused-vars": "warn",\n "no-undef": "error"\n }\n }\n];\n`;
738
+ } else {
739
+ eslintConfigContent = `const js = require("@eslint/js");\n\nmodule.exports = [\n js.configs.recommended,\n {\n rules: {\n "no-unused-vars": "warn",\n "no-undef": "error"\n }\n }\n];\n`;
740
+ }
741
+ }
742
+ fs.writeFileSync(eslintConfigFile, eslintConfigContent);
743
+ console.log(` šŸŽØ Provisioned automated static syntax layout: eslint.config.js`);
744
+ }
745
+
746
+ if (fs.existsSync(pkgPath)) {
747
+ try {
748
+ const currentPackageJson = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
749
+ currentPackageJson.dependencies = { ...packageJson.dependencies, ...currentPackageJson.dependencies };
750
+ currentPackageJson.devDependencies = { ...packageJson.devDependencies, ...currentPackageJson.devDependencies };
751
+ if (packageJson.scripts.lint && !currentPackageJson.scripts.lint) currentPackageJson.scripts.lint = packageJson.scripts.lint;
752
+
753
+ fs.writeFileSync(pkgPath, JSON.stringify(currentPackageJson, null, 2));
754
+ console.log(` šŸ”„ Safely merged discovered dependencies into existing package.json`);
755
+ } catch (e) {}
756
+ } else {
397
757
  fs.writeFileSync(pkgPath, JSON.stringify(packageJson, null, 2));
398
758
  console.log(` šŸ“ Injected: package.json`);
399
759
  }
@@ -416,30 +776,33 @@ async function main() {
416
776
  }
417
777
 
418
778
  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`); }
779
+ if (!fs.existsSync(gitignorePath)) {
780
+ fs.writeFileSync(gitignorePath, `node_modules/\ndist/\nbuild/\n.env\n.env.local\n.DS_Store\n`);
781
+ console.log(` āš™ļø Structural default configurations locked: .gitignore`);
782
+ }
420
783
 
421
784
  if (isTypeScript) {
422
785
  const tsconfigPath = path.join(targetDir, 'tsconfig.json');
423
786
  if (!fs.existsSync(tsconfigPath)) {
424
787
  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`);
788
+ console.log(` āš™ļø Structural default configurations locked: tsconfig.json`);
426
789
  }
427
790
  }
428
791
 
429
- // --- Adaptive Flat Shields.io README Layout ---
430
792
  const readmePath = path.join(targetDir, 'README.md');
431
793
  if (!fs.existsSync(readmePath)) {
432
794
  const pName = packageJson.name;
433
795
  const layoutTree = buildAsciiTree(targetDir).join('\n');
434
-
435
796
  const displayDeps = Object.keys(packageJson.dependencies).map(d => `* \`${d}\``).join('\n') || '* None extracted';
436
797
  const displayDevDeps = Object.keys(packageJson.devDependencies).map(d => `* \`${d}\``).join('\n') || '* None extracted';
798
+ const licenseBadgeParam = encodeURIComponent(chosenLicenseType.replace(/-/g, '_'));
437
799
 
438
800
  const documentationTemplate =
439
801
  `# ${pName}
440
802
 
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})
803
+ ![Workspace Engine](https://img.shields.io/badge/engine-node-${packageJson.type === 'module' ? 'green' : 'blue'}?style=flat)
804
+ ![License Architecture](https://img.shields.io/badge/license-${licenseBadgeParam}-orange?style=flat)
805
+ ![Development Tooling](https://img.shields.io/badge/compiled_via-${isTypeScript ? 'typescript' : 'javascript'}-blueviolet?style=flat)
443
806
 
444
807
  ${packageJson.description}
445
808
 
@@ -473,52 +836,71 @@ ${activePkgManager} install
473
836
  console.log(` šŸ“– Auto-generated system asset metrics: README.md`);
474
837
  }
475
838
 
476
- // --- Interactive Code Mutation Pipeline ---
477
- if (stats.phantomInjections.size > 0) {
839
+ if (stats.phantomInjections.size > 0 || (stats.injectDotenvEngine && stats.filesWithEnvVars.size > 0)) {
478
840
  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();
841
+ const injectChoice = await rl.question(`ā“ Found phantom modules or unmanaged env components. Mutate file headers cleanly now? (y/N): `);
482
842
 
483
843
  if (injectChoice.trim().toLowerCase() === 'y' || injectChoice.trim().toLowerCase() === 'yes') {
484
- for (const [filePath, missingModules] of stats.phantomInjections.entries()) {
844
+ const allTargets = new Set([...stats.phantomInjections.keys(), ...stats.filesWithEnvVars]);
845
+
846
+ for (const filePath of allTargets) {
485
847
  const originalCode = readFileSyncNormalized(filePath);
486
848
  let declarationBlock = '';
487
849
 
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`;
850
+ const missingModules = stats.phantomInjections.get(filePath);
851
+ if (missingModules) {
852
+ for (const mod of missingModules) {
853
+ if (packageJson.type === 'module') declarationBlock += `import ${mod} from '${mod}';\n`;
854
+ else declarationBlock += `const ${mod} = require('${mod}');\n`;
493
855
  }
494
856
  }
495
- fs.writeFileSync(filePath, declarationBlock + originalCode);
496
- console.log(` ⚔ Injected declarations into top header row: ${path.relative(targetDir, filePath)}`);
857
+
858
+ if (stats.injectDotenvEngine && stats.filesWithEnvVars.has(filePath) && !originalCode.includes('dotenv')) {
859
+ if (packageJson.type === 'module') declarationBlock += `import 'dotenv/config';\n`;
860
+ else declarationBlock += `require('dotenv').config();\n`;
861
+ }
862
+
863
+ if (declarationBlock !== '') {
864
+ fs.writeFileSync(filePath, smartPrepend(originalCode, declarationBlock));
865
+ console.log(` ⚔ Injected contextual runtime headers safely: ${path.relative(targetDir, filePath)}`);
866
+ }
497
867
  }
498
868
  }
499
869
  }
500
870
 
501
- // --- Dynamic Self-Contained Local Auditing via npm-deprecated-check ---
502
871
  console.log(`\nšŸ›‘ INITIALIZING LIVE ECOSYSTEM DEPRECATION SECURITY SCAN...`);
503
872
  console.log(` Running integrated npm-deprecated-check validation algorithms:\n`);
504
873
  try {
505
874
  const localRequire = createRequire(import.meta.url);
506
875
  const dependencyPkgJsonPath = localRequire.resolve('npm-deprecated-check/package.json');
507
876
  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
-
877
+ const binRelativeMapping = typeof dependencyPkgJson.bin === 'string' ? dependencyPkgJson.bin : (dependencyPkgJson.bin['npm-deprecated-check'] || dependencyPkgJson.bin['ndc']);
513
878
  const absoluteExecutablePath = path.join(path.dirname(dependencyPkgJsonPath), binRelativeMapping);
514
879
  execSync(`node "${absoluteExecutablePath}" current`, { stdio: 'inherit', cwd: targetDir });
515
880
  } catch (err) {}
516
881
 
517
- // --- Automated Asset Installation Pipeline ---
882
+ if (stats.conflictingLockfiles.length > 1) {
883
+ console.log(`\nāš ļø CONFLICTING ACCUMULATED LOCKFILES DETECTED: [${stats.conflictingLockfiles.join(', ')}]`);
884
+ const cleanLocks = await rl.question(`ā“ Purge legacy/mismatched lockfiles to protect systemic package integrity? (y/N): `);
885
+
886
+ if (cleanLocks.trim().toLowerCase() === 'y' || cleanLocks.trim().toLowerCase() === 'yes') {
887
+ const packageEngineLockmap = { npm: 'package-lock.json', pnpm: 'pnpm-lock.yaml', yarn: 'yarn.lock' };
888
+ const operationalLockfile = packageEngineLockmap[activePkgManager];
889
+ for (const lockfile of stats.conflictingLockfiles) {
890
+ if (lockfile !== operationalLockfile) {
891
+ try {
892
+ fs.unlinkSync(path.join(targetDir, lockfile));
893
+ console.log(` šŸ—‘ļø Cleaned up duplicate lockfile artifact: ${lockfile}`);
894
+ } catch (e) {}
895
+ }
896
+ }
897
+ }
898
+ }
899
+
518
900
  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();
901
+ const userPromptChoice = await rl.question(`ā“ Detected system default manager: "${activePkgManager}". Run "${activePkgManager} install" automatically now? (y/N): `);
902
+
903
+ rl.close();
522
904
 
523
905
  const normalizedAnswer = userPromptChoice.trim().toLowerCase();
524
906
  if (normalizedAnswer === 'y' || normalizedAnswer === 'yes') {
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "pkg-scaffold",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Zero-config workspace initializer that scans your source code, generates modern configuration layers, corrects missing imports, and automatically audits legacy dependencies.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
8
8
  "pkg-scaffold": "./index.js"
9
9
  },
10
+ "scripts": {
11
+ "postpublish": "git add . && git commit -m \"chore: auto-sync version bump and workspace configuration layers\" && git pull origin main --rebase && git push origin main"
12
+ },
10
13
  "keywords": [
11
14
  "scaffold",
12
15
  "init",
@@ -20,6 +23,8 @@
20
23
  "author": "DreamLongYT",
21
24
  "license": "MIT",
22
25
  "dependencies": {
26
+ "acorn": "^8.17.0",
27
+ "acorn-walk": "^8.3.5",
23
28
  "npm-deprecated-check": "^1.4.0"
24
29
  }
25
30
  }