liferewind 0.1.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.
- package/LICENSE +21 -0
- package/README.md +219 -0
- package/dist/api/client.d.ts +31 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +115 -0
- package/dist/cli/commands/collect.d.ts +3 -0
- package/dist/cli/commands/collect.d.ts.map +1 -0
- package/dist/cli/commands/collect.js +62 -0
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +112 -0
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +150 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +244 -0
- package/dist/cli/commands/start.d.ts +3 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +59 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +49 -0
- package/dist/cli/detect/browsers.d.ts +3 -0
- package/dist/cli/detect/browsers.d.ts.map +1 -0
- package/dist/cli/detect/browsers.js +19 -0
- package/dist/cli/detect/chatbot.d.ts +3 -0
- package/dist/cli/detect/chatbot.d.ts.map +1 -0
- package/dist/cli/detect/chatbot.js +15 -0
- package/dist/cli/detect/git.d.ts +2 -0
- package/dist/cli/detect/git.d.ts.map +1 -0
- package/dist/cli/detect/git.js +10 -0
- package/dist/cli/detect/index.d.ts +4 -0
- package/dist/cli/detect/index.d.ts.map +1 -0
- package/dist/cli/detect/index.js +3 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +30 -0
- package/dist/cli/utils/output.d.ts +8 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +28 -0
- package/dist/cli/utils/path.d.ts +9 -0
- package/dist/cli/utils/path.d.ts.map +1 -0
- package/dist/cli/utils/path.js +23 -0
- package/dist/config/loader.d.ts +7 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +64 -0
- package/dist/config/paths.d.ts +8 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +21 -0
- package/dist/config/schema.d.ts +95 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +110 -0
- package/dist/config/writer.d.ts +3 -0
- package/dist/config/writer.d.ts.map +1 -0
- package/dist/config/writer.js +19 -0
- package/dist/core/collector.d.ts +19 -0
- package/dist/core/collector.d.ts.map +1 -0
- package/dist/core/collector.js +83 -0
- package/dist/core/scheduler.d.ts +12 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +48 -0
- package/dist/core/types.d.ts +29 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/sources/base.d.ts +27 -0
- package/dist/sources/base.d.ts.map +1 -0
- package/dist/sources/base.js +23 -0
- package/dist/sources/browser/index.d.ts +14 -0
- package/dist/sources/browser/index.d.ts.map +1 -0
- package/dist/sources/browser/index.js +116 -0
- package/dist/sources/browser/readers/base.d.ts +28 -0
- package/dist/sources/browser/readers/base.d.ts.map +1 -0
- package/dist/sources/browser/readers/base.js +110 -0
- package/dist/sources/browser/readers/chromium.d.ts +13 -0
- package/dist/sources/browser/readers/chromium.d.ts.map +1 -0
- package/dist/sources/browser/readers/chromium.js +64 -0
- package/dist/sources/browser/readers/safari.d.ts +9 -0
- package/dist/sources/browser/readers/safari.d.ts.map +1 -0
- package/dist/sources/browser/readers/safari.js +34 -0
- package/dist/sources/browser/types.d.ts +35 -0
- package/dist/sources/browser/types.d.ts.map +1 -0
- package/dist/sources/browser/types.js +1 -0
- package/dist/sources/chatbot/index.d.ts +12 -0
- package/dist/sources/chatbot/index.d.ts.map +1 -0
- package/dist/sources/chatbot/index.js +67 -0
- package/dist/sources/chatbot/readers/base.d.ts +25 -0
- package/dist/sources/chatbot/readers/base.d.ts.map +1 -0
- package/dist/sources/chatbot/readers/base.js +109 -0
- package/dist/sources/chatbot/readers/chatwise.d.ts +14 -0
- package/dist/sources/chatbot/readers/chatwise.d.ts.map +1 -0
- package/dist/sources/chatbot/readers/chatwise.js +117 -0
- package/dist/sources/chatbot/types.d.ts +33 -0
- package/dist/sources/chatbot/types.d.ts.map +1 -0
- package/dist/sources/chatbot/types.js +1 -0
- package/dist/sources/filesystem/index.d.ts +10 -0
- package/dist/sources/filesystem/index.d.ts.map +1 -0
- package/dist/sources/filesystem/index.js +58 -0
- package/dist/sources/filesystem/scanner.d.ts +24 -0
- package/dist/sources/filesystem/scanner.d.ts.map +1 -0
- package/dist/sources/filesystem/scanner.js +264 -0
- package/dist/sources/filesystem/types.d.ts +39 -0
- package/dist/sources/filesystem/types.d.ts.map +1 -0
- package/dist/sources/filesystem/types.js +1 -0
- package/dist/sources/git/index.d.ts +16 -0
- package/dist/sources/git/index.d.ts.map +1 -0
- package/dist/sources/git/index.js +169 -0
- package/dist/sources/git/types.d.ts +25 -0
- package/dist/sources/git/types.d.ts.map +1 -0
- package/dist/sources/git/types.js +1 -0
- package/dist/sources/index.d.ts +7 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +16 -0
- package/dist/sources/registry.d.ts +13 -0
- package/dist/sources/registry.d.ts.map +1 -0
- package/dist/sources/registry.js +19 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +34 -0
- package/dist/utils/path.d.ts +9 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +22 -0
- package/dist/utils/retry.d.ts +8 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +22 -0
- package/package.json +81 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { findConfigPath, loadConfig } from '../../config/loader.js';
|
|
5
|
+
import { detectInstalledBrowsers, detectGitInstalled, detectChatbotClients } from '../detect/index.js';
|
|
6
|
+
import { printSuccess, printError, printInfo } from '../utils/output.js';
|
|
7
|
+
function checkNodeVersion() {
|
|
8
|
+
const version = process.version;
|
|
9
|
+
const major = parseInt(version.slice(1).split('.')[0] ?? '0', 10);
|
|
10
|
+
if (major >= 20) {
|
|
11
|
+
return { ok: true, message: `Node.js ${version}` };
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
message: `Node.js ${version} (requires >= 20)`,
|
|
16
|
+
suggestion: 'Upgrade to Node.js 20 or later',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function checkConfigExists(customPath) {
|
|
20
|
+
const configPath = findConfigPath(customPath);
|
|
21
|
+
if (configPath) {
|
|
22
|
+
return { ok: true, message: `Found at ${configPath}` };
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
message: 'No config file found',
|
|
27
|
+
suggestion: "Run 'liferewind init' to create one",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function checkApiConnection(customPath) {
|
|
31
|
+
try {
|
|
32
|
+
const config = loadConfig(customPath);
|
|
33
|
+
const healthUrl = new URL('/api/health', config.api.baseUrl).toString();
|
|
34
|
+
const response = await fetch(healthUrl, {
|
|
35
|
+
method: 'GET',
|
|
36
|
+
signal: AbortSignal.timeout(5000),
|
|
37
|
+
});
|
|
38
|
+
if (response.ok) {
|
|
39
|
+
return { ok: true, message: `API reachable at ${config.api.baseUrl}` };
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: `API returned ${response.status}`,
|
|
44
|
+
suggestion: 'Check if the web server is running',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof Error && error.message.includes('No configuration')) {
|
|
49
|
+
return { ok: false, message: 'Cannot check - no config', suggestion: "Run 'liferewind init' first" };
|
|
50
|
+
}
|
|
51
|
+
// Special handling for timeout errors
|
|
52
|
+
if (error instanceof Error && (error.name === 'TimeoutError' || error.message.includes('timeout'))) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
message: 'Connection timeout (5s)',
|
|
56
|
+
suggestion: 'Check if the web server is running and accessible',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
message: `Cannot reach API: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
62
|
+
suggestion: 'Check if the web server is running and accessible',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function checkGitCommand() {
|
|
67
|
+
if (detectGitInstalled()) {
|
|
68
|
+
try {
|
|
69
|
+
const version = execSync('git --version', { encoding: 'utf-8' }).trim();
|
|
70
|
+
return { ok: true, message: version };
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return { ok: true, message: 'Git installed' };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
message: 'Git not found',
|
|
79
|
+
suggestion: 'Install Git if you want to collect git commits',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function checkBrowserAccess() {
|
|
83
|
+
const browsers = detectInstalledBrowsers();
|
|
84
|
+
if (browsers.length > 0) {
|
|
85
|
+
return { ok: true, message: `Detected: ${browsers.join(', ')}` };
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
message: 'No supported browsers found',
|
|
90
|
+
suggestion: 'Install Chrome, Safari, or Arc for browser history collection',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function checkChatbotAccess() {
|
|
94
|
+
const clients = detectChatbotClients();
|
|
95
|
+
if (clients.length > 0) {
|
|
96
|
+
return { ok: true, message: `Detected: ${clients.join(', ')}` };
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
message: 'No chatbot clients found',
|
|
101
|
+
suggestion: 'Install ChatWise for chatbot history collection',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export const doctorCommand = new Command('doctor')
|
|
105
|
+
.description('Diagnose environment and configuration issues')
|
|
106
|
+
.action(async (_options, cmd) => {
|
|
107
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
108
|
+
const customPath = globalOpts.config;
|
|
109
|
+
console.log('Running diagnostics...\n');
|
|
110
|
+
// Synchronous checks
|
|
111
|
+
const syncChecks = [
|
|
112
|
+
{ name: 'Node.js version', result: checkNodeVersion() },
|
|
113
|
+
{ name: 'Configuration file', result: checkConfigExists(customPath) },
|
|
114
|
+
{ name: 'Git availability', result: checkGitCommand() },
|
|
115
|
+
{ name: 'Browser databases', result: checkBrowserAccess() },
|
|
116
|
+
{ name: 'Chatbot clients', result: checkChatbotAccess() },
|
|
117
|
+
];
|
|
118
|
+
let hasIssues = false;
|
|
119
|
+
for (const { name, result } of syncChecks) {
|
|
120
|
+
if (result.ok) {
|
|
121
|
+
printSuccess(`${name}: ${result.message}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
printError(`${name}: ${result.message}`);
|
|
125
|
+
if (result.suggestion) {
|
|
126
|
+
console.log(` ${pc.dim('Suggestion:')} ${result.suggestion}`);
|
|
127
|
+
}
|
|
128
|
+
hasIssues = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Async check for API
|
|
132
|
+
const apiResult = await checkApiConnection(customPath);
|
|
133
|
+
if (apiResult.ok) {
|
|
134
|
+
printSuccess(`API connectivity: ${apiResult.message}`);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
printError(`API connectivity: ${apiResult.message}`);
|
|
138
|
+
if (apiResult.suggestion) {
|
|
139
|
+
console.log(` ${pc.dim('Suggestion:')} ${apiResult.suggestion}`);
|
|
140
|
+
}
|
|
141
|
+
hasIssues = true;
|
|
142
|
+
}
|
|
143
|
+
console.log();
|
|
144
|
+
if (hasIssues) {
|
|
145
|
+
printInfo('Some issues were found. Address them for full functionality.');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
printSuccess('All checks passed! The collector is ready to run.');
|
|
149
|
+
}
|
|
150
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,eAAO,MAAM,WAAW,SAwPpB,CAAC"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { input, confirm, select, checkbox, password } from '@inquirer/prompts';
|
|
5
|
+
import { detectInstalledBrowsers, detectGitInstalled, detectChatbotClients } from '../detect/index.js';
|
|
6
|
+
import { writeConfig } from '../../config/writer.js';
|
|
7
|
+
import { getUserConfigPath } from '../../config/paths.js';
|
|
8
|
+
import { printBanner, printSection, printSuccess, printInfo, printDim, printWarning } from '../utils/output.js';
|
|
9
|
+
import { expandPath, parsePaths } from '../utils/path.js';
|
|
10
|
+
function warnMissingPaths(paths) {
|
|
11
|
+
for (const p of paths) {
|
|
12
|
+
const expanded = expandPath(p);
|
|
13
|
+
if (!existsSync(expanded)) {
|
|
14
|
+
printWarning(`Path does not exist: ${p}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const initCommand = new Command('init')
|
|
19
|
+
.description('Initialize configuration with interactive wizard')
|
|
20
|
+
.option('--force', 'overwrite existing configuration')
|
|
21
|
+
.action(async (options, cmd) => {
|
|
22
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
23
|
+
const configPath = globalOpts.config || getUserConfigPath();
|
|
24
|
+
// Check if config already exists
|
|
25
|
+
if (existsSync(configPath) && !options.force) {
|
|
26
|
+
printInfo(`Configuration already exists at ${configPath}`);
|
|
27
|
+
const overwrite = await confirm({
|
|
28
|
+
message: 'Overwrite existing configuration?',
|
|
29
|
+
default: false,
|
|
30
|
+
});
|
|
31
|
+
if (!overwrite) {
|
|
32
|
+
printInfo('Aborted.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
printBanner();
|
|
37
|
+
const config = {
|
|
38
|
+
api: { baseUrl: '', apiKey: '', timeout: 30000, retryAttempts: 3 },
|
|
39
|
+
sources: {
|
|
40
|
+
git: { enabled: false, schedule: 'daily', options: { scanPaths: [], sinceDays: 30 } },
|
|
41
|
+
browser: { enabled: false, schedule: 'daily', options: { browsers: [], excludeDomains: [], sinceDays: 7 } },
|
|
42
|
+
filesystem: {
|
|
43
|
+
enabled: false,
|
|
44
|
+
schedule: 'daily',
|
|
45
|
+
options: {
|
|
46
|
+
watchPaths: [],
|
|
47
|
+
excludePatterns: ['**/node_modules/**', '**/.git/**', '**/Library/**'],
|
|
48
|
+
sinceDays: 7,
|
|
49
|
+
includeContent: true,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
chatbot: { enabled: false, schedule: 'daily', options: { clients: [], sinceDays: 30, includeContent: true } },
|
|
53
|
+
},
|
|
54
|
+
logging: { level: 'info' },
|
|
55
|
+
};
|
|
56
|
+
// Step 1: API Configuration
|
|
57
|
+
printSection('Step 1/5: API Configuration');
|
|
58
|
+
config.api.baseUrl = await input({
|
|
59
|
+
message: 'API Base URL:',
|
|
60
|
+
default: 'http://localhost:3000',
|
|
61
|
+
validate: (value) => {
|
|
62
|
+
try {
|
|
63
|
+
new URL(value);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return 'Please enter a valid URL';
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
config.api.apiKey = await password({
|
|
72
|
+
message: 'API Key:',
|
|
73
|
+
validate: (value) => (value.length > 0 ? true : 'API Key is required'),
|
|
74
|
+
});
|
|
75
|
+
// Step 2: Browser History
|
|
76
|
+
printSection('Step 2/5: Browser History');
|
|
77
|
+
const detectedBrowsers = detectInstalledBrowsers();
|
|
78
|
+
if (detectedBrowsers.length > 0) {
|
|
79
|
+
printDim(` Detected: ${detectedBrowsers.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
printDim(' No supported browsers detected');
|
|
83
|
+
}
|
|
84
|
+
const enableBrowser = await confirm({
|
|
85
|
+
message: 'Enable browser history collection?',
|
|
86
|
+
default: true,
|
|
87
|
+
});
|
|
88
|
+
if (enableBrowser) {
|
|
89
|
+
const selectedBrowsers = await checkbox({
|
|
90
|
+
message: 'Select browsers to collect:',
|
|
91
|
+
choices: [
|
|
92
|
+
{ name: 'Chrome', value: 'chrome', checked: detectedBrowsers.includes('chrome') },
|
|
93
|
+
{ name: 'Safari', value: 'safari', checked: detectedBrowsers.includes('safari') },
|
|
94
|
+
{ name: 'Arc', value: 'arc', checked: detectedBrowsers.includes('arc') },
|
|
95
|
+
{ name: 'Dia', value: 'dia', checked: detectedBrowsers.includes('dia') },
|
|
96
|
+
{ name: 'Comet', value: 'comet', checked: detectedBrowsers.includes('comet') },
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
// If no browsers selected, disable the source
|
|
100
|
+
if (selectedBrowsers.length === 0) {
|
|
101
|
+
printWarning('No browsers selected, browser collection will be disabled.');
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const browserSchedule = await select({
|
|
105
|
+
message: 'Collection schedule:',
|
|
106
|
+
choices: [
|
|
107
|
+
{ name: 'Hourly', value: 'hourly' },
|
|
108
|
+
{ name: 'Daily (recommended)', value: 'daily' },
|
|
109
|
+
{ name: 'Weekly', value: 'weekly' },
|
|
110
|
+
{ name: 'Manual only', value: 'manual' },
|
|
111
|
+
],
|
|
112
|
+
default: 'daily',
|
|
113
|
+
});
|
|
114
|
+
config.sources.browser = {
|
|
115
|
+
enabled: true,
|
|
116
|
+
schedule: browserSchedule,
|
|
117
|
+
options: {
|
|
118
|
+
browsers: selectedBrowsers,
|
|
119
|
+
excludeDomains: ['localhost', '127.0.0.1'],
|
|
120
|
+
sinceDays: 7,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Step 3: Git Commits
|
|
126
|
+
printSection('Step 3/5: Git Commits');
|
|
127
|
+
const gitInstalled = detectGitInstalled();
|
|
128
|
+
printDim(gitInstalled ? ' Git is installed' : ' Git not found');
|
|
129
|
+
const enableGit = await confirm({
|
|
130
|
+
message: 'Enable git commit collection?',
|
|
131
|
+
default: true,
|
|
132
|
+
});
|
|
133
|
+
if (enableGit) {
|
|
134
|
+
const defaultPaths = [`${homedir()}/Projects`, `${homedir()}/Documents`].filter(existsSync);
|
|
135
|
+
const scanPathsInput = await input({
|
|
136
|
+
message: 'Paths to scan for git repositories (comma-separated):',
|
|
137
|
+
default: defaultPaths.join(',') || `${homedir()}/Projects`,
|
|
138
|
+
});
|
|
139
|
+
const scanPaths = parsePaths(scanPathsInput);
|
|
140
|
+
if (scanPaths.length === 0) {
|
|
141
|
+
printWarning('No paths specified, git collection will be disabled.');
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
warnMissingPaths(scanPaths);
|
|
145
|
+
const gitSchedule = await select({
|
|
146
|
+
message: 'Collection schedule:',
|
|
147
|
+
choices: [
|
|
148
|
+
{ name: 'Hourly', value: 'hourly' },
|
|
149
|
+
{ name: 'Daily (recommended)', value: 'daily' },
|
|
150
|
+
{ name: 'Weekly', value: 'weekly' },
|
|
151
|
+
{ name: 'Manual only', value: 'manual' },
|
|
152
|
+
],
|
|
153
|
+
default: 'daily',
|
|
154
|
+
});
|
|
155
|
+
config.sources.git = {
|
|
156
|
+
enabled: true,
|
|
157
|
+
schedule: gitSchedule,
|
|
158
|
+
options: {
|
|
159
|
+
scanPaths,
|
|
160
|
+
sinceDays: 30,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Step 4: Filesystem (Optional)
|
|
166
|
+
printSection('Step 4/5: Filesystem Changes');
|
|
167
|
+
const enableFilesystem = await confirm({
|
|
168
|
+
message: 'Enable filesystem monitoring?',
|
|
169
|
+
default: true,
|
|
170
|
+
});
|
|
171
|
+
if (enableFilesystem) {
|
|
172
|
+
const watchPathsInput = await input({
|
|
173
|
+
message: 'Paths to monitor (comma-separated):',
|
|
174
|
+
default: `${homedir()}/Documents,${homedir()}/Desktop`,
|
|
175
|
+
});
|
|
176
|
+
const watchPaths = parsePaths(watchPathsInput);
|
|
177
|
+
if (watchPaths.length === 0) {
|
|
178
|
+
printWarning('No paths specified, filesystem monitoring will be disabled.');
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
warnMissingPaths(watchPaths);
|
|
182
|
+
config.sources.filesystem = {
|
|
183
|
+
enabled: true,
|
|
184
|
+
schedule: 'daily',
|
|
185
|
+
options: {
|
|
186
|
+
watchPaths,
|
|
187
|
+
excludePatterns: ['**/node_modules/**', '**/.git/**', '**/Library/**'],
|
|
188
|
+
sinceDays: 7,
|
|
189
|
+
includeContent: true,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Step 5: Chatbot (Optional)
|
|
195
|
+
printSection('Step 5/5: Chatbot History');
|
|
196
|
+
const detectedChatbots = detectChatbotClients();
|
|
197
|
+
if (detectedChatbots.length > 0) {
|
|
198
|
+
printDim(` Detected: ${detectedChatbots.join(', ')}`);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
printDim(' No supported chatbot clients detected');
|
|
202
|
+
}
|
|
203
|
+
const enableChatbot = await confirm({
|
|
204
|
+
message: 'Enable chatbot history collection?',
|
|
205
|
+
default: true,
|
|
206
|
+
});
|
|
207
|
+
if (enableChatbot) {
|
|
208
|
+
config.sources.chatbot = {
|
|
209
|
+
enabled: true,
|
|
210
|
+
schedule: 'daily',
|
|
211
|
+
options: {
|
|
212
|
+
clients: detectedChatbots.length > 0 ? detectedChatbots : ['chatwise'],
|
|
213
|
+
sinceDays: 30,
|
|
214
|
+
includeContent: true,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
// Summary
|
|
219
|
+
printSection('Configuration Summary');
|
|
220
|
+
console.log(` API: ${config.api.baseUrl}`);
|
|
221
|
+
console.log(' Sources enabled:');
|
|
222
|
+
console.log(` ${config.sources.browser.enabled ? '✓' : '✗'} Browser`);
|
|
223
|
+
console.log(` ${config.sources.git.enabled ? '✓' : '✗'} Git`);
|
|
224
|
+
console.log(` ${config.sources.filesystem.enabled ? '✓' : '✗'} Filesystem`);
|
|
225
|
+
console.log(` ${config.sources.chatbot.enabled ? '✓' : '✗'} Chatbot`);
|
|
226
|
+
// Save
|
|
227
|
+
const shouldSave = await confirm({
|
|
228
|
+
message: `Save configuration to ${configPath}?`,
|
|
229
|
+
default: true,
|
|
230
|
+
});
|
|
231
|
+
if (shouldSave) {
|
|
232
|
+
writeConfig(config, configPath);
|
|
233
|
+
printSuccess('Configuration saved!');
|
|
234
|
+
console.log(`
|
|
235
|
+
Next steps:
|
|
236
|
+
Run 'liferewind start' to begin collecting data
|
|
237
|
+
Run 'liferewind collect' for immediate collection
|
|
238
|
+
Run 'liferewind config edit' to modify settings
|
|
239
|
+
`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
printInfo('Configuration not saved.');
|
|
243
|
+
}
|
|
244
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,YAAY,SA8DrB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Collector } from '../../core/collector.js';
|
|
3
|
+
import { loadConfig } from '../../config/loader.js';
|
|
4
|
+
import { createLogger } from '../../utils/logger.js';
|
|
5
|
+
import { registerBuiltinSources } from '../../sources/index.js';
|
|
6
|
+
import { printError, printInfo, printSuccess } from '../utils/output.js';
|
|
7
|
+
export const startCommand = new Command('start')
|
|
8
|
+
.description('Start the collector service')
|
|
9
|
+
.option('--run-once', 'collect once and exit')
|
|
10
|
+
.option('--run-on-start', 'run collection immediately on start')
|
|
11
|
+
.action(async (options, cmd) => {
|
|
12
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
13
|
+
try {
|
|
14
|
+
const config = loadConfig(globalOpts.config);
|
|
15
|
+
// Apply global log level overrides
|
|
16
|
+
let logLevel = config.logging.level;
|
|
17
|
+
if (globalOpts.verbose)
|
|
18
|
+
logLevel = 'debug';
|
|
19
|
+
if (globalOpts.quiet)
|
|
20
|
+
logLevel = 'error';
|
|
21
|
+
const logger = createLogger({ level: logLevel });
|
|
22
|
+
registerBuiltinSources();
|
|
23
|
+
const collector = new Collector(config, logger);
|
|
24
|
+
await collector.validateSources();
|
|
25
|
+
const enabledSources = collector.getEnabledSources();
|
|
26
|
+
if (enabledSources.length === 0) {
|
|
27
|
+
printError('No data sources enabled or validated.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
printInfo(`Enabled sources: ${enabledSources.join(', ')}`);
|
|
31
|
+
if (options.runOnce) {
|
|
32
|
+
printInfo('Running one-time collection...');
|
|
33
|
+
await collector.collectAll();
|
|
34
|
+
printSuccess('Collection complete.');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Setup graceful shutdown
|
|
38
|
+
const shutdown = async (signal) => {
|
|
39
|
+
printInfo(`Received ${signal}, shutting down...`);
|
|
40
|
+
await collector.stop();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
};
|
|
43
|
+
process.on('SIGTERM', () => {
|
|
44
|
+
shutdown('SIGTERM').catch(console.error);
|
|
45
|
+
});
|
|
46
|
+
process.on('SIGINT', () => {
|
|
47
|
+
shutdown('SIGINT').catch(console.error);
|
|
48
|
+
});
|
|
49
|
+
await collector.start();
|
|
50
|
+
if (options.runOnStart) {
|
|
51
|
+
await collector.collectAll();
|
|
52
|
+
}
|
|
53
|
+
printSuccess('Collector started. Press Ctrl+C to stop.');
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
printError(`Failed to start: ${error instanceof Error ? error.message : String(error)}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,aAAa,SAmDtB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { loadConfig, findConfigPath } from '../../config/loader.js';
|
|
3
|
+
import { printInfo, printSuccess, printError, printDim } from '../utils/output.js';
|
|
4
|
+
export const statusCommand = new Command('status')
|
|
5
|
+
.description('Show collector status')
|
|
6
|
+
.option('--json', 'output as JSON')
|
|
7
|
+
.action((options, cmd) => {
|
|
8
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
9
|
+
try {
|
|
10
|
+
const configPath = findConfigPath(globalOpts.config);
|
|
11
|
+
if (!configPath) {
|
|
12
|
+
printError('No configuration found.');
|
|
13
|
+
printInfo("Run 'liferewind init' to create one.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const config = loadConfig(globalOpts.config);
|
|
17
|
+
const enabledSources = Object.entries(config.sources)
|
|
18
|
+
.filter(([, cfg]) => cfg.enabled)
|
|
19
|
+
.map(([name, cfg]) => ({ name, schedule: cfg.schedule }));
|
|
20
|
+
const status = {
|
|
21
|
+
configPath,
|
|
22
|
+
apiUrl: config.api.baseUrl,
|
|
23
|
+
logLevel: config.logging.level,
|
|
24
|
+
sources: enabledSources,
|
|
25
|
+
};
|
|
26
|
+
if (options.json) {
|
|
27
|
+
console.log(JSON.stringify(status, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
printSuccess('Configuration loaded');
|
|
31
|
+
printDim(` Config: ${configPath}`);
|
|
32
|
+
printDim(` API: ${config.api.baseUrl}`);
|
|
33
|
+
printDim(` Log level: ${config.logging.level}`);
|
|
34
|
+
console.log();
|
|
35
|
+
if (enabledSources.length === 0) {
|
|
36
|
+
printInfo('No data sources enabled.');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
printInfo(`Enabled sources (${enabledSources.length}):`);
|
|
40
|
+
for (const src of enabledSources) {
|
|
41
|
+
console.log(` - ${src.name} (${src.schedule})`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
printError(`Failed to load status: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browsers.d.ts","sourceRoot":"","sources":["../../../src/cli/detect/browsers.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;AAUxE,wBAAgB,uBAAuB,IAAI,WAAW,EAAE,CAUvD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const BROWSER_PATHS = {
|
|
5
|
+
chrome: join(homedir(), 'Library/Application Support/Google/Chrome'),
|
|
6
|
+
arc: join(homedir(), 'Library/Application Support/Arc/User Data'),
|
|
7
|
+
safari: join(homedir(), 'Library/Safari'),
|
|
8
|
+
dia: join(homedir(), 'Library/Application Support/Dia/User Data'),
|
|
9
|
+
comet: join(homedir(), 'Library/Application Support/Comet'),
|
|
10
|
+
};
|
|
11
|
+
export function detectInstalledBrowsers() {
|
|
12
|
+
const detected = [];
|
|
13
|
+
for (const [browser, path] of Object.entries(BROWSER_PATHS)) {
|
|
14
|
+
if (existsSync(path)) {
|
|
15
|
+
detected.push(browser);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return detected;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatbot.d.ts","sourceRoot":"","sources":["../../../src/cli/detect/chatbot.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC;AAMvC,wBAAgB,oBAAoB,IAAI,aAAa,EAAE,CAUtD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const CHATBOT_PATHS = {
|
|
5
|
+
chatwise: join(homedir(), 'Library', 'Application Support', 'app.chatwise', 'app.db'),
|
|
6
|
+
};
|
|
7
|
+
export function detectChatbotClients() {
|
|
8
|
+
const detected = [];
|
|
9
|
+
for (const [client, path] of Object.entries(CHATBOT_PATHS)) {
|
|
10
|
+
if (existsSync(path)) {
|
|
11
|
+
detected.push(client);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return detected;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/cli/detect/git.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,IAAI,OAAO,CAO5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/detect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { initCommand } from './commands/init.js';
|
|
7
|
+
import { startCommand } from './commands/start.js';
|
|
8
|
+
import { collectCommand } from './commands/collect.js';
|
|
9
|
+
import { configCommand } from './commands/config.js';
|
|
10
|
+
import { statusCommand } from './commands/status.js';
|
|
11
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
12
|
+
// Read version from package.json
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const packagePath = join(__dirname, '../../package.json');
|
|
15
|
+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program
|
|
18
|
+
.name('liferewind')
|
|
19
|
+
.description('LifeRewind data collector - capture your digital footprint')
|
|
20
|
+
.version(packageJson.version)
|
|
21
|
+
.option('-c, --config <path>', 'path to config file')
|
|
22
|
+
.option('--verbose', 'enable verbose output')
|
|
23
|
+
.option('--quiet', 'suppress non-essential output');
|
|
24
|
+
program.addCommand(initCommand);
|
|
25
|
+
program.addCommand(startCommand);
|
|
26
|
+
program.addCommand(collectCommand);
|
|
27
|
+
program.addCommand(configCommand);
|
|
28
|
+
program.addCommand(statusCommand);
|
|
29
|
+
program.addCommand(doctorCommand);
|
|
30
|
+
program.parse();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function printBanner(): void;
|
|
2
|
+
export declare function printSection(title: string): void;
|
|
3
|
+
export declare function printSuccess(message: string): void;
|
|
4
|
+
export declare function printError(message: string): void;
|
|
5
|
+
export declare function printInfo(message: string): void;
|
|
6
|
+
export declare function printWarning(message: string): void;
|
|
7
|
+
export declare function printDim(message: string): void;
|
|
8
|
+
//# sourceMappingURL=output.d.ts.map
|