@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,160 @@
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.getTodos = getTodos;
7
+ exports.upsertTodo = upsertTodo;
8
+ exports.clearTodos = clearTodos;
9
+ exports.parseTodoWritePayload = parseTodoWritePayload;
10
+ exports.watchClaudeTasks = watchClaudeTasks;
11
+ exports.readClaudeSessions = readClaudeSessions;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const os_1 = __importDefault(require("os"));
15
+ const chokidar_1 = __importDefault(require("chokidar"));
16
+ // In-memory store for todos received via hooks
17
+ const todos = new Map();
18
+ function getTodos() {
19
+ return Array.from(todos.values());
20
+ }
21
+ function upsertTodo(todo) {
22
+ todos.set(todo.id, todo);
23
+ }
24
+ function clearTodos() {
25
+ todos.clear();
26
+ }
27
+ // Parse a TodoWrite hook payload into our todo format
28
+ function parseTodoWritePayload(toolInput) {
29
+ if (!toolInput)
30
+ return [];
31
+ const result = [];
32
+ const items = toolInput.todos || toolInput.items || (Array.isArray(toolInput) ? toolInput : [toolInput]);
33
+ for (const item of items) {
34
+ if (!item)
35
+ continue;
36
+ result.push({
37
+ id: item.id || String(result.length),
38
+ content: item.content || item.subject || item.title || item.text || JSON.stringify(item),
39
+ status: mapTodoStatus(item.status),
40
+ priority: item.priority,
41
+ updatedAt: new Date().toISOString(),
42
+ });
43
+ }
44
+ return result;
45
+ }
46
+ function mapTodoStatus(status) {
47
+ if (!status)
48
+ return 'pending';
49
+ const s = status.toLowerCase();
50
+ if (s.includes('progress') || s === 'in_progress')
51
+ return 'in_progress';
52
+ if (s.includes('complet') || s === 'done')
53
+ return 'completed';
54
+ return 'pending';
55
+ }
56
+ // Watch ~/.claude/tasks/ and ~/.claude/sessions/ for changes
57
+ function watchClaudeTasks(onChange) {
58
+ const claudeDir = path_1.default.join(os_1.default.homedir(), '.claude');
59
+ const tasksDir = path_1.default.join(claudeDir, 'tasks');
60
+ const sessionsDir = path_1.default.join(claudeDir, 'sessions');
61
+ if (!fs_1.default.existsSync(tasksDir))
62
+ return null;
63
+ let debounceTimer = null;
64
+ const watchPaths = [tasksDir];
65
+ if (fs_1.default.existsSync(sessionsDir))
66
+ watchPaths.push(sessionsDir);
67
+ const watcher = chokidar_1.default.watch(watchPaths, {
68
+ persistent: true,
69
+ ignoreInitial: true,
70
+ depth: 2,
71
+ });
72
+ const debouncedOnChange = () => {
73
+ if (debounceTimer)
74
+ clearTimeout(debounceTimer);
75
+ debounceTimer = setTimeout(() => {
76
+ const sessions = readClaudeSessions();
77
+ onChange(sessions);
78
+ }, 300);
79
+ };
80
+ watcher.on('change', debouncedOnChange);
81
+ watcher.on('add', debouncedOnChange);
82
+ watcher.on('unlink', debouncedOnChange);
83
+ return watcher;
84
+ }
85
+ // Read session metadata from ~/.claude/sessions/*.json
86
+ function readSessionMetadata() {
87
+ const sessionsDir = path_1.default.join(os_1.default.homedir(), '.claude', 'sessions');
88
+ const metadata = new Map();
89
+ if (!fs_1.default.existsSync(sessionsDir))
90
+ return metadata;
91
+ try {
92
+ const files = fs_1.default.readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
93
+ for (const file of files) {
94
+ try {
95
+ const data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(sessionsDir, file), 'utf-8'));
96
+ if (data.sessionId) {
97
+ // Keep the latest entry per sessionId (multiple PIDs may share a session)
98
+ const existing = metadata.get(data.sessionId);
99
+ if (!existing || (data.startedAt && (!existing.startedAt || data.startedAt > existing.startedAt))) {
100
+ metadata.set(data.sessionId, {
101
+ name: data.name,
102
+ cwd: data.cwd,
103
+ pid: data.pid,
104
+ startedAt: data.startedAt,
105
+ });
106
+ }
107
+ }
108
+ }
109
+ catch { }
110
+ }
111
+ }
112
+ catch { }
113
+ return metadata;
114
+ }
115
+ // Read all Claude sessions with correlated metadata
116
+ function readClaudeSessions() {
117
+ const tasksDir = path_1.default.join(os_1.default.homedir(), '.claude', 'tasks');
118
+ if (!fs_1.default.existsSync(tasksDir))
119
+ return [];
120
+ const sessionMeta = readSessionMetadata();
121
+ const sessions = [];
122
+ try {
123
+ const entries = fs_1.default.readdirSync(tasksDir, { withFileTypes: true });
124
+ for (const entry of entries) {
125
+ if (!entry.isDirectory())
126
+ continue;
127
+ const sessionDir = path_1.default.join(tasksDir, entry.name);
128
+ const hwFile = path_1.default.join(sessionDir, '.highwatermark');
129
+ const lockFile = path_1.default.join(sessionDir, '.lock');
130
+ let taskCount = 0;
131
+ if (fs_1.default.existsSync(hwFile)) {
132
+ try {
133
+ taskCount = parseInt(fs_1.default.readFileSync(hwFile, 'utf-8').trim(), 10) || 0;
134
+ }
135
+ catch { }
136
+ }
137
+ const meta = sessionMeta.get(entry.name);
138
+ sessions.push({
139
+ sessionId: entry.name,
140
+ name: meta?.name,
141
+ cwd: meta?.cwd,
142
+ pid: meta?.pid,
143
+ startedAt: meta?.startedAt ? new Date(meta.startedAt).toISOString() : undefined,
144
+ taskCount,
145
+ active: fs_1.default.existsSync(lockFile),
146
+ });
147
+ }
148
+ }
149
+ catch { }
150
+ // Sort: active first, then by startedAt descending
151
+ sessions.sort((a, b) => {
152
+ if (a.active !== b.active)
153
+ return b.active ? 1 : -1;
154
+ if (a.startedAt && b.startedAt)
155
+ return b.startedAt.localeCompare(a.startedAt);
156
+ return 0;
157
+ });
158
+ return sessions;
159
+ }
160
+ //# sourceMappingURL=claudeTasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeTasks.js","sourceRoot":"","sources":["../../src/services/claudeTasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { DevlensConfig } from '../types';
2
+ export declare function loadConfig(projectDir: string): DevlensConfig;
3
+ export declare function saveConfig(projectDir: string, config: DevlensConfig): void;
@@ -0,0 +1,25 @@
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.loadConfig = loadConfig;
7
+ exports.saveConfig = saveConfig;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function loadConfig(projectDir) {
11
+ const configFile = path_1.default.join(projectDir, '.devlens', 'config.json');
12
+ if (!fs_1.default.existsSync(configFile)) {
13
+ return {};
14
+ }
15
+ return JSON.parse(fs_1.default.readFileSync(configFile, 'utf-8'));
16
+ }
17
+ function saveConfig(projectDir, config) {
18
+ const devlensDir = path_1.default.join(projectDir, '.devlens');
19
+ if (!fs_1.default.existsSync(devlensDir)) {
20
+ fs_1.default.mkdirSync(devlensDir, { recursive: true });
21
+ }
22
+ const configFile = path_1.default.join(devlensDir, 'config.json');
23
+ fs_1.default.writeFileSync(configFile, JSON.stringify(config, null, 2));
24
+ }
25
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/services/config.ts"],"names":[],"mappings":";;;;;AAIA,gCAMC;AAED,gCAOC;AAnBD,4CAAoB;AACpB,gDAAwB;AAGxB,SAAgB,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IACpE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,SAAgB,UAAU,CAAC,UAAkB,EAAE,MAAqB;IAClE,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACrD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,YAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACxD,YAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { FileStatus, LogEntry } from '../types';
2
+ export interface GitService {
3
+ getDiff(filter?: string): Promise<string>;
4
+ getStatus(): Promise<FileStatus[]>;
5
+ getLog(limit?: number): Promise<LogEntry[]>;
6
+ isRepo(): Promise<boolean>;
7
+ }
8
+ export declare function createGitService(projectDir: string): GitService;
@@ -0,0 +1,90 @@
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.createGitService = createGitService;
7
+ const simple_git_1 = __importDefault(require("simple-git"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function createGitService(projectDir) {
11
+ const git = (0, simple_git_1.default)(projectDir);
12
+ // Generate a unified diff for an untracked file (show as all-new)
13
+ function makeUntrackedDiff(filePath) {
14
+ try {
15
+ const fullPath = path_1.default.join(projectDir, filePath);
16
+ const content = fs_1.default.readFileSync(fullPath, 'utf-8');
17
+ const lines = content.split('\n');
18
+ const added = lines.map(l => '+' + l).join('\n');
19
+ return `diff --git a/${filePath} b/${filePath}\nnew file mode 100644\n--- /dev/null\n+++ b/${filePath}\n@@ -0,0 +1,${lines.length} @@\n${added}`;
20
+ }
21
+ catch {
22
+ return '';
23
+ }
24
+ }
25
+ return {
26
+ async getDiff(filter) {
27
+ let diff = '';
28
+ if (filter === 'staged') {
29
+ diff = await git.diff(['--cached']);
30
+ }
31
+ else if (filter === 'unstaged') {
32
+ diff = await git.diff();
33
+ }
34
+ else {
35
+ const unstaged = await git.diff();
36
+ const staged = await git.diff(['--cached']);
37
+ diff = [unstaged, staged].filter(Boolean).join('\n');
38
+ }
39
+ // Include untracked files as new-file diffs
40
+ if (filter !== 'staged') {
41
+ const status = await git.status();
42
+ for (const f of status.not_added) {
43
+ const untrackedDiff = makeUntrackedDiff(f);
44
+ if (untrackedDiff) {
45
+ diff = diff ? diff + '\n' + untrackedDiff : untrackedDiff;
46
+ }
47
+ }
48
+ }
49
+ return diff;
50
+ },
51
+ async getStatus() {
52
+ const status = await git.status();
53
+ const files = [];
54
+ for (const f of status.modified) {
55
+ files.push({ path: f, status: 'modified', staged: false });
56
+ }
57
+ for (const f of status.not_added) {
58
+ files.push({ path: f, status: 'untracked', staged: false });
59
+ }
60
+ for (const f of status.deleted) {
61
+ files.push({ path: f, status: 'deleted', staged: false });
62
+ }
63
+ for (const f of status.created) {
64
+ files.push({ path: f, status: 'added', staged: true });
65
+ }
66
+ for (const f of status.staged) {
67
+ if (!files.some(x => x.path === f)) {
68
+ files.push({ path: f, status: 'modified', staged: true });
69
+ }
70
+ }
71
+ for (const f of status.renamed) {
72
+ files.push({ path: f.to, status: 'renamed', staged: true });
73
+ }
74
+ return files;
75
+ },
76
+ async getLog(limit = 20) {
77
+ const log = await git.log({ maxCount: limit });
78
+ return log.all.map((entry) => ({
79
+ hash: entry.hash.substring(0, 8),
80
+ message: entry.message,
81
+ author: entry.author_name,
82
+ date: entry.date,
83
+ }));
84
+ },
85
+ async isRepo() {
86
+ return git.checkIsRepo();
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { ExternalTask } from '../types';
2
+ interface JiraConfig {
3
+ baseUrl: string;
4
+ email: string;
5
+ apiToken: string;
6
+ projectKey: string;
7
+ }
8
+ export declare function createJiraClient(config: JiraConfig): {
9
+ getIssues(jql?: string): Promise<ExternalTask[]>;
10
+ };
11
+ export {};
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createJiraClient = createJiraClient;
4
+ function createJiraClient(config) {
5
+ const auth = Buffer.from(`${config.email}:${config.apiToken}`).toString('base64');
6
+ async function fetchJira(endpoint) {
7
+ const url = `${config.baseUrl}/rest/api/3${endpoint}`;
8
+ const res = await fetch(url, {
9
+ headers: {
10
+ 'Authorization': `Basic ${auth}`,
11
+ 'Accept': 'application/json',
12
+ },
13
+ });
14
+ if (!res.ok)
15
+ throw new Error(`Jira API error: ${res.status}`);
16
+ return res.json();
17
+ }
18
+ function mapStatus(jiraStatus) {
19
+ const lower = jiraStatus.toLowerCase();
20
+ if (lower.includes('done') || lower.includes('closed') || lower.includes('resolved'))
21
+ return 'completed';
22
+ if (lower.includes('progress') || lower.includes('review'))
23
+ return 'in-progress';
24
+ return 'pending';
25
+ }
26
+ function mapPriority(jiraPriority) {
27
+ const lower = jiraPriority.toLowerCase();
28
+ if (lower.includes('high') || lower.includes('critical') || lower.includes('blocker'))
29
+ return 'high';
30
+ if (lower.includes('low') || lower.includes('trivial'))
31
+ return 'low';
32
+ return 'medium';
33
+ }
34
+ return {
35
+ async getIssues(jql) {
36
+ const query = jql || `project = ${config.projectKey} AND status != Done ORDER BY updated DESC`;
37
+ const data = await fetchJira(`/search?jql=${encodeURIComponent(query)}&maxResults=50`);
38
+ return data.issues.map((issue) => ({
39
+ id: issue.id,
40
+ externalId: issue.key,
41
+ title: issue.fields.summary,
42
+ description: issue.fields.description?.content?.[0]?.content?.[0]?.text || '',
43
+ status: mapStatus(issue.fields.status.name),
44
+ priority: mapPriority(issue.fields.priority?.name || 'Medium'),
45
+ source: 'jira',
46
+ url: `${config.baseUrl}/browse/${issue.key}`,
47
+ assignee: issue.fields.assignee?.displayName,
48
+ }));
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=jira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../src/services/jira.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { ExternalTask } from '../types';
2
+ interface LinearConfig {
3
+ apiKey: string;
4
+ teamId?: string;
5
+ }
6
+ export declare function createLinearClient(config: LinearConfig): {
7
+ getIssues(): Promise<ExternalTask[]>;
8
+ };
9
+ export {};
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLinearClient = createLinearClient;
4
+ function createLinearClient(config) {
5
+ async function query(graphql, variables = {}) {
6
+ const res = await fetch('https://api.linear.app/graphql', {
7
+ method: 'POST',
8
+ headers: {
9
+ 'Authorization': config.apiKey,
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ body: JSON.stringify({ query: graphql, variables }),
13
+ });
14
+ if (!res.ok)
15
+ throw new Error(`Linear API error: ${res.status}`);
16
+ const data = await res.json();
17
+ if (data.errors)
18
+ throw new Error(data.errors[0].message);
19
+ return data.data;
20
+ }
21
+ function mapStatus(state) {
22
+ const lower = state.toLowerCase();
23
+ if (lower.includes('done') || lower.includes('completed') || lower.includes('canceled'))
24
+ return 'completed';
25
+ if (lower.includes('progress') || lower.includes('started') || lower.includes('review'))
26
+ return 'in-progress';
27
+ return 'pending';
28
+ }
29
+ function mapPriority(priority) {
30
+ if (priority <= 1)
31
+ return 'high';
32
+ if (priority >= 3)
33
+ return 'low';
34
+ return 'medium';
35
+ }
36
+ return {
37
+ async getIssues() {
38
+ const teamFilter = config.teamId ? `(filter: { team: { id: { eq: "${config.teamId}" } } })` : '';
39
+ const data = await query(`
40
+ query {
41
+ issues${teamFilter} {
42
+ nodes {
43
+ id
44
+ identifier
45
+ title
46
+ description
47
+ url
48
+ priority
49
+ state { name }
50
+ assignee { name }
51
+ }
52
+ }
53
+ }
54
+ `);
55
+ return data.issues.nodes.map((issue) => ({
56
+ id: issue.id,
57
+ externalId: issue.identifier,
58
+ title: issue.title,
59
+ description: issue.description || '',
60
+ status: mapStatus(issue.state?.name || 'Backlog'),
61
+ priority: mapPriority(issue.priority),
62
+ source: 'linear',
63
+ url: issue.url,
64
+ assignee: issue.assignee?.name,
65
+ }));
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=linear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear.js","sourceRoot":"","sources":["../../src/services/linear.ts"],"names":[],"mappings":";;AAOA,gDA6DC;AA7DD,SAAgB,kBAAkB,CAAC,MAAoB;IACrD,KAAK,UAAU,KAAK,CAAC,OAAe,EAAE,YAAiC,EAAE;QACvE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gCAAgC,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,MAAM,CAAC,MAAM;gBAC9B,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;SACpD,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAQ,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACzD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,SAAS,SAAS,CAAC,KAAa;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,OAAO,WAAW,CAAC;QAC5G,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,aAAa,CAAC;QAC9G,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,SAAS,WAAW,CAAC,QAAgB;QACnC,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC;QACjC,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAChC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO;QACL,KAAK,CAAC,SAAS;YACb,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,iCAAiC,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACjG,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC;;kBAEb,UAAU;;;;;;;;;;;;;OAarB,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,CAAC;gBAC5C,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,EAAE;gBACpC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS,CAAC;gBACjD,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACrC,MAAM,EAAE,QAAiB;gBACzB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI;aAC/B,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface Rule {
2
+ index: number;
3
+ content: string;
4
+ active: boolean;
5
+ protected: boolean;
6
+ }
7
+ export declare function createRulesService(projectDir: string): {
8
+ ensureDefault(): void;
9
+ getRules(): Rule[];
10
+ addRule(content: string): Rule;
11
+ removeRule(index: number): boolean;
12
+ toggleRule(index: number): Rule | null;
13
+ };
14
+ export type RulesService = ReturnType<typeof createRulesService>;
@@ -0,0 +1,133 @@
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.createRulesService = createRulesService;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const DEFAULT_RULES = `# Devlens Rules
10
+ - Do not run git commit or git push under any circumstances. Only proceed after receiving an explicit user instruction, and clearly indicate before performing the commit.
11
+ `;
12
+ function isProtected(content) {
13
+ // Protect the default git commit guard rule
14
+ const lower = content.toLowerCase();
15
+ return lower.includes('git commit') && lower.includes('git push');
16
+ }
17
+ function createRulesService(projectDir) {
18
+ const devlensDir = path_1.default.join(projectDir, '.devlens');
19
+ const rulesFile = path_1.default.join(devlensDir, 'rules.md');
20
+ function ensureFile() {
21
+ if (!fs_1.default.existsSync(devlensDir)) {
22
+ fs_1.default.mkdirSync(devlensDir, { recursive: true });
23
+ }
24
+ if (!fs_1.default.existsSync(rulesFile)) {
25
+ fs_1.default.writeFileSync(rulesFile, DEFAULT_RULES);
26
+ }
27
+ }
28
+ function readLines() {
29
+ ensureFile();
30
+ return fs_1.default.readFileSync(rulesFile, 'utf-8').split('\n');
31
+ }
32
+ function writeLines(lines) {
33
+ ensureFile();
34
+ fs_1.default.writeFileSync(rulesFile, lines.join('\n'));
35
+ }
36
+ // Parse a line into a rule. Returns null if it's not a rule line (heading/blank).
37
+ function parseLine(line, index) {
38
+ const trimmed = line.trim();
39
+ if (!trimmed || trimmed.startsWith('# '))
40
+ return null;
41
+ let content = trimmed;
42
+ let active = true;
43
+ // Inactive rules: "#- text" or "# - text"
44
+ if (trimmed.startsWith('#-') || trimmed.startsWith('# -')) {
45
+ active = false;
46
+ content = trimmed.replace(/^#\s*-\s*/, '').trim();
47
+ }
48
+ else if (trimmed.startsWith('-')) {
49
+ content = trimmed.replace(/^-\s*/, '').trim();
50
+ }
51
+ else {
52
+ return null;
53
+ }
54
+ return {
55
+ index,
56
+ content,
57
+ active,
58
+ protected: isProtected(content),
59
+ };
60
+ }
61
+ return {
62
+ ensureDefault() {
63
+ ensureFile();
64
+ },
65
+ getRules() {
66
+ const lines = readLines();
67
+ const rules = [];
68
+ lines.forEach((line, i) => {
69
+ const r = parseLine(line, i);
70
+ if (r)
71
+ rules.push(r);
72
+ });
73
+ // Re-index to consecutive numbers for stable references
74
+ return rules.map((r, i) => ({ ...r, index: i }));
75
+ },
76
+ addRule(content) {
77
+ const lines = readLines();
78
+ // Append at end with a leading "- "
79
+ if (lines[lines.length - 1] !== '')
80
+ lines.push('');
81
+ const newLine = `- ${content}`;
82
+ lines.push(newLine);
83
+ writeLines(lines);
84
+ return {
85
+ index: this.getRules().length - 1,
86
+ content,
87
+ active: true,
88
+ protected: isProtected(content),
89
+ };
90
+ },
91
+ removeRule(index) {
92
+ const lines = readLines();
93
+ const ruleLineIndices = [];
94
+ lines.forEach((line, i) => {
95
+ if (parseLine(line, i))
96
+ ruleLineIndices.push(i);
97
+ });
98
+ if (index < 0 || index >= ruleLineIndices.length)
99
+ return false;
100
+ const lineIdx = ruleLineIndices[index];
101
+ const rule = parseLine(lines[lineIdx], lineIdx);
102
+ if (rule?.protected)
103
+ return false;
104
+ lines.splice(lineIdx, 1);
105
+ writeLines(lines);
106
+ return true;
107
+ },
108
+ toggleRule(index) {
109
+ const lines = readLines();
110
+ const ruleLineIndices = [];
111
+ lines.forEach((line, i) => {
112
+ if (parseLine(line, i))
113
+ ruleLineIndices.push(i);
114
+ });
115
+ if (index < 0 || index >= ruleLineIndices.length)
116
+ return null;
117
+ const lineIdx = ruleLineIndices[index];
118
+ const rule = parseLine(lines[lineIdx], lineIdx);
119
+ if (!rule)
120
+ return null;
121
+ // Toggle: active → "#- text", inactive → "- text"
122
+ if (rule.active) {
123
+ lines[lineIdx] = `#- ${rule.content}`;
124
+ }
125
+ else {
126
+ lines[lineIdx] = `- ${rule.content}`;
127
+ }
128
+ writeLines(lines);
129
+ return { ...rule, active: !rule.active, index };
130
+ },
131
+ };
132
+ }
133
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/services/rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Task, CreateTaskInput, UpdateTaskInput } from '../types';
2
+ export interface SessionInfo {
3
+ sessionId: string;
4
+ name?: string;
5
+ cwd?: string;
6
+ pid?: number;
7
+ startedAt?: string;
8
+ lastSeenAt: string;
9
+ status: 'active' | 'ended';
10
+ taskCount: number;
11
+ }
12
+ export interface TaskStoreService {
13
+ getTasks(filter?: {
14
+ status?: string;
15
+ sessionId?: string;
16
+ }): Promise<Task[]>;
17
+ getTask(id: string): Promise<Task | null>;
18
+ createTask(input: CreateTaskInput): Promise<Task>;
19
+ updateTask(id: string, input: UpdateTaskInput & Record<string, any>): Promise<Task>;
20
+ deleteTask(id: string): Promise<void>;
21
+ upsertSession(info: Partial<SessionInfo> & {
22
+ sessionId: string;
23
+ }): void;
24
+ getSessions(): SessionInfo[];
25
+ updateSessionStatus(sessionId: string, status: 'active' | 'ended'): void;
26
+ }
27
+ export declare function createTaskStore(projectDir: string): TaskStoreService;