progga 1.0.5 → 1.0.7

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/index.js CHANGED
@@ -11,6 +11,53 @@ const ProfileRegistry = require('./profiles/ProfileRegistry');
11
11
  const ProjectTypeDetector = require('./core/ProjectTypeDetector');
12
12
  const PresetSelector = require('./core/PresetSelector');
13
13
  const Spinner = require('./core/Spinner');
14
+ const { capture, maybeShowTelemetryNotice } = require('./telemetry');
15
+ const os = require('os');
16
+
17
+ function handleTelemetryCommand(args) {
18
+ if (args[0] !== 'telemetry') return false;
19
+
20
+ const action = args[1];
21
+ const configPath = path.join(os.homedir(), '.progga', 'config.json');
22
+
23
+ let config = {};
24
+ try {
25
+ if (fs.existsSync(configPath)) {
26
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
27
+ }
28
+ } catch { }
29
+
30
+ if (action === 'on') {
31
+ config.telemetry = true;
32
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
33
+ console.log('āœ… Telemetry enabled');
34
+ return true;
35
+ }
36
+
37
+ if (action === 'off') {
38
+ config.telemetry = false;
39
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
40
+ console.log('🚫 Telemetry disabled');
41
+ return true;
42
+ }
43
+
44
+ if (action === 'status') {
45
+ const enabled = config.telemetry !== false;
46
+ console.log(
47
+ enabled
48
+ ? 'šŸ“Š Telemetry is enabled'
49
+ : '🚫 Telemetry is disabled'
50
+ );
51
+ return true;
52
+ }
53
+
54
+ console.log('Usage: progga telemetry [on|off|status]');
55
+ return true;
56
+ }
57
+
58
+
59
+ const CLI_IGNORE_PATHS = new Set();
60
+ const CLI_IGNORE_EXTENSIONS = new Set();
14
61
 
15
62
  /**
16
63
  * Check if path should be ignored
@@ -20,13 +67,19 @@ function shouldIgnore(filePath, basePath, profile) {
20
67
  const parts = relativePath.split(path.sep);
21
68
 
22
69
  for (const part of parts) {
23
- if (profile.ignorePaths().includes(part)) {
70
+ if (
71
+ profile.ignorePaths().includes(part) ||
72
+ CLI_IGNORE_PATHS.has(part)
73
+ ) {
24
74
  return true;
25
75
  }
26
76
  }
27
77
 
28
78
  const ext = path.extname(filePath);
29
- if (profile.ignoreExtensions().includes(ext)) {
79
+ if (
80
+ profile.ignoreExtensions().includes(ext) ||
81
+ CLI_IGNORE_EXTENSIONS.has(ext)
82
+ ) {
30
83
  return true;
31
84
  }
32
85
 
@@ -295,13 +348,31 @@ function generateDocumentation(projectPath, outputFile, profile) {
295
348
  // Write to file
296
349
  fs.writeFileSync(outputFile, output, 'utf-8');
297
350
 
351
+ capture('generation_completed', {
352
+ files_processed: files.length,
353
+ });
354
+
298
355
  console.log(`\nāœ… Documentation generated successfully: ${outputFile}`);
299
356
  console.log(`šŸ“Š Total files processed: ${files.length}`);
300
357
  }
301
358
 
302
359
  // Main execution
303
360
  async function main() {
361
+ let cliIgnores = [];
304
362
  const args = process.argv.slice(2);
363
+ if (handleTelemetryCommand(args)) {
364
+ return; // šŸ”„ EXIT EARLY
365
+ }
366
+
367
+ maybeShowTelemetryNotice();
368
+
369
+ capture('cli_run', {
370
+ args_count: args.length,
371
+ used_ignore_flag: args.includes('--ignore') || args.includes('-i'),
372
+ used_preset: args.includes('--preset'),
373
+ is_tty: process.stdin.isTTY,
374
+ });
375
+
305
376
 
306
377
  let projectPath = '.';
307
378
  let outputFile = 'PROJECT_DOCUMENTATION.md';
@@ -310,13 +381,22 @@ async function main() {
310
381
  for (let i = 0; i < args.length; i++) {
311
382
  const arg = args[i];
312
383
 
313
- if (arg === '--project-type' || arg === '--preset') {
314
- projectType = args[i + 1];
315
- i++;
316
- } else if (!projectPath) {
317
- projectPath = arg;
318
- } else if (!outputFile) {
319
- outputFile = arg;
384
+ if (arg === '--ignore' || arg === '-i') {
385
+ const value = args[i + 1];
386
+ if (value) {
387
+ value
388
+ .split(',')
389
+ .map(v => v.trim())
390
+ .filter(Boolean)
391
+ .forEach(item => {
392
+ if (item.startsWith('.')) {
393
+ CLI_IGNORE_EXTENSIONS.add(item);
394
+ } else {
395
+ CLI_IGNORE_PATHS.add(item);
396
+ }
397
+ });
398
+ i++;
399
+ }
320
400
  }
321
401
  }
322
402
 
@@ -342,8 +422,19 @@ async function main() {
342
422
  profile = ProfileRegistry.fallback(projectPath);
343
423
  }
344
424
 
425
+ if (cliIgnores.length) {
426
+ profile.applyCliIgnores(cliIgnores);
427
+ console.log(`🚫 CLI ignores applied: ${cliIgnores.join(', ')}`);
428
+ }
429
+
430
+ capture('profile_selected', {
431
+ profile: profile.name,
432
+ });
433
+
345
434
  console.log(`Using profile: ${profile.name}`);
435
+
346
436
  generateDocumentation(projectPath, outputFile, profile);
437
+
347
438
  }
348
439
 
349
440
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "progga",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Generate comprehensive project documentation for AI assistants - Share your entire codebase context in one markdown file",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -40,7 +40,9 @@
40
40
  "homepage": "https://github.com/Yousuf-Basir/progga#readme",
41
41
  "dependencies": {
42
42
  "@inquirer/select": "^5.0.4",
43
+ "dotenv": "^17.2.3",
43
44
  "inquirer": "^13.2.0",
44
- "ora": "^9.0.0"
45
+ "ora": "^9.0.0",
46
+ "posthog-node": "^5.20.0"
45
47
  }
46
48
  }
@@ -1,6 +1,18 @@
1
1
  class ProjectProfile {
2
2
  constructor(projectRoot) {
3
3
  this.projectRoot = projectRoot;
4
+ this.cliIgnorePaths = [];
5
+ this.cliIgnoreExtensions = [];
6
+ }
7
+
8
+ applyCliIgnores(list) {
9
+ for (const item of list) {
10
+ if (item.startsWith('.')) {
11
+ this.cliIgnoreExtensions.push(item);
12
+ } else {
13
+ this.cliIgnorePaths.push(item);
14
+ }
15
+ }
4
16
  }
5
17
 
6
18
  get name() {
@@ -9,12 +21,12 @@ class ProjectProfile {
9
21
 
10
22
  /** Paths to fully ignore */
