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,39 @@
|
|
|
1
|
+
/** Filesystem data source configuration options */
|
|
2
|
+
export interface FilesystemSourceOptions {
|
|
3
|
+
/** Paths to watch for file changes, supports ~/ expansion */
|
|
4
|
+
watchPaths: string[];
|
|
5
|
+
/** Glob patterns to exclude (e.g., node_modules, .git) */
|
|
6
|
+
excludePatterns: string[];
|
|
7
|
+
/** File extensions to include (e.g., ['.md', '.docx']), empty means all */
|
|
8
|
+
fileTypes?: string[];
|
|
9
|
+
/** Only scan files modified within this many days */
|
|
10
|
+
sinceDays: number;
|
|
11
|
+
/** Skip files larger than this size in bytes */
|
|
12
|
+
maxFileSize?: number;
|
|
13
|
+
/** Include content preview for text files */
|
|
14
|
+
includeContent?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Event type for file changes */
|
|
17
|
+
export type FileEventType = 'create' | 'modify' | 'delete';
|
|
18
|
+
/** Information about a file change */
|
|
19
|
+
export interface FileChangeItem {
|
|
20
|
+
/** Absolute path to the file */
|
|
21
|
+
filePath: string;
|
|
22
|
+
/** Base name of the file */
|
|
23
|
+
fileName: string;
|
|
24
|
+
/** Type of change (always 'modify' in stateless mode) */
|
|
25
|
+
eventType: FileEventType;
|
|
26
|
+
/** ISO timestamp of file modification */
|
|
27
|
+
modifiedAt: string;
|
|
28
|
+
/** File size in bytes */
|
|
29
|
+
fileSize: number;
|
|
30
|
+
/** File extension (e.g., '.md') */
|
|
31
|
+
extension: string;
|
|
32
|
+
/** MIME type if detectable */
|
|
33
|
+
mimeType?: string;
|
|
34
|
+
/** First N characters of text content */
|
|
35
|
+
contentPreview?: string;
|
|
36
|
+
/** Parent directory path */
|
|
37
|
+
parentDirectory: string;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/sources/filesystem/types.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,0DAA0D;IAC1D,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kCAAkC;AAClC,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3D,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,SAAS,EAAE,aAAa,CAAC;IACzB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4BAA4B;IAC5B,eAAe,EAAE,MAAM,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DataSource } from '../base.js';
|
|
2
|
+
import type { CollectionResult } from '../../core/types.js';
|
|
3
|
+
import type { GitSourceOptions } from './types.js';
|
|
4
|
+
export declare class GitSource extends DataSource<GitSourceOptions> {
|
|
5
|
+
readonly type: "git";
|
|
6
|
+
readonly name = "Git Commits";
|
|
7
|
+
private discoveredRepos;
|
|
8
|
+
validate(): Promise<boolean>;
|
|
9
|
+
private discoverRepositories;
|
|
10
|
+
collect(): Promise<CollectionResult>;
|
|
11
|
+
private execGit;
|
|
12
|
+
private getCommitsFromRepo;
|
|
13
|
+
private parseGitLog;
|
|
14
|
+
private getCommitStats;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sources/git/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAa,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9D,qBAAa,SAAU,SAAQ,UAAU,CAAC,gBAAgB,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAC/B,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,eAAe,CAAgB;IAEjC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAqClC,OAAO,CAAC,oBAAoB;IA6BtB,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA4B1C,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,kBAAkB;IA6B1B,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,cAAc;CA2BvB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { DataSource } from '../base.js';
|
|
5
|
+
import { expandPath, isGitRepository } from '../../utils/path.js';
|
|
6
|
+
export class GitSource extends DataSource {
|
|
7
|
+
type = 'git';
|
|
8
|
+
name = 'Git Commits';
|
|
9
|
+
discoveredRepos = [];
|
|
10
|
+
async validate() {
|
|
11
|
+
try {
|
|
12
|
+
this.execGit('.', ['--version']);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
this.context.logger.error('Git is not installed or not in PATH');
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (!this.options.scanPaths || this.options.scanPaths.length === 0) {
|
|
19
|
+
this.context.logger.error('No scan paths configured for git source');
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const excludeSet = new Set((this.options.excludeRepositories ?? []).map((p) => expandPath(p)));
|
|
23
|
+
for (const scanPath of this.options.scanPaths) {
|
|
24
|
+
const expanded = expandPath(scanPath);
|
|
25
|
+
if (!existsSync(expanded)) {
|
|
26
|
+
this.context.logger.warn(`Scan path does not exist: ${scanPath}`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const repos = this.discoverRepositories(expanded, excludeSet);
|
|
30
|
+
this.discoveredRepos.push(...repos);
|
|
31
|
+
}
|
|
32
|
+
if (this.discoveredRepos.length === 0) {
|
|
33
|
+
this.context.logger.error('No git repositories found in scan paths');
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
this.context.logger.info(`Discovered ${this.discoveredRepos.length} git repositories`);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
discoverRepositories(dirPath, excludeSet) {
|
|
40
|
+
const repos = [];
|
|
41
|
+
if (isGitRepository(dirPath)) {
|
|
42
|
+
if (excludeSet.has(dirPath)) {
|
|
43
|
+
this.context.logger.debug(`Excluding repository: ${dirPath}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
repos.push(dirPath);
|
|
47
|
+
}
|
|
48
|
+
// Don't recurse into nested git repos
|
|
49
|
+
return repos;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
57
|
+
continue;
|
|
58
|
+
const subPath = resolve(dirPath, entry.name);
|
|
59
|
+
repos.push(...this.discoverRepositories(subPath, excludeSet));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
this.context.logger.debug(`Cannot read directory: ${dirPath}`);
|
|
64
|
+
}
|
|
65
|
+
return repos;
|
|
66
|
+
}
|
|
67
|
+
async collect() {
|
|
68
|
+
const items = [];
|
|
69
|
+
const sinceDate = new Date();
|
|
70
|
+
sinceDate.setDate(sinceDate.getDate() - this.options.sinceDays);
|
|
71
|
+
for (const repoPath of this.discoveredRepos) {
|
|
72
|
+
try {
|
|
73
|
+
const commits = this.getCommitsFromRepo(repoPath, sinceDate);
|
|
74
|
+
items.push(...commits);
|
|
75
|
+
this.context.logger.debug(`Found ${commits.length} commits in ${repoPath}`);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
this.context.logger.error(`Failed to get commits from ${repoPath}`, error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
sourceType: this.type,
|
|
83
|
+
success: true,
|
|
84
|
+
itemsCollected: items.length,
|
|
85
|
+
items: items.map((commit) => ({
|
|
86
|
+
sourceType: this.type,
|
|
87
|
+
timestamp: new Date(commit.date),
|
|
88
|
+
data: commit,
|
|
89
|
+
})),
|
|
90
|
+
collectedAt: new Date(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
execGit(repoPath, args) {
|
|
94
|
+
return execFileSync('git', ['-C', repoPath, ...args], {
|
|
95
|
+
encoding: 'utf-8',
|
|
96
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
getCommitsFromRepo(repoPath, since) {
|
|
100
|
+
const sinceStr = since.toISOString().split('T')[0];
|
|
101
|
+
// Use NULL as separator for safe parsing of multi-line commit messages
|
|
102
|
+
const fieldSep = '%x00';
|
|
103
|
+
const recordSep = '%x00%x00';
|
|
104
|
+
const format = `%H${fieldSep}%an${fieldSep}%ae${fieldSep}%at${fieldSep}%B${recordSep}`;
|
|
105
|
+
const args = ['log', `--since=${sinceStr}`, `--format=${format}`];
|
|
106
|
+
if (this.options.authors?.length) {
|
|
107
|
+
for (const author of this.options.authors) {
|
|
108
|
+
args.push(`--author=${author}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const output = this.execGit(repoPath, args);
|
|
113
|
+
const commits = this.parseGitLog(output, repoPath);
|
|
114
|
+
return commits.map((commit) => {
|
|
115
|
+
const stats = this.getCommitStats(repoPath, commit.hash);
|
|
116
|
+
return { ...commit, stats };
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.context.logger.warn(`Failed to get git log from ${repoPath}`, error);
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
parseGitLog(output, repoPath) {
|
|
125
|
+
const commits = [];
|
|
126
|
+
const records = output.split('\0\0').filter(Boolean);
|
|
127
|
+
for (const record of records) {
|
|
128
|
+
const parts = record.split('\0');
|
|
129
|
+
if (parts.length < 5)
|
|
130
|
+
continue;
|
|
131
|
+
const [rawHash, authorName, authorEmail, timestamp, ...messageParts] = parts;
|
|
132
|
+
const hash = rawHash?.trim();
|
|
133
|
+
if (!hash || !authorName || !authorEmail || !timestamp)
|
|
134
|
+
continue;
|
|
135
|
+
const message = messageParts.join('\0').trim();
|
|
136
|
+
commits.push({
|
|
137
|
+
hash,
|
|
138
|
+
repository: repoPath,
|
|
139
|
+
authorName,
|
|
140
|
+
authorEmail,
|
|
141
|
+
date: new Date(parseInt(timestamp, 10) * 1000).toISOString(),
|
|
142
|
+
message,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return commits;
|
|
146
|
+
}
|
|
147
|
+
getCommitStats(repoPath, hash) {
|
|
148
|
+
try {
|
|
149
|
+
const statsOutput = this.execGit(repoPath, ['show', '--stat', '--format=', hash]);
|
|
150
|
+
const lines = statsOutput.trim().split('\n');
|
|
151
|
+
const summaryLine = lines[lines.length - 1] ?? '';
|
|
152
|
+
const filesMatch = summaryLine.match(/(\d+) files? changed/);
|
|
153
|
+
const insertMatch = summaryLine.match(/(\d+) insertions?\(\+\)/);
|
|
154
|
+
const deleteMatch = summaryLine.match(/(\d+) deletions?\(-\)/);
|
|
155
|
+
const filesOutput = this.execGit(repoPath, ['diff-tree', '--no-commit-id', '--name-only', '-r', hash]);
|
|
156
|
+
const files = filesOutput.trim().split('\n').filter(Boolean);
|
|
157
|
+
return {
|
|
158
|
+
filesChanged: filesMatch?.[1] ? parseInt(filesMatch[1], 10) : 0,
|
|
159
|
+
insertions: insertMatch?.[1] ? parseInt(insertMatch[1], 10) : 0,
|
|
160
|
+
deletions: deleteMatch?.[1] ? parseInt(deleteMatch[1], 10) : 0,
|
|
161
|
+
files,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
this.context.logger.warn(`Failed to get commit stats for ${hash}`, error);
|
|
166
|
+
return { filesChanged: 0, insertions: 0, deletions: 0, files: [] };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface GitCommit {
|
|
2
|
+
hash: string;
|
|
3
|
+
repository: string;
|
|
4
|
+
authorName: string;
|
|
5
|
+
authorEmail: string;
|
|
6
|
+
date: string;
|
|
7
|
+
message: string;
|
|
8
|
+
stats: {
|
|
9
|
+
filesChanged: number;
|
|
10
|
+
insertions: number;
|
|
11
|
+
deletions: number;
|
|
12
|
+
files: string[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface GitSourceOptions {
|
|
16
|
+
/** Directories to scan for git repositories */
|
|
17
|
+
scanPaths: string[];
|
|
18
|
+
/** Repository paths to exclude from collection */
|
|
19
|
+
excludeRepositories?: string[];
|
|
20
|
+
/** Filter commits by author email or name */
|
|
21
|
+
authors?: string[];
|
|
22
|
+
/** Only collect commits from the last N days */
|
|
23
|
+
sinceDays: number;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/sources/git/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function registerBuiltinSources(): void;
|
|
2
|
+
export { sourceRegistry } from './registry.js';
|
|
3
|
+
export { GitSource } from './git/index.js';
|
|
4
|
+
export { BrowserSource } from './browser/index.js';
|
|
5
|
+
export { FilesystemSource } from './filesystem/index.js';
|
|
6
|
+
export { ChatbotSource } from './chatbot/index.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sources/index.ts"],"names":[],"mappings":"AAMA,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { sourceRegistry } from './registry.js';
|
|
2
|
+
import { GitSource } from './git/index.js';
|
|
3
|
+
import { BrowserSource } from './browser/index.js';
|
|
4
|
+
import { FilesystemSource } from './filesystem/index.js';
|
|
5
|
+
import { ChatbotSource } from './chatbot/index.js';
|
|
6
|
+
export function registerBuiltinSources() {
|
|
7
|
+
sourceRegistry.register('git', (config, ctx) => new GitSource(config, ctx));
|
|
8
|
+
sourceRegistry.register('browser', (config, ctx) => new BrowserSource(config, ctx));
|
|
9
|
+
sourceRegistry.register('filesystem', (config, ctx) => new FilesystemSource(config, ctx));
|
|
10
|
+
sourceRegistry.register('chatbot', (config, ctx) => new ChatbotSource(config, ctx));
|
|
11
|
+
}
|
|
12
|
+
export { sourceRegistry } from './registry.js';
|
|
13
|
+
export { GitSource } from './git/index.js';
|
|
14
|
+
export { BrowserSource } from './browser/index.js';
|
|
15
|
+
export { FilesystemSource } from './filesystem/index.js';
|
|
16
|
+
export { ChatbotSource } from './chatbot/index.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataSource, DataSourceContext } from './base.js';
|
|
2
|
+
import type { SourceConfig, SourceType } from '../core/types.js';
|
|
3
|
+
type SourceFactory = (config: SourceConfig, context: DataSourceContext) => DataSource;
|
|
4
|
+
declare class SourceRegistry {
|
|
5
|
+
private factories;
|
|
6
|
+
register(type: SourceType, factory: SourceFactory): void;
|
|
7
|
+
create(type: SourceType, config: SourceConfig, context: DataSourceContext): DataSource | null;
|
|
8
|
+
getRegisteredTypes(): SourceType[];
|
|
9
|
+
has(type: SourceType): boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const sourceRegistry: SourceRegistry;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/sources/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,KAAK,UAAU,CAAC;AAEtF,cAAM,cAAc;IAClB,OAAO,CAAC,SAAS,CAAwC;IAEzD,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAIxD,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU,GAAG,IAAI;IAM7F,kBAAkB,IAAI,UAAU,EAAE;IAIlC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;CAG/B;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class SourceRegistry {
|
|
2
|
+
factories = new Map();
|
|
3
|
+
register(type, factory) {
|
|
4
|
+
this.factories.set(type, factory);
|
|
5
|
+
}
|
|
6
|
+
create(type, config, context) {
|
|
7
|
+
const factory = this.factories.get(type);
|
|
8
|
+
if (!factory)
|
|
9
|
+
return null;
|
|
10
|
+
return factory(config, context);
|
|
11
|
+
}
|
|
12
|
+
getRegisteredTypes() {
|
|
13
|
+
return Array.from(this.factories.keys());
|
|
14
|
+
}
|
|
15
|
+
has(type) {
|
|
16
|
+
return this.factories.has(type);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const sourceRegistry = new SourceRegistry();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
2
|
+
export interface Logger {
|
|
3
|
+
debug(message: string, ...args: unknown[]): void;
|
|
4
|
+
info(message: string, ...args: unknown[]): void;
|
|
5
|
+
warn(message: string, ...args: unknown[]): void;
|
|
6
|
+
error(message: string, ...args: unknown[]): void;
|
|
7
|
+
}
|
|
8
|
+
export interface LoggerConfig {
|
|
9
|
+
level: LogLevel;
|
|
10
|
+
}
|
|
11
|
+
export declare function createLogger(config: LoggerConfig): Logger;
|
|
12
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AASD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA8BzD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const LOG_LEVELS = {
|
|
2
|
+
debug: 0,
|
|
3
|
+
info: 1,
|
|
4
|
+
warn: 2,
|
|
5
|
+
error: 3,
|
|
6
|
+
};
|
|
7
|
+
export function createLogger(config) {
|
|
8
|
+
const minLevel = LOG_LEVELS[config.level];
|
|
9
|
+
const log = (level, message, ...args) => {
|
|
10
|
+
if (LOG_LEVELS[level] < minLevel)
|
|
11
|
+
return;
|
|
12
|
+
const timestamp = new Date().toISOString();
|
|
13
|
+
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
|
|
14
|
+
const fullMessage = `${prefix} ${message}`;
|
|
15
|
+
switch (level) {
|
|
16
|
+
case 'debug':
|
|
17
|
+
case 'info':
|
|
18
|
+
console.log(fullMessage, ...args);
|
|
19
|
+
break;
|
|
20
|
+
case 'warn':
|
|
21
|
+
console.warn(fullMessage, ...args);
|
|
22
|
+
break;
|
|
23
|
+
case 'error':
|
|
24
|
+
console.error(fullMessage, ...args);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
debug: (msg, ...args) => log('debug', msg, ...args),
|
|
30
|
+
info: (msg, ...args) => log('info', msg, ...args),
|
|
31
|
+
warn: (msg, ...args) => log('warn', msg, ...args),
|
|
32
|
+
error: (msg, ...args) => log('error', msg, ...args),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expand a path that may start with ~ or ~/ to an absolute path.
|
|
3
|
+
*/
|
|
4
|
+
export declare function expandPath(path: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Check if a directory is a git repository (contains .git folder).
|
|
7
|
+
*/
|
|
8
|
+
export declare function isGitRepository(dirPath: string): boolean;
|
|
9
|
+
//# sourceMappingURL=path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGxD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
/**
|
|
5
|
+
* Expand a path that may start with ~ or ~/ to an absolute path.
|
|
6
|
+
*/
|
|
7
|
+
export function expandPath(path) {
|
|
8
|
+
if (path === '~') {
|
|
9
|
+
return homedir();
|
|
10
|
+
}
|
|
11
|
+
if (path.startsWith('~/')) {
|
|
12
|
+
return resolve(homedir(), path.slice(2));
|
|
13
|
+
}
|
|
14
|
+
return resolve(path);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a directory is a git repository (contains .git folder).
|
|
18
|
+
*/
|
|
19
|
+
export function isGitRepository(dirPath) {
|
|
20
|
+
const gitDir = resolve(dirPath, '.git');
|
|
21
|
+
return existsSync(gitDir);
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
attempts: number;
|
|
3
|
+
delay: number;
|
|
4
|
+
backoff: number;
|
|
5
|
+
onRetry?: (error: Error, attempt: number) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function retry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
|
|
8
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AAMD,wBAAsB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAqBtF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function sleep(ms) {
|
|
2
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
}
|
|
4
|
+
export async function retry(fn, options) {
|
|
5
|
+
let lastError = new Error('Retry failed');
|
|
6
|
+
let currentDelay = options.delay;
|
|
7
|
+
for (let attempt = 1; attempt <= options.attempts; attempt++) {
|
|
8
|
+
try {
|
|
9
|
+
return await fn();
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
13
|
+
if (attempt === options.attempts) {
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
options.onRetry?.(lastError, attempt);
|
|
17
|
+
await sleep(currentDelay);
|
|
18
|
+
currentDelay *= options.backoff;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw lastError;
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "liferewind",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI-powered personal life review tool - collect your digital footprints from git, browser history, documents, and AI chatbots",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"data-collection",
|
|
8
|
+
"git",
|
|
9
|
+
"browser-history",
|
|
10
|
+
"productivity",
|
|
11
|
+
"life-logging",
|
|
12
|
+
"digital-footprint"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Richard Wang <git@xmail.ing>",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/i-richardwang/LifeRewind.git",
|
|
19
|
+
"directory": "packages/collector"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/i-richardwang/LifeRewind#readme",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/i-richardwang/LifeRewind/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"liferewind": "./dist/cli/index.js"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./types": {
|
|
37
|
+
"types": "./dist/core/types.d.ts",
|
|
38
|
+
"default": "./dist/core/types.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"LICENSE",
|
|
44
|
+
"README.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc",
|
|
48
|
+
"dev": "tsx watch src/cli/index.ts",
|
|
49
|
+
"start": "node dist/cli/index.js start",
|
|
50
|
+
"lint": "eslint . --max-warnings 0",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"prepublishOnly": "npm run build",
|
|
53
|
+
"pm2:start": "pm2 start ecosystem.config.cjs",
|
|
54
|
+
"pm2:stop": "pm2 stop liferewind-collector",
|
|
55
|
+
"pm2:restart": "pm2 restart liferewind-collector",
|
|
56
|
+
"pm2:logs": "pm2 logs liferewind-collector"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@inquirer/prompts": "^8.1.0",
|
|
60
|
+
"better-sqlite3": "^12.5.0",
|
|
61
|
+
"commander": "^14.0.2",
|
|
62
|
+
"minimatch": "^10.1.1",
|
|
63
|
+
"node-cron": "^3.0.3",
|
|
64
|
+
"ora": "^9.0.0",
|
|
65
|
+
"picocolors": "^1.1.1",
|
|
66
|
+
"zod": "^4.2.1"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
70
|
+
"@types/node": "^20.19.25",
|
|
71
|
+
"@types/node-cron": "^3.0.11",
|
|
72
|
+
"@workspace/eslint-config": "workspace:*",
|
|
73
|
+
"@workspace/typescript-config": "workspace:*",
|
|
74
|
+
"eslint": "^9.39.1",
|
|
75
|
+
"tsx": "^4.19.0",
|
|
76
|
+
"typescript": "^5.9.3"
|
|
77
|
+
},
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": ">=20"
|
|
80
|
+
}
|
|
81
|
+
}
|