@ycniuqton/devlens 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.
Files changed (61) hide show
  1. package/README.md +164 -0
  2. package/bin/devlens.js +2 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +205 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/init.d.ts +3 -0
  7. package/dist/init.js +239 -0
  8. package/dist/init.js.map +1 -0
  9. package/dist/routes/diff.d.ts +1 -0
  10. package/dist/routes/diff.js +39 -0
  11. package/dist/routes/diff.js.map +1 -0
  12. package/dist/routes/integrations.d.ts +1 -0
  13. package/dist/routes/integrations.js +132 -0
  14. package/dist/routes/integrations.js.map +1 -0
  15. package/dist/routes/rules.d.ts +1 -0
  16. package/dist/routes/rules.js +115 -0
  17. package/dist/routes/rules.js.map +1 -0
  18. package/dist/routes/tasks.d.ts +4 -0
  19. package/dist/routes/tasks.js +360 -0
  20. package/dist/routes/tasks.js.map +1 -0
  21. package/dist/server.d.ts +7 -0
  22. package/dist/server.js +112 -0
  23. package/dist/server.js.map +1 -0
  24. package/dist/services/claudeTasks.d.ts +23 -0
  25. package/dist/services/claudeTasks.js +160 -0
  26. package/dist/services/claudeTasks.js.map +1 -0
  27. package/dist/services/config.d.ts +3 -0
  28. package/dist/services/config.js +25 -0
  29. package/dist/services/config.js.map +1 -0
  30. package/dist/services/git.d.ts +8 -0
  31. package/dist/services/git.js +90 -0
  32. package/dist/services/git.js.map +1 -0
  33. package/dist/services/jira.d.ts +11 -0
  34. package/dist/services/jira.js +52 -0
  35. package/dist/services/jira.js.map +1 -0
  36. package/dist/services/linear.d.ts +9 -0
  37. package/dist/services/linear.js +69 -0
  38. package/dist/services/linear.js.map +1 -0
  39. package/dist/services/rules.d.ts +14 -0
  40. package/dist/services/rules.js +133 -0
  41. package/dist/services/rules.js.map +1 -0
  42. package/dist/services/taskStore.d.ts +27 -0
  43. package/dist/services/taskStore.js +261 -0
  44. package/dist/services/taskStore.js.map +1 -0
  45. package/dist/services/tunnel.d.ts +8 -0
  46. package/dist/services/tunnel.js +152 -0
  47. package/dist/services/tunnel.js.map +1 -0
  48. package/dist/services/watcher.d.ts +2 -0
  49. package/dist/services/watcher.js +30 -0
  50. package/dist/services/watcher.js.map +1 -0
  51. package/dist/types/index.d.ts +87 -0
  52. package/dist/types/index.js +3 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/package.json +53 -0
  55. package/public/css/style.css +1613 -0
  56. package/public/index.html +395 -0
  57. package/public/js/app.js +104 -0
  58. package/public/js/diff.js +337 -0
  59. package/public/js/integrations.js +194 -0
  60. package/public/js/rules.js +174 -0
  61. package/public/js/tasks.js +301 -0
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createTaskStore = createTaskStore;
7
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const crypto_1 = __importDefault(require("crypto"));
11
+ const ARCHIVE_AFTER_MS = 60 * 60 * 1000; // 1 hour
12
+ function createTaskStore(projectDir) {
13
+ const devlensDir = path_1.default.join(projectDir, '.devlens');
14
+ if (!fs_1.default.existsSync(devlensDir)) {
15
+ fs_1.default.mkdirSync(devlensDir, { recursive: true });
16
+ }
17
+ const dbPath = path_1.default.join(devlensDir, 'devlens.db');
18
+ const db = new better_sqlite3_1.default(dbPath);
19
+ // Enable WAL mode for better concurrent read performance
20
+ db.pragma('journal_mode = WAL');
21
+ // Create tables
22
+ db.exec(`
23
+ CREATE TABLE IF NOT EXISTS tasks (
24
+ id TEXT PRIMARY KEY,
25
+ title TEXT NOT NULL,
26
+ description TEXT DEFAULT '',
27
+ status TEXT DEFAULT 'pending',
28
+ priority TEXT DEFAULT 'medium',
29
+ tags TEXT DEFAULT '[]',
30
+ dependencies TEXT DEFAULT '[]',
31
+ created_at TEXT NOT NULL,
32
+ updated_at TEXT NOT NULL,
33
+ completed_at TEXT,
34
+ source TEXT DEFAULT 'local',
35
+ claude_session_id TEXT,
36
+ claude_task_id TEXT,
37
+ active_form TEXT,
38
+ owner TEXT,
39
+ metadata TEXT,
40
+ context TEXT,
41
+ completion_context TEXT
42
+ )
43
+ `);
44
+ // Migration: add column if missing (for existing DBs)
45
+ try {
46
+ db.exec('ALTER TABLE tasks ADD COLUMN completion_context TEXT');
47
+ }
48
+ catch { }
49
+ db.exec(`
50
+ CREATE TABLE IF NOT EXISTS sessions (
51
+ session_id TEXT PRIMARY KEY,
52
+ name TEXT,
53
+ cwd TEXT,
54
+ pid INTEGER,
55
+ started_at TEXT,
56
+ last_seen_at TEXT,
57
+ status TEXT DEFAULT 'active',
58
+ task_count INTEGER DEFAULT 0
59
+ )
60
+ `);
61
+ // Prepared statements — tasks
62
+ const insertStmt = db.prepare(`
63
+ INSERT INTO tasks (id, title, description, status, priority, tags, dependencies, created_at, updated_at, source)
64
+ VALUES (@id, @title, @description, @status, @priority, @tags, @dependencies, @created_at, @updated_at, @source)
65
+ `);
66
+ const selectAllStmt = db.prepare('SELECT * FROM tasks ORDER BY created_at DESC');
67
+ const selectByStatusStmt = db.prepare('SELECT * FROM tasks WHERE status = ? ORDER BY created_at DESC');
68
+ const selectBySessionStmt = db.prepare('SELECT * FROM tasks WHERE claude_session_id = ? ORDER BY created_at DESC');
69
+ const selectByStatusAndSessionStmt = db.prepare('SELECT * FROM tasks WHERE status = ? AND claude_session_id = ? ORDER BY created_at DESC');
70
+ const selectByIdStmt = db.prepare('SELECT * FROM tasks WHERE id = ?');
71
+ const deleteStmt = db.prepare('DELETE FROM tasks WHERE id = ?');
72
+ // Prepared statements — sessions
73
+ const upsertSessionStmt = db.prepare(`
74
+ INSERT INTO sessions (session_id, name, cwd, pid, started_at, last_seen_at, status, task_count)
75
+ VALUES (@session_id, @name, @cwd, @pid, @started_at, @last_seen_at, @status, @task_count)
76
+ ON CONFLICT(session_id) DO UPDATE SET
77
+ name = COALESCE(@name, sessions.name),
78
+ cwd = COALESCE(@cwd, sessions.cwd),
79
+ pid = COALESCE(@pid, sessions.pid),
80
+ started_at = COALESCE(@started_at, sessions.started_at),
81
+ last_seen_at = @last_seen_at,
82
+ status = @status,
83
+ task_count = (SELECT COUNT(*) FROM tasks WHERE claude_session_id = @session_id)
84
+ `);
85
+ const selectAllSessionsStmt = db.prepare('SELECT * FROM sessions ORDER BY last_seen_at DESC');
86
+ const updateSessionStatusStmt = db.prepare('UPDATE sessions SET status = ?, last_seen_at = ? WHERE session_id = ?');
87
+ // Auto-archive completed tasks older than 1 hour
88
+ const archiveStmt = db.prepare(`
89
+ UPDATE tasks SET status = 'archived', updated_at = ?
90
+ WHERE status = 'completed' AND completed_at IS NOT NULL
91
+ AND (julianday(?) - julianday(completed_at)) * 86400000 > ?
92
+ `);
93
+ function rowToTask(row) {
94
+ return {
95
+ id: row.id,
96
+ title: row.title,
97
+ description: row.description || '',
98
+ status: row.status,
99
+ priority: row.priority,
100
+ tags: JSON.parse(row.tags || '[]'),
101
+ dependencies: JSON.parse(row.dependencies || '[]'),
102
+ createdAt: row.created_at,
103
+ updatedAt: row.updated_at,
104
+ completedAt: row.completed_at || undefined,
105
+ source: row.source || 'local',
106
+ claudeSessionId: row.claude_session_id || undefined,
107
+ claudeTaskId: row.claude_task_id || undefined,
108
+ activeForm: row.active_form || undefined,
109
+ owner: row.owner || undefined,
110
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
111
+ context: row.context || undefined,
112
+ completionContext: row.completion_context || undefined,
113
+ };
114
+ }
115
+ return {
116
+ async getTasks(filter) {
117
+ // Auto-archive old completed tasks
118
+ const now = new Date().toISOString();
119
+ archiveStmt.run(now, now, ARCHIVE_AFTER_MS);
120
+ let rows;
121
+ if (filter?.status && filter?.sessionId) {
122
+ rows = selectByStatusAndSessionStmt.all(filter.status, filter.sessionId);
123
+ }
124
+ else if (filter?.sessionId) {
125
+ rows = selectBySessionStmt.all(filter.sessionId);
126
+ }
127
+ else if (filter?.status) {
128
+ rows = selectByStatusStmt.all(filter.status);
129
+ }
130
+ else {
131
+ rows = selectAllStmt.all();
132
+ }
133
+ return rows.map(rowToTask);
134
+ },
135
+ async getTask(id) {
136
+ const row = selectByIdStmt.get(id);
137
+ return row ? rowToTask(row) : null;
138
+ },
139
+ async createTask(input) {
140
+ const now = new Date().toISOString();
141
+ const id = crypto_1.default.randomUUID();
142
+ insertStmt.run({
143
+ id,
144
+ title: input.title,
145
+ description: input.description || '',
146
+ status: input.status || 'pending',
147
+ priority: input.priority || 'medium',
148
+ tags: JSON.stringify(input.tags || []),
149
+ dependencies: JSON.stringify(input.dependencies || []),
150
+ created_at: now,
151
+ updated_at: now,
152
+ source: 'local',
153
+ });
154
+ return rowToTask(selectByIdStmt.get(id));
155
+ },
156
+ async updateTask(id, input) {
157
+ const existing = selectByIdStmt.get(id);
158
+ if (!existing)
159
+ throw new Error('Task not found');
160
+ const updates = [];
161
+ const values = { id };
162
+ if (input.title !== undefined) {
163
+ updates.push('title = @title');
164
+ values.title = input.title;
165
+ }
166
+ if (input.description !== undefined) {
167
+ updates.push('description = @description');
168
+ values.description = input.description;
169
+ }
170
+ if (input.status !== undefined) {
171
+ updates.push('status = @status');
172
+ values.status = input.status;
173
+ // Track completion time
174
+ if (input.status === 'completed' && existing.status !== 'completed') {
175
+ updates.push('completed_at = @completed_at');
176
+ values.completed_at = new Date().toISOString();
177
+ }
178
+ }
179
+ if (input.priority !== undefined) {
180
+ updates.push('priority = @priority');
181
+ values.priority = input.priority;
182
+ }
183
+ if (input.tags !== undefined) {
184
+ updates.push('tags = @tags');
185
+ values.tags = JSON.stringify(input.tags);
186
+ }
187
+ if (input.dependencies !== undefined) {
188
+ updates.push('dependencies = @dependencies');
189
+ values.dependencies = JSON.stringify(input.dependencies);
190
+ }
191
+ // Claude-specific fields
192
+ if (input.claudeSessionId !== undefined) {
193
+ updates.push('claude_session_id = @claude_session_id');
194
+ values.claude_session_id = input.claudeSessionId;
195
+ }
196
+ if (input.claudeTaskId !== undefined) {
197
+ updates.push('claude_task_id = @claude_task_id');
198
+ values.claude_task_id = input.claudeTaskId;
199
+ }
200
+ if (input.activeForm !== undefined) {
201
+ updates.push('active_form = @active_form');
202
+ values.active_form = input.activeForm;
203
+ }
204
+ if (input.owner !== undefined) {
205
+ updates.push('owner = @owner');
206
+ values.owner = input.owner;
207
+ }
208
+ if (input.metadata !== undefined) {
209
+ updates.push('metadata = @metadata');
210
+ values.metadata = JSON.stringify(input.metadata);
211
+ }
212
+ if (input.context !== undefined) {
213
+ updates.push('context = @context');
214
+ values.context = input.context;
215
+ }
216
+ if (input.completionContext !== undefined) {
217
+ updates.push('completion_context = @completion_context');
218
+ values.completion_context = input.completionContext;
219
+ }
220
+ updates.push('updated_at = @updated_at');
221
+ values.updated_at = new Date().toISOString();
222
+ if (updates.length > 1) {
223
+ db.prepare(`UPDATE tasks SET ${updates.join(', ')} WHERE id = @id`).run(values);
224
+ }
225
+ return rowToTask(selectByIdStmt.get(id));
226
+ },
227
+ async deleteTask(id) {
228
+ deleteStmt.run(id);
229
+ },
230
+ upsertSession(info) {
231
+ const now = new Date().toISOString();
232
+ upsertSessionStmt.run({
233
+ session_id: info.sessionId,
234
+ name: info.name || null,
235
+ cwd: info.cwd || null,
236
+ pid: info.pid || null,
237
+ started_at: info.startedAt || null,
238
+ last_seen_at: now,
239
+ status: info.status || 'active',
240
+ task_count: 0,
241
+ });
242
+ },
243
+ getSessions() {
244
+ const rows = selectAllSessionsStmt.all();
245
+ return rows.map(r => ({
246
+ sessionId: r.session_id,
247
+ name: r.name || undefined,
248
+ cwd: r.cwd || undefined,
249
+ pid: r.pid || undefined,
250
+ startedAt: r.started_at || undefined,
251
+ lastSeenAt: r.last_seen_at,
252
+ status: r.status,
253
+ taskCount: r.task_count,
254
+ }));
255
+ },
256
+ updateSessionStatus(sessionId, status) {
257
+ updateSessionStatusStmt.run(status, new Date().toISOString(), sessionId);
258
+ },
259
+ };
260
+ }
261
+ //# sourceMappingURL=taskStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taskStore.js","sourceRoot":"","sources":["../../src/services/taskStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function getTunnelStatus(): {
2
+ provider: "cloudflare" | "ngrok" | null;
3
+ url: string | null;
4
+ status: "error" | "disconnected" | "connecting" | "connected";
5
+ error: string | undefined;
6
+ };
7
+ export declare function startTunnel(port: number, provider?: 'cloudflare' | 'ngrok'): Promise<string>;
8
+ export declare function stopTunnel(): void;
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTunnelStatus = getTunnelStatus;
4
+ exports.startTunnel = startTunnel;
5
+ exports.stopTunnel = stopTunnel;
6
+ const child_process_1 = require("child_process");
7
+ const state = {
8
+ provider: null,
9
+ url: null,
10
+ process: null,
11
+ status: 'disconnected',
12
+ };
13
+ function getTunnelStatus() {
14
+ return {
15
+ provider: state.provider,
16
+ url: state.url,
17
+ status: state.status,
18
+ error: state.error,
19
+ };
20
+ }
21
+ function startTunnel(port, provider = 'cloudflare') {
22
+ // Stop existing tunnel first
23
+ stopTunnel();
24
+ state.provider = provider;
25
+ state.status = 'connecting';
26
+ state.error = undefined;
27
+ if (provider === 'ngrok') {
28
+ return startNgrok(port);
29
+ }
30
+ return startCloudflare(port);
31
+ }
32
+ function startCloudflare(port) {
33
+ return new Promise((resolve, reject) => {
34
+ try {
35
+ state.process = (0, child_process_1.spawn)('cloudflared', ['tunnel', '--url', `http://localhost:${port}`], {
36
+ stdio: ['ignore', 'pipe', 'pipe'],
37
+ });
38
+ }
39
+ catch {
40
+ state.status = 'error';
41
+ state.error = 'cloudflared not installed';
42
+ reject(new Error('cloudflared is not installed. Install: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/'));
43
+ return;
44
+ }
45
+ let resolved = false;
46
+ const urlRegex = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
47
+ const handleOutput = (data) => {
48
+ const text = data.toString();
49
+ if (!resolved) {
50
+ const match = text.match(urlRegex);
51
+ if (match) {
52
+ resolved = true;
53
+ state.url = match[0];
54
+ state.status = 'connected';
55
+ resolve(match[0]);
56
+ }
57
+ }
58
+ };
59
+ state.process.stdout?.on('data', handleOutput);
60
+ state.process.stderr?.on('data', handleOutput);
61
+ state.process.on('error', (err) => {
62
+ if (!resolved) {
63
+ resolved = true;
64
+ state.status = 'error';
65
+ state.error = err.message;
66
+ reject(new Error(`cloudflared failed: ${err.message}`));
67
+ }
68
+ });
69
+ state.process.on('exit', (code) => {
70
+ state.status = 'disconnected';
71
+ state.url = null;
72
+ if (!resolved) {
73
+ resolved = true;
74
+ reject(new Error(`cloudflared exited with code ${code}`));
75
+ }
76
+ });
77
+ setTimeout(() => {
78
+ if (!resolved) {
79
+ resolved = true;
80
+ state.status = 'error';
81
+ state.error = 'Tunnel setup timed out';
82
+ reject(new Error('Tunnel setup timed out'));
83
+ }
84
+ }, 15000);
85
+ });
86
+ }
87
+ function startNgrok(port) {
88
+ return new Promise((resolve, reject) => {
89
+ try {
90
+ state.process = (0, child_process_1.spawn)('ngrok', ['http', String(port), '--log=stdout'], {
91
+ stdio: ['ignore', 'pipe', 'pipe'],
92
+ });
93
+ }
94
+ catch {
95
+ state.status = 'error';
96
+ state.error = 'ngrok not installed';
97
+ reject(new Error('ngrok is not installed. Install: https://ngrok.com/download'));
98
+ return;
99
+ }
100
+ let resolved = false;
101
+ const urlRegex = /https:\/\/[a-z0-9-]+\.ngrok[a-z-]*\.[a-z]+/;
102
+ const handleOutput = (data) => {
103
+ const text = data.toString();
104
+ if (!resolved) {
105
+ const match = text.match(urlRegex);
106
+ if (match) {
107
+ resolved = true;
108
+ state.url = match[0];
109
+ state.status = 'connected';
110
+ resolve(match[0]);
111
+ }
112
+ }
113
+ };
114
+ state.process.stdout?.on('data', handleOutput);
115
+ state.process.stderr?.on('data', handleOutput);
116
+ state.process.on('error', (err) => {
117
+ if (!resolved) {
118
+ resolved = true;
119
+ state.status = 'error';
120
+ state.error = err.message;
121
+ reject(new Error(`ngrok failed: ${err.message}`));
122
+ }
123
+ });
124
+ state.process.on('exit', (code) => {
125
+ state.status = 'disconnected';
126
+ state.url = null;
127
+ if (!resolved) {
128
+ resolved = true;
129
+ reject(new Error(`ngrok exited with code ${code}`));
130
+ }
131
+ });
132
+ setTimeout(() => {
133
+ if (!resolved) {
134
+ resolved = true;
135
+ state.status = 'error';
136
+ state.error = 'Tunnel setup timed out';
137
+ reject(new Error('Tunnel setup timed out'));
138
+ }
139
+ }, 15000);
140
+ });
141
+ }
142
+ function stopTunnel() {
143
+ if (state.process) {
144
+ state.process.kill();
145
+ state.process = null;
146
+ }
147
+ state.url = null;
148
+ state.status = 'disconnected';
149
+ state.provider = null;
150
+ state.error = undefined;
151
+ }
152
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/services/tunnel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import chokidar from 'chokidar';
2
+ export declare function createWatcher(projectDir: string, onChange: () => void): chokidar.FSWatcher;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createWatcher = createWatcher;
7
+ const chokidar_1 = __importDefault(require("chokidar"));
8
+ function createWatcher(projectDir, onChange) {
9
+ let debounceTimer = null;
10
+ const watcher = chokidar_1.default.watch(projectDir, {
11
+ ignored: [
12
+ /(^|[\/\\])\../, // dotfiles
13
+ '**/node_modules/**',
14
+ '**/.git/**',
15
+ '**/.devlens/**',
16
+ ],
17
+ persistent: true,
18
+ ignoreInitial: true,
19
+ });
20
+ const debouncedOnChange = () => {
21
+ if (debounceTimer)
22
+ clearTimeout(debounceTimer);
23
+ debounceTimer = setTimeout(onChange, 300);
24
+ };
25
+ watcher.on('change', debouncedOnChange);
26
+ watcher.on('add', debouncedOnChange);
27
+ watcher.on('unlink', debouncedOnChange);
28
+ return watcher;
29
+ }
30
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/services/watcher.ts"],"names":[],"mappings":";;;;;AAEA,sCAwBC;AA1BD,wDAAgC;AAEhC,SAAgB,aAAa,CAAC,UAAkB,EAAE,QAAoB;IACpE,IAAI,aAAa,GAA0B,IAAI,CAAC;IAEhD,MAAM,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,UAAU,EAAE;QACzC,OAAO,EAAE;YACP,eAAe,EAAQ,WAAW;YAClC,oBAAoB;YACpB,YAAY;YACZ,gBAAgB;SACjB;QACD,UAAU,EAAE,IAAI;QAChB,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,aAAa;YAAE,YAAY,CAAC,aAAa,CAAC,CAAC;QAC/C,aAAa,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAExC,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,87 @@
1
+ export interface ServerOptions {
2
+ port: number;
3
+ projectDir: string;
4
+ openBrowser: boolean;
5
+ tunnel: boolean;
6
+ }
7
+ export interface FileStatus {
8
+ path: string;
9
+ status: 'modified' | 'added' | 'deleted' | 'renamed' | 'untracked';
10
+ staged: boolean;
11
+ }
12
+ export interface LogEntry {
13
+ hash: string;
14
+ message: string;
15
+ author: string;
16
+ date: string;
17
+ }
18
+ export interface Task {
19
+ id: string;
20
+ title: string;
21
+ description: string;
22
+ status: 'pending' | 'in-progress' | 'completed' | 'archived';
23
+ priority: 'low' | 'medium' | 'high';
24
+ tags: string[];
25
+ dependencies: string[];
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ completedAt?: string;
29
+ source: 'local';
30
+ claudeSessionId?: string;
31
+ claudeTaskId?: string;
32
+ activeForm?: string;
33
+ owner?: string;
34
+ metadata?: Record<string, any>;
35
+ context?: string;
36
+ completionContext?: string;
37
+ }
38
+ export interface CreateTaskInput {
39
+ title: string;
40
+ description?: string;
41
+ status?: Task['status'];
42
+ priority?: Task['priority'];
43
+ tags?: string[];
44
+ dependencies?: string[];
45
+ }
46
+ export interface UpdateTaskInput {
47
+ title?: string;
48
+ description?: string;
49
+ status?: Task['status'];
50
+ priority?: Task['priority'];
51
+ tags?: string[];
52
+ dependencies?: string[];
53
+ }
54
+ export interface TaskStore {
55
+ version: 1;
56
+ tasks: Task[];
57
+ }
58
+ export interface ExternalTask {
59
+ id: string;
60
+ externalId: string;
61
+ title: string;
62
+ description: string;
63
+ status: 'pending' | 'in-progress' | 'completed';
64
+ priority: 'low' | 'medium' | 'high';
65
+ source: 'jira' | 'linear';
66
+ url: string;
67
+ assignee?: string;
68
+ }
69
+ export interface DevlensConfig {
70
+ jira?: {
71
+ baseUrl: string;
72
+ email: string;
73
+ apiToken: string;
74
+ projectKey: string;
75
+ };
76
+ linear?: {
77
+ apiKey: string;
78
+ teamId?: string;
79
+ };
80
+ tunnel?: {
81
+ enabled: boolean;
82
+ };
83
+ }
84
+ export interface WsMessage {
85
+ type: 'file-changed' | 'diff-update' | 'status-update' | 'task-update' | 'todo-update' | 'claude-tasks-update' | 'rules-update' | 'commit-approval-update';
86
+ payload: unknown;
87
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@ycniuqton/devlens",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Developer dashboard with real-time git diffs, task board, and external integrations",
8
+ "bin": {
9
+ "devlens": "./bin/devlens.js"
10
+ },
11
+ "main": "dist/index.js",
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "git",
20
+ "diff",
21
+ "dashboard",
22
+ "kanban",
23
+ "devtools"
24
+ ],
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/ycniuqton/Devlens.git"
29
+ },
30
+ "homepage": "https://github.com/ycniuqton/Devlens#readme",
31
+ "dependencies": {
32
+ "better-sqlite3": "^12.8.0",
33
+ "chokidar": "^3.6.0",
34
+ "commander": "^12.0.0",
35
+ "diff2html": "^3.4.47",
36
+ "express": "^4.18.2",
37
+ "open": "^10.1.0",
38
+ "simple-git": "^3.22.0",
39
+ "ws": "^8.16.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/better-sqlite3": "^7.6.13",
43
+ "@types/express": "^4.17.21",
44
+ "@types/node": "^20.11.0",
45
+ "@types/ws": "^8.5.10",
46
+ "typescript": "^5.3.3"
47
+ },
48
+ "files": [
49
+ "dist/",
50
+ "bin/",
51
+ "public/"
52
+ ]
53
+ }