11
23
  ignorePaths() {
12
- return [];
24
+ return this.cliIgnorePaths;
13
25
  }
14
26
 
15
27
  /** Extensions to ignore */
16
28
  ignoreExtensions() {
17
- return [];
29
+ return this.cliIgnoreExtensions;
18
30
  }
19
31
 
20
32
  /** Binary extensions */
package/telemetry.js ADDED
@@ -0,0 +1,122 @@
1
+ require('dotenv').config();
2
+ const os = require('os')
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+ const { PostHog } = require('posthog-node')
6
+ const pkg = require('./package.json')
7
+
8
+ const POSTHOG_KEY = process.env.POSTHOG_KEY;
9
+ const POSTHOG_HOST = process.env.POSTHOG_HOST || 'https://us.i.posthog.com';
10
+
11
+ const CONFIG_DIR = path.join(os.homedir(), '.progga')
12
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
13
+
14
+ let client = null;
15
+
16
+ if (POSTHOG_KEY) {
17
+ client = new PostHog(POSTHOG_KEY, {
18
+ host: POSTHOG_HOST,
19
+ flushAt: 1,
20
+ flushInterval: 0
21
+ });
22
+ }
23
+
24
+ function getConfig() {
25
+ try {
26
+ if (!fs.existsSync(CONFIG_DIR)) {
27
+ fs.mkdirSync(CONFIG_DIR);
28
+ }
29
+
30
+ if (fs.existsSync(CONFIG_FILE)) {
31
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
32
+ }
33
+ } catch { }
34
+
35
+ return {};
36
+ }
37
+
38
+ function saveConfig(config) {
39
+ try {
40
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
41
+ } catch { }
42
+ }
43
+
44
+
45
+ function getOrCreateUserId() {
46
+ try {
47
+ if (!fs.existsSync(CONFIG_DIR)) {
48
+ fs.mkdirSync(CONFIG_DIR)
49
+ }
50
+
51
+ if (fs.existsSync(CONFIG_FILE)) {
52
+ const data = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'))
53
+ if (data.userId) return data.userId
54
+ }
55
+
56
+ const userId = cryptoRandomId()
57
+ saveConfig({ userId });
58
+
59
+ return userId
60
+ } catch {
61
+ return null
62
+ }
63
+ }
64
+
65
+ function isTelemetryEnabled() {
66
+ const config = getConfig();
67
+ return config.telemetry !== false; // default ON
68
+ }
69
+
70
+ function cryptoRandomId() {
71
+ return require('crypto').randomUUID()
72
+ }
73
+
74
+ function capture(event, properties = {}) {
75
+ if (!client) return;
76
+ if (!isTelemetryEnabled()) return;
77
+
78
+ const distinctId = getOrCreateUserId();
79
+ if (!distinctId) return;
80
+
81
+ client.capture({
82
+ distinctId,
83
+ event,
84
+ properties: {
85
+ tool: 'progga',
86
+ version: pkg.version,
87
+ os: os.platform(),
88
+ node: process.version,
89
+ ...properties,
90
+ },
91
+ });
92
+
93
+ client.flush().catch(() => { });
94
+ }
95
+
96
+ function maybeShowTelemetryNotice() {
97
+ if (!process.stdin.isTTY) return;
98
+
99
+ const config = getConfig();
100
+
101
+ if (config.telemetry_notice_shown) return;
102
+
103
+ console.log('');
104
+ console.log('ℹ Progga collects anonymous usage data to improve the tool.');
105
+ console.log(' No project files, paths, or code are ever collected.');
106
+ console.log('');
107
+ console.log(' You can disable telemetry anytime with:');
108
+ console.log(' progga telemetry off');
109
+ console.log('');
110
+
111
+ saveConfig({
112
+ ...config,
113
+ telemetry_notice_shown: true,
114
+ });
115
+ }
116
+
117
+
118
+ process.on('exit', () => {
119
+ client.shutdown()
120
+ })
121
+
122
+ module.exports = { capture, maybeShowTelemetryNotice }