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 +100 -9
- package/package.json +4 -2
- package/profiles/ProjectProfile.js +14 -2
- package/telemetry.js +122 -0
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 (
|
|
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 (
|
|
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 === '--
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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.
|
|
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 }
|