@edcalderon/versioning 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +83 -17
  2. package/dist/extensions/cleanup-repo/index.d.ts +49 -0
  3. package/dist/extensions/cleanup-repo/index.js +649 -0
  4. package/dist/extensions/lifecycle-hooks/index.d.ts +4 -0
  5. package/dist/extensions/{lifecycle-hooks.js → lifecycle-hooks/index.js} +1 -1
  6. package/dist/extensions/npm-publish/index.d.ts +4 -0
  7. package/dist/extensions/{npm-publish.js → npm-publish/index.js} +1 -1
  8. package/dist/extensions/reentry-status/config-manager.js +3 -1
  9. package/dist/extensions/reentry-status/constants.d.ts +1 -1
  10. package/dist/extensions/reentry-status/constants.js +1 -1
  11. package/dist/extensions/reentry-status/extension.d.ts +4 -0
  12. package/dist/extensions/{reentry-status-extension.js → reentry-status/extension.js} +165 -18
  13. package/dist/extensions/reentry-status/git-context.d.ts +27 -0
  14. package/dist/extensions/reentry-status/git-context.js +94 -0
  15. package/dist/extensions/reentry-status/index.d.ts +3 -0
  16. package/dist/extensions/reentry-status/index.js +6 -0
  17. package/dist/extensions/reentry-status/roadmap-renderer.d.ts +7 -0
  18. package/dist/extensions/reentry-status/roadmap-renderer.js +27 -10
  19. package/dist/extensions/sample-extension/index.d.ts +4 -0
  20. package/dist/extensions/{sample-extension.js → sample-extension/index.js} +1 -1
  21. package/dist/extensions/secrets-check/index.d.ts +16 -0
  22. package/dist/extensions/secrets-check/index.js +264 -0
  23. package/dist/extensions.js +27 -15
  24. package/dist/versioning.d.ts +1 -0
  25. package/package.json +2 -2
  26. package/dist/extensions/lifecycle-hooks.d.ts +0 -4
  27. package/dist/extensions/npm-publish.d.ts +0 -4
  28. package/dist/extensions/reentry-status-extension.d.ts +0 -4
  29. package/dist/extensions/sample-extension.d.ts +0 -4
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.checkContentForSecrets = checkContentForSecrets;
37
+ const child_process_1 = require("child_process");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ // Definition of patterns to search for
41
+ // Each pattern is a regex
42
+ const DEFAULT_PATTERNS = [
43
+ // PEM / JSON private keys
44
+ new RegExp('-----BEGIN ' + 'PRIVATE KEY-----'),
45
+ new RegExp('-----BEGIN ' + 'RSA PRIVATE KEY-----'),
46
+ /"private_key":\s*"/,
47
+ /"private_key_id":\s*"/,
48
+ // Cloud / API tokens
49
+ /AIza[0-9A-Za-z\-_]{35}/,
50
+ /ghp_[0-9A-Za-z]{36}/,
51
+ /npm_[0-9A-Za-z]{36}/,
52
+ // Ethereum / EVM hex private keys
53
+ /PRIVATE_DEPLOYER=[0-9a-fA-F]{40,}/,
54
+ /DEPLOYER_PRIVATE_KEY=0x[0-9a-fA-F]{40,}/,
55
+ /PRIVATE_KEY=[0-9a-fA-F]{64}/,
56
+ /_KEY=0x[0-9a-fA-F]{64}/,
57
+ /cast wallet address 0x[0-9a-fA-F]{64}/,
58
+ // Seed phrases
59
+ /MNEMONIC=.{20,}/
60
+ ];
61
+ // Allowlist patterns that are safe
62
+ const DEFAULT_ALLOWLIST = [
63
+ "POOL_MANAGER_ADDRESS=",
64
+ "HOOK_OWNER=",
65
+ "NEXT_PUBLIC_",
66
+ "ETHERSCAN_API_KEY=YOUR_",
67
+ "RPC_URL=",
68
+ "YOUR_DEPLOYER_PRIVATE_KEY",
69
+ "YOUR_LOCAL_PRIVATE_KEY",
70
+ "YOUR_TESTNET_PRIVATE_KEY",
71
+ "your_private_key_here"
72
+ ];
73
+ function checkContentForSecrets(content, patterns, allowlist, filename) {
74
+ const results = [];
75
+ const lines = content.split('\n');
76
+ for (let i = 0; i < lines.length; i++) {
77
+ const line = lines[i];
78
+ for (const pattern of patterns) {
79
+ if (pattern.test(line)) {
80
+ // Check allowance
81
+ let isAllowed = false;
82
+ for (const allow of allowlist) {
83
+ if (line.includes(allow)) {
84
+ isAllowed = true;
85
+ break;
86
+ }
87
+ }
88
+ if (!isAllowed) {
89
+ results.push({
90
+ file: filename,
91
+ line: i + 1,
92
+ content: line.trim(),
93
+ pattern: pattern.toString()
94
+ });
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return results;
100
+ }
101
+ const extension = {
102
+ name: 'secrets-check',
103
+ description: 'Checks for hardcoded secrets and private keys in staged files',
104
+ version: '1.1.0',
105
+ register: async (program, config) => {
106
+ // Try to get config from extensionConfig first, fallback to top-level secrets for backcompat
107
+ const extensionConfig = config.extensionConfig?.['secrets-check'];
108
+ const secretsConfig = extensionConfig || config.secrets || {};
109
+ if (secretsConfig.enabled === false) {
110
+ return;
111
+ }
112
+ // Merge patterns
113
+ const patterns = [...DEFAULT_PATTERNS];
114
+ if (secretsConfig.patterns) {
115
+ for (const p of secretsConfig.patterns) {
116
+ try {
117
+ patterns.push(new RegExp(p));
118
+ }
119
+ catch (e) {
120
+ console.warn(`⚠️ Invalid regex pattern in config: ${p}`);
121
+ }
122
+ }
123
+ }
124
+ // Merge allowlist
125
+ const allowlist = [...DEFAULT_ALLOWLIST];
126
+ if (secretsConfig.allowlist) {
127
+ allowlist.push(...secretsConfig.allowlist);
128
+ }
129
+ const secretsCmd = program
130
+ .command('check-secrets')
131
+ .description('Scan staged files for potential secrets')
132
+ .action(async () => {
133
+ await runSecretsCheck();
134
+ });
135
+ secretsCmd
136
+ .command('husky')
137
+ .description('Add secrets check to Husky pre-commit hook')
138
+ .option('--remove', 'Remove secrets check from Husky hook', false)
139
+ .action(async (options) => {
140
+ const rootDir = process.cwd();
141
+ const huskyDir = path.join(rootDir, '.husky');
142
+ const hookPath = path.join(huskyDir, 'pre-commit');
143
+ const MARKER_START = '# === secrets-check: start ===';
144
+ const MARKER_END = '# === secrets-check: end ===';
145
+ if (options.remove) {
146
+ if (!fs.existsSync(hookPath)) {
147
+ console.log('ℹ️ Hook pre-commit does not exist.');
148
+ return;
149
+ }
150
+ const content = fs.readFileSync(hookPath, 'utf8');
151
+ const startIdx = content.indexOf(MARKER_START);
152
+ const endIdx = content.indexOf(MARKER_END);
153
+ if (startIdx === -1 || endIdx === -1) {
154
+ console.log('ℹ️ No secrets-check block found in pre-commit.');
155
+ return;
156
+ }
157
+ const before = content.slice(0, startIdx).trimEnd();
158
+ const after = content.slice(endIdx + MARKER_END.length).trimStart();
159
+ const updated = [before, '', after].join('\n').replace(/\n{3,}/g, '\n\n').trim() + '\n';
160
+ fs.writeFileSync(hookPath, updated, 'utf8');
161
+ console.log('✅ Removed secrets check from .husky/pre-commit');
162
+ return;
163
+ }
164
+ // Add cleanup block to hook
165
+ if (!fs.existsSync(huskyDir)) {
166
+ fs.mkdirSync(huskyDir, { recursive: true });
167
+ }
168
+ const block = [
169
+ '',
170
+ MARKER_START,
171
+ 'echo "🔒 Running secrets check…"',
172
+ 'npx versioning check-secrets 2>/dev/null',
173
+ MARKER_END,
174
+ ''
175
+ ].join('\n');
176
+ if (fs.existsSync(hookPath)) {
177
+ const existing = fs.readFileSync(hookPath, 'utf8');
178
+ if (existing.includes(MARKER_START)) {
179
+ console.log('ℹ️ Secrets check is already integrated in .husky/pre-commit.');
180
+ return;
181
+ }
182
+ const updated = existing.trimEnd() + '\n' + block;
183
+ fs.writeFileSync(hookPath, updated, 'utf8');
184
+ }
185
+ else {
186
+ const content = [
187
+ '#!/bin/sh',
188
+ '. "$(dirname "$0")/_/husky.sh"',
189
+ '',
190
+ block
191
+ ].join('\n');
192
+ fs.writeFileSync(hookPath, content, { mode: 0o755 });
193
+ }
194
+ console.log('✅ Secrets check integrated into .husky/pre-commit');
195
+ });
196
+ async function runSecretsCheck() {
197
+ try {
198
+ console.log("🔒 Scanning for secrets...");
199
+ let failed = false;
200
+ // Get list of staged files
201
+ let output = '';
202
+ try {
203
+ output = (0, child_process_1.execSync)('git diff --cached --name-only --diff-filter=ACMR', { encoding: 'utf-8' });
204
+ }
205
+ catch (e) {
206
+ // If not in a git repo or no staged files, just return
207
+ console.log("⚠️ Not a git repository or git error.");
208
+ return;
209
+ }
210
+ const files = output.split('\n').filter(f => f.trim() !== '');
211
+ if (files.length === 0) {
212
+ console.log("✅ No staged files to check.");
213
+ return;
214
+ }
215
+ for (const relativePath of files) {
216
+ const filePath = path.resolve(process.cwd(), relativePath);
217
+ // Skip check if file doesn't exist (deleted)
218
+ if (!fs.existsSync(filePath)) {
219
+ continue;
220
+ }
221
+ // Skip lock files
222
+ if (relativePath.includes('lock.yaml') || relativePath.includes('lock.json')) {
223
+ continue;
224
+ }
225
+ // Read file content
226
+ let content = '';
227
+ try {
228
+ content = fs.readFileSync(filePath, 'utf-8');
229
+ }
230
+ catch (e) {
231
+ console.warn(`⚠️ Could not read file ${relativePath}:`, e);
232
+ continue;
233
+ }
234
+ const findings = checkContentForSecrets(content, patterns, allowlist, relativePath);
235
+ if (findings.length > 0) {
236
+ failed = true;
237
+ for (const finding of findings) {
238
+ console.log(`❌ POTENTIAL SECRET FOUND in ${finding.file}:${finding.line}`);
239
+ console.log(` ${finding.content}`);
240
+ console.log(` (matched pattern: ${finding.pattern})`);
241
+ }
242
+ }
243
+ }
244
+ if (failed) {
245
+ console.log("----------------------------------------------------");
246
+ console.log("⛔ COMMIT REJECTED");
247
+ console.log("Sensitive data was found in the staged files.");
248
+ console.log("Please remove the secrets before committing.");
249
+ console.log("----------------------------------------------------");
250
+ process.exit(1);
251
+ }
252
+ else {
253
+ console.log("✅ No secrets found.");
254
+ }
255
+ }
256
+ catch (error) {
257
+ console.error('❌ Check failed:', error instanceof Error ? error.message : String(error));
258
+ process.exit(1);
259
+ }
260
+ }
261
+ }
262
+ };
263
+ exports.default = extension;
264
+ //# sourceMappingURL=index.js.map
@@ -81,24 +81,36 @@ async function loadExtensions(program) {
81
81
  if (await fs.pathExists(extensionsDir)) {
82
82
  const extensionFiles = await fs.readdir(extensionsDir);
83
83
  for (const file of extensionFiles) {
84
- if (file.endsWith('.js')) {
85
- try {
86
- const extensionPath = path.join(extensionsDir, file);
87
- const extensionModule = require(extensionPath);
88
- const extension = extensionModule.default || extensionModule;
89
- if (extension && typeof extension.register === 'function') {
90
- await extension.register(program, config);
91
- // Register hooks if available
92
- if (extension.hooks) {
93
- context.hooks.push(extension.hooks);
94
- }
95
- console.log(`✅ Loaded extension: ${extension.name}@${extension.version}`);
96
- }
84
+ let extensionPath = path.join(extensionsDir, file);
85
+ const stats = await fs.stat(extensionPath);
86
+ if (stats.isDirectory()) {
87
+ // Check for index.js in directory
88
+ const indexPath = path.join(extensionPath, 'index.js');
89
+ if (await fs.pathExists(indexPath)) {
90
+ extensionPath = indexPath;
97
91
  }
98
- catch (error) {
99
- console.warn(`⚠️ Failed to load extension ${file}:`, error instanceof Error ? error.message : String(error));
92
+ else {
93
+ continue;
100
94
  }
101
95
  }
96
+ else if (!file.endsWith('.js')) {
97
+ continue;
98
+ }
99
+ try {
100
+ const extensionModule = require(extensionPath);
101
+ const extension = extensionModule.default || extensionModule;
102
+ if (extension && typeof extension.register === 'function') {
103
+ await extension.register(program, config);
104
+ // Register hooks if available
105
+ if (extension.hooks) {
106
+ context.hooks.push(extension.hooks);
107
+ }
108
+ console.log(`✅ Loaded extension: ${extension.name}@${extension.version}`);
109
+ }
110
+ }
111
+ catch (error) {
112
+ console.warn(`⚠️ Failed to load extension ${file}:`, error instanceof Error ? error.message : String(error));
113
+ }
102
114
  }
103
115
  }
104
116
  // Note: External extensions from config.extensions are not yet implemented
@@ -4,6 +4,7 @@ export interface VersionConfig {
4
4
  packages: string[];
5
5
  changelogFile?: string;
6
6
  conventionalCommits?: boolean;
7
+ extensionConfig?: Record<string, any>;
7
8
  }
8
9
  export declare class VersionManager {
9
10
  private config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edcalderon/versioning",
3
- "version": "1.1.2",
3
+ "version": "1.3.0",
4
4
  "description": "A comprehensive versioning and changelog management tool for monorepos",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -78,4 +78,4 @@
78
78
  "url": "git+https://github.com/edcalderon/my-second-brain.git",
79
79
  "directory": "packages/versioning"
80
80
  }
81
- }
81
+ }
@@ -1,4 +0,0 @@
1
- import { VersioningExtension } from '../extensions';
2
- declare const extension: VersioningExtension;
3
- export default extension;
4
- //# sourceMappingURL=lifecycle-hooks.d.ts.map
@@ -1,4 +0,0 @@
1
- import { VersioningExtension } from '../extensions';
2
- declare const extension: VersioningExtension;
3
- export default extension;
4
- //# sourceMappingURL=npm-publish.d.ts.map
@@ -1,4 +0,0 @@
1
- import { VersioningExtension } from '../extensions';
2
- declare const extension: VersioningExtension;
3
- export default extension;
4
- //# sourceMappingURL=reentry-status-extension.d.ts.map
@@ -1,4 +0,0 @@
1
- import { VersioningExtension } from '../extensions';
2
- declare const extension: VersioningExtension;
3
- export default extension;
4
- //# sourceMappingURL=sample-extension.d.ts.map