@ycniuqton/devlens 0.1.7 → 0.1.9

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/README.md CHANGED
@@ -21,15 +21,24 @@ Devlens gives you a web-based UI to monitor file changes, manage Claude Code tas
21
21
 
22
22
  ## Installation
23
23
 
24
- ### Global install (recommended)
24
+ ### One-liner (install + init in current project)
25
+
26
+ ```bash
27
+ npm install @ycniuqton/devlens@latest && npx devlens init
28
+ ```
29
+
30
+ Run this in any project directory — installs the latest version locally and sets up Devlens hooks for that project. Re-run anytime to upgrade.
31
+
32
+ ### Global install
25
33
 
26
34
  ```bash
27
35
  npm install -g @ycniuqton/devlens
36
+ devlens init
28
37
  ```
29
38
 
30
39
  ### Without installing — use `npx`
31
40
 
32
- > **Note:** the package is scoped, so you must use the `--package` form. Plain `npx devlens` will install an unrelated package with the same name.
41
+ > **Note:** the package is scoped. Plain `npx devlens` will install an unrelated package with the same name. Use the `--package` form:
33
42
 
34
43
  ```bash
35
44
  npx --package=@ycniuqton/devlens -- devlens init
@@ -42,8 +42,10 @@ exports.browserRouter.get('/commit/:hash', async (req, res) => {
42
42
  // GET /api/browser/files?path=... — list directory contents
43
43
  exports.browserRouter.get('/files', (req, res) => {
44
44
  const projectDir = req.app.locals.projectDir;
45
+ const settings = req.app.locals.settingsService;
45
46
  const relPath = req.query.path || '';
46
- const entries = (0, files_1.listDirectory)(projectDir, relPath);
47
+ const ignoreSet = settings ? settings.getIgnoreNameSet() : undefined;
48
+ const entries = (0, files_1.listDirectory)(projectDir, relPath, ignoreSet);
47
49
  res.json({ path: relPath, entries });
48
50
  });
49
51
  // GET /api/browser/file?path=... — read file content
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/routes/browser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/routes/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const settingsRouter: import("express-serve-static-core").Router;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.settingsRouter = void 0;
4
+ const express_1 = require("express");
5
+ exports.settingsRouter = (0, express_1.Router)();
6
+ const PRESET_PATTERNS = [
7
+ 'node_modules',
8
+ '.git',
9
+ '.devlens',
10
+ 'dist',
11
+ 'build',
12
+ '.next',
13
+ '.nuxt',
14
+ '.cache',
15
+ '.turbo',
16
+ '_bmad',
17
+ 'venv',
18
+ '.venv',
19
+ 'env',
20
+ '__pycache__',
21
+ '.pytest_cache',
22
+ 'target',
23
+ 'vendor',
24
+ 'coverage',
25
+ '.idea',
26
+ '.vscode',
27
+ ];
28
+ // GET /api/settings — current settings + presets
29
+ exports.settingsRouter.get('/', (req, res) => {
30
+ const settings = req.app.locals.settingsService;
31
+ res.json({
32
+ ignorePatterns: settings.getIgnorePatterns(),
33
+ presets: PRESET_PATTERNS,
34
+ });
35
+ });
36
+ // PUT /api/settings — replace settings
37
+ exports.settingsRouter.put('/', (req, res) => {
38
+ const settings = req.app.locals.settingsService;
39
+ const broadcast = req.app.locals.broadcast;
40
+ const reloadWatcher = req.app.locals.reloadWatcher;
41
+ const { ignorePatterns } = req.body || {};
42
+ if (!Array.isArray(ignorePatterns)) {
43
+ return res.status(400).json({ error: 'ignorePatterns must be an array' });
44
+ }
45
+ const updated = settings.updateSettings({ ignorePatterns });
46
+ // Restart the watcher with new patterns
47
+ if (reloadWatcher)
48
+ reloadWatcher();
49
+ if (broadcast)
50
+ broadcast({ type: 'settings-update', payload: updated });
51
+ res.json(updated);
52
+ });
53
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/routes/settings.ts"],"names":[],"mappings":";;;AAAA,qCAAoD;AAIvC,QAAA,cAAc,GAAG,IAAA,gBAAM,GAAE,CAAC;AAEvC,MAAM,eAAe,GAAG;IACtB,cAAc;IACd,MAAM;IACN,UAAU;IACV,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,OAAO;IACP,KAAK;IACL,aAAa;IACb,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,OAAO;IACP,SAAS;CACV,CAAC;AAEF,iDAAiD;AACjD,sBAAc,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACtD,MAAM,QAAQ,GAAoB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC;IACjE,GAAG,CAAC,IAAI,CAAC;QACP,cAAc,EAAE,QAAQ,CAAC,iBAAiB,EAAE;QAC5C,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,uCAAuC;AACvC,sBAAc,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACtD,MAAM,QAAQ,GAAoB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC;IACjE,MAAM,SAAS,GAA6B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACrE,MAAM,aAAa,GAA6B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;IAE7E,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC;IAE5D,wCAAwC;IACxC,IAAI,aAAa;QAAE,aAAa,EAAE,CAAC;IAEnC,IAAI,SAAS;QAAE,SAAS,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAS,CAAC,CAAC;IAC/E,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
package/dist/server.js CHANGED
@@ -13,11 +13,13 @@ const git_1 = require("./services/git");
13
13
  const watcher_1 = require("./services/watcher");
14
14
  const taskStore_1 = require("./services/taskStore");
15
15
  const rules_1 = require("./services/rules");
16
+ const settings_1 = require("./services/settings");
16
17
  const diff_1 = require("./routes/diff");
17
18
  const tasks_1 = require("./routes/tasks");
18
19
  const integrations_1 = require("./routes/integrations");
19
20
  const rules_2 = require("./routes/rules");
20
21
  const browser_1 = require("./routes/browser");
22
+ const settings_2 = require("./routes/settings");
21
23
  function createServer(options) {
22
24
  const app = (0, express_1.default)();
23
25
  const httpServer = http_1.default.createServer(app);
@@ -28,11 +30,13 @@ function createServer(options) {
28
30
  const gitService = (0, git_1.createGitService)(options.projectDir);
29
31
  const taskStore = (0, taskStore_1.createTaskStore)(options.projectDir);
30
32
  const rulesService = (0, rules_1.createRulesService)(options.projectDir);
33
+ const settingsService = (0, settings_1.createSettingsService)(options.projectDir);
31
34
  rulesService.ensureDefault();
32
35
  // Attach to app.locals for route access
33
36
  app.locals.gitService = gitService;
34
37
  app.locals.taskStore = taskStore;
35
38
  app.locals.rulesService = rulesService;
39
+ app.locals.settingsService = settingsService;
36
40
  app.locals.projectDir = options.projectDir;
37
41
  app.locals.port = options.port;
38
42
  // API routes
@@ -48,6 +52,7 @@ function createServer(options) {
48
52
  app.use('/api/integrations', integrations_1.integrationsRouter);
49
53
  app.use('/api/rules', rules_2.rulesRouter);
50
54
  app.use('/api/browser', browser_1.browserRouter);
55
+ app.use('/api/settings', settings_2.settingsRouter);
51
56
  // Static files
52
57
  const publicDir = path_1.default.resolve(__dirname, '../public');
53
58
  app.use(express_1.default.static(publicDir));
@@ -64,8 +69,9 @@ function createServer(options) {
64
69
  }
65
70
  });
66
71
  }
67
- // File watcher -> WebSocket broadcast
68
- const watcher = (0, watcher_1.createWatcher)(options.projectDir, async () => {
72
+ // File watcher -> WebSocket broadcast (rebuildable when settings change)
73
+ let watcher = null;
74
+ const onWatcherChange = async () => {
69
75
  try {
70
76
  const diff = await gitService.getDiff();
71
77
  const status = await gitService.getStatus();
@@ -75,7 +81,18 @@ function createServer(options) {
75
81
  catch {
76
82
  // Git service may fail if not a git repo
77
83
  }
78
- });
84
+ };
85
+ function buildWatcher() {
86
+ watcher = (0, watcher_1.createWatcher)(options.projectDir, onWatcherChange, settingsService.getChokidarIgnoreGlobs());
87
+ }
88
+ buildWatcher();
89
+ function reloadWatcher() {
90
+ if (watcher) {
91
+ watcher.close().catch(() => { });
92
+ }
93
+ buildWatcher();
94
+ }
95
+ app.locals.reloadWatcher = reloadWatcher;
79
96
  // Watch rules.md for external changes
80
97
  const rulesPath = path_1.default.join(options.projectDir, '.devlens', 'rules.md');
81
98
  const rulesWatcher = chokidar_1.default.watch(rulesPath, { ignoreInitial: true });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ export interface FileEntry {
4
4
  type: 'file' | 'dir';
5
5
  size?: number;
6
6
  }
7
- export declare function listDirectory(projectDir: string, relPath: string): FileEntry[];
7
+ export declare function listDirectory(projectDir: string, relPath: string, ignoreSet?: Set<string>): FileEntry[];
8
8
  export declare function readFile(projectDir: string, relPath: string, maxBytes?: number): {
9
9
  content: string;
10
10
  truncated: boolean;
@@ -7,13 +7,13 @@ exports.listDirectory = listDirectory;
7
7
  exports.readFile = readFile;
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
- const IGNORE = new Set(['.git', 'node_modules', '.devlens', 'dist', '.next', '.nuxt', '.cache']);
10
+ const FALLBACK_IGNORE = new Set(['.git', 'node_modules', '.devlens', 'dist', '.next', '.nuxt', '.cache']);
11
11
  function isSafePath(projectDir, target) {
12
12
  const abs = path_1.default.resolve(projectDir, target);
13
13
  const root = path_1.default.resolve(projectDir);
14
14
  return abs === root || abs.startsWith(root + path_1.default.sep);
15
15
  }
16
- function listDirectory(projectDir, relPath) {
16
+ function listDirectory(projectDir, relPath, ignoreSet) {
17
17
  if (!isSafePath(projectDir, relPath))
18
18
  return [];
19
19
  const abs = path_1.default.resolve(projectDir, relPath);
@@ -21,8 +21,9 @@ function listDirectory(projectDir, relPath) {
21
21
  return [];
22
22
  const entries = fs_1.default.readdirSync(abs, { withFileTypes: true });
23
23
  const result = [];
24
+ const ignored = ignoreSet || FALLBACK_IGNORE;
24
25
  for (const entry of entries) {
25
- if (IGNORE.has(entry.name))
26
+ if (ignored.has(entry.name))
26
27
  continue;
27
28
  if (entry.name.startsWith('.') && entry.name !== '.gitignore' && entry.name !== '.env.example')
28
29
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/services/files.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/services/files.ts"],"names":[],"mappings":"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"}
@@ -78,6 +78,7 @@ function createGitService(projectDir) {
78
78
  return log.all.map((entry) => ({
79
79
  hash: entry.hash.substring(0, 8),
80
80
  message: entry.message,
81
+ body: entry.body || '',
81
82
  author: entry.author_name,
82
83
  date: entry.date,
83
84
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface DevlensSettings {
2
+ ignorePatterns: string[];
3
+ }
4
+ export interface SettingsService {
5
+ getSettings(): DevlensSettings;
6
+ updateSettings(input: Partial<DevlensSettings>): DevlensSettings;
7
+ getIgnorePatterns(): string[];
8
+ /** Convert ignore patterns to chokidar-compatible globs */
9
+ getChokidarIgnoreGlobs(): (string | RegExp)[];
10
+ /** Convert ignore patterns to a Set of names for the file explorer */
11
+ getIgnoreNameSet(): Set<string>;
12
+ }
13
+ export declare function createSettingsService(projectDir: string): SettingsService;
@@ -0,0 +1,104 @@
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.createSettingsService = createSettingsService;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ // Common heavy/noisy directories that should be ignored by default
10
+ const DEFAULT_IGNORE_PATTERNS = [
11
+ 'node_modules',
12
+ '.git',
13
+ '.devlens',
14
+ 'dist',
15
+ 'build',
16
+ '.next',
17
+ '.nuxt',
18
+ '.cache',
19
+ '.turbo',
20
+ '_bmad',
21
+ 'venv',
22
+ '.venv',
23
+ 'env',
24
+ '__pycache__',
25
+ '.pytest_cache',
26
+ 'target', // Rust / Java
27
+ 'vendor', // Go / PHP
28
+ 'coverage',
29
+ '.idea',
30
+ '.vscode',
31
+ ];
32
+ function createSettingsService(projectDir) {
33
+ const devlensDir = path_1.default.join(projectDir, '.devlens');
34
+ const settingsFile = path_1.default.join(devlensDir, 'settings.json');
35
+ function ensureFile() {
36
+ if (!fs_1.default.existsSync(devlensDir)) {
37
+ fs_1.default.mkdirSync(devlensDir, { recursive: true });
38
+ }
39
+ if (!fs_1.default.existsSync(settingsFile)) {
40
+ const initial = { ignorePatterns: DEFAULT_IGNORE_PATTERNS };
41
+ fs_1.default.writeFileSync(settingsFile, JSON.stringify(initial, null, 2));
42
+ }
43
+ }
44
+ function load() {
45
+ ensureFile();
46
+ try {
47
+ const data = JSON.parse(fs_1.default.readFileSync(settingsFile, 'utf-8'));
48
+ return {
49
+ ignorePatterns: Array.isArray(data.ignorePatterns) ? data.ignorePatterns : DEFAULT_IGNORE_PATTERNS,
50
+ };
51
+ }
52
+ catch {
53
+ return { ignorePatterns: DEFAULT_IGNORE_PATTERNS };
54
+ }
55
+ }
56
+ function save(settings) {
57
+ ensureFile();
58
+ fs_1.default.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
59
+ }
60
+ return {
61
+ getSettings() {
62
+ return load();
63
+ },
64
+ updateSettings(input) {
65
+ const current = load();
66
+ const merged = {
67
+ ignorePatterns: input.ignorePatterns ?? current.ignorePatterns,
68
+ };
69
+ // Dedupe + trim + drop empties
70
+ merged.ignorePatterns = Array.from(new Set(merged.ignorePatterns.map(p => (p || '').trim()).filter(Boolean)));
71
+ save(merged);
72
+ return merged;
73
+ },
74
+ getIgnorePatterns() {
75
+ return load().ignorePatterns;
76
+ },
77
+ getChokidarIgnoreGlobs() {
78
+ const patterns = load().ignorePatterns;
79
+ // Always ignore dotfiles
80
+ const result = [/(^|[\/\\])\../];
81
+ for (const p of patterns) {
82
+ // If pattern contains glob chars, use as-is. Otherwise treat as a directory or filename.
83
+ if (p.includes('*') || p.includes('?') || p.includes('[')) {
84
+ result.push(p);
85
+ }
86
+ else {
87
+ // Match anywhere in tree: ignore the dir/file at any depth
88
+ result.push(`**/${p}/**`, `**/${p}`);
89
+ }
90
+ }
91
+ return result;
92
+ },
93
+ getIgnoreNameSet() {
94
+ const patterns = load().ignorePatterns;
95
+ const set = new Set();
96
+ for (const p of patterns) {
97
+ if (!p.includes('*') && !p.includes('/'))
98
+ set.add(p);
99
+ }
100
+ return set;
101
+ },
102
+ };
103
+ }
104
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/services/settings.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import chokidar from 'chokidar';
2
- export declare function createWatcher(projectDir: string, onChange: () => void): chokidar.FSWatcher;
1
+ import { FSWatcher } from 'chokidar';
2
+ export declare function createWatcher(projectDir: string, onChange: () => void, ignored?: (string | RegExp)[]): FSWatcher;
@@ -5,22 +5,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createWatcher = createWatcher;
7
7
  const chokidar_1 = __importDefault(require("chokidar"));
8
- function createWatcher(projectDir, onChange) {
8
+ function createWatcher(projectDir, onChange, ignored = [
9
+ /(^|[\/\\])\../,
10
+ '**/node_modules/**',
11
+ '**/.git/**',
12
+ '**/.devlens/**',
13
+ ]) {
9
14
  let debounceTimer = null;
10
15
  const watcher = chokidar_1.default.watch(projectDir, {
11
- ignored: [
12
- /(^|[\/\\])\../, // dotfiles
13
- '**/node_modules/**',
14
- '**/.git/**',
15
- '**/.devlens/**',
16
- ],
16
+ ignored,
17
17
  persistent: true,
18
18
  ignoreInitial: true,
19
19
  });
20
20
  const debouncedOnChange = () => {
21
21
  if (debounceTimer)
22
22
  clearTimeout(debounceTimer);
23
- debounceTimer = setTimeout(onChange, 300);
23
+ debounceTimer = setTimeout(onChange, 500);
24
24
  };
25
25
  watcher.on('change', debouncedOnChange);
26
26
  watcher.on('add', debouncedOnChange);
@@ -1 +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"}
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/services/watcher.ts"],"names":[],"mappings":";;;;;AAEA,sCA4BC;AA9BD,wDAA+C;AAE/C,SAAgB,aAAa,CAC3B,UAAkB,EAClB,QAAoB,EACpB,UAA+B;IAC7B,eAAe;IACf,oBAAoB;IACpB,YAAY;IACZ,gBAAgB;CACjB;IAED,IAAI,aAAa,GAA0B,IAAI,CAAC;IAEhD,MAAM,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,UAAU,EAAE;QACzC,OAAO;QACP,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"}
@@ -12,6 +12,7 @@ export interface FileStatus {
12
12
  export interface LogEntry {
13
13
  hash: string;
14
14
  message: string;
15
+ body?: string;
15
16
  author: string;
16
17
  date: string;
17
18
  }
@@ -82,6 +83,6 @@ export interface DevlensConfig {
82
83
  };
83
84
  }
84
85
  export interface WsMessage {
85
- type: 'file-changed' | 'diff-update' | 'status-update' | 'task-update' | 'todo-update' | 'claude-tasks-update' | 'rules-update' | 'commit-approval-update';
86
+ type: 'file-changed' | 'diff-update' | 'status-update' | 'task-update' | 'todo-update' | 'claude-tasks-update' | 'rules-update' | 'commit-approval-update' | 'settings-update';
86
87
  payload: unknown;
87
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycniuqton/devlens",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "homepage": "https://github.com/ycniuqton/Devlens#readme",
31
31
  "dependencies": {
32
- "@ycniuqton/devlens": "^0.1.3",
32
+ "@ycniuqton/devlens": "^0.1.7",
33
33
  "better-sqlite3": "^12.8.0",
34
34
  "chokidar": "^3.6.0",
35
35
  "commander": "^12.0.0",
@@ -1781,9 +1781,16 @@ body {
1781
1781
  }
1782
1782
 
1783
1783
  .commit-header-content {
1784
+ display: flex;
1785
+ flex-direction: column;
1786
+ gap: var(--sp-3);
1787
+ }
1788
+
1789
+ .commit-header-top {
1784
1790
  display: flex;
1785
1791
  align-items: center;
1786
1792
  gap: var(--sp-3);
1793
+ flex-wrap: wrap;
1787
1794
  }
1788
1795
 
1789
1796
  .commit-header-hash {
@@ -1796,15 +1803,112 @@ body {
1796
1803
  border-radius: var(--radius-sm);
1797
1804
  }
1798
1805
 
1806
+ .commit-header-meta {
1807
+ display: flex;
1808
+ align-items: center;
1809
+ gap: var(--sp-2);
1810
+ font-size: var(--text-xs);
1811
+ color: var(--color-text-muted);
1812
+ }
1813
+
1799
1814
  .commit-header-files {
1800
1815
  font-size: var(--text-xs);
1801
1816
  color: var(--color-text-muted);
1802
1817
  }
1803
1818
 
1819
+ .commit-header-message {
1820
+ background: var(--color-bg);
1821
+ border: 1px solid var(--color-border-subtle);
1822
+ border-radius: var(--radius-md);
1823
+ padding: var(--sp-3) var(--sp-4);
1824
+ max-height: 240px;
1825
+ overflow-y: auto;
1826
+ }
1827
+
1828
+ .commit-header-subject {
1829
+ font-size: var(--text-base);
1830
+ font-weight: 600;
1831
+ color: var(--color-text);
1832
+ word-break: break-word;
1833
+ }
1834
+
1835
+ .commit-header-body {
1836
+ margin: var(--sp-2) 0 0;
1837
+ font-family: var(--font-mono);
1838
+ font-size: var(--text-xs);
1839
+ color: var(--color-text-secondary);
1840
+ white-space: pre-wrap;
1841
+ word-break: break-word;
1842
+ line-height: var(--leading-normal);
1843
+ }
1844
+
1804
1845
  .commit-header-actions {
1805
- margin-left: auto;
1806
1846
  display: flex;
1807
1847
  gap: var(--sp-2);
1848
+ flex-wrap: wrap;
1849
+ }
1850
+
1851
+ /* Hover tooltip on commit list items */
1852
+ .commit-item { position: relative; }
1853
+
1854
+ .commit-tooltip {
1855
+ position: absolute;
1856
+ left: calc(100% + 12px);
1857
+ top: 50%;
1858
+ transform: translateY(-50%);
1859
+ background: var(--color-surface-2);
1860
+ border: 1px solid var(--color-border);
1861
+ border-radius: var(--radius-md);
1862
+ padding: var(--sp-3) var(--sp-4);
1863
+ min-width: 320px;
1864
+ max-width: 480px;
1865
+ box-shadow: var(--shadow-lg);
1866
+ opacity: 0;
1867
+ pointer-events: none;
1868
+ transform-origin: left center;
1869
+ transform: translateY(-50%) scale(0.95);
1870
+ transition: opacity var(--duration-fast) var(--ease), transform var(--duration-fast) var(--ease);
1871
+ z-index: 50;
1872
+ }
1873
+
1874
+ .commit-item:hover .commit-tooltip {
1875
+ opacity: 1;
1876
+ transform: translateY(-50%) scale(1);
1877
+ transition-delay: 250ms;
1878
+ }
1879
+
1880
+ .commit-tooltip::before {
1881
+ content: '';
1882
+ position: absolute;
1883
+ left: -6px;
1884
+ top: 50%;
1885
+ transform: translateY(-50%);
1886
+ width: 0;
1887
+ height: 0;
1888
+ border-top: 6px solid transparent;
1889
+ border-bottom: 6px solid transparent;
1890
+ border-right: 6px solid var(--color-border);
1891
+ }
1892
+
1893
+ .commit-tooltip-message {
1894
+ font-family: var(--font-mono);
1895
+ font-size: var(--text-xs);
1896
+ color: var(--color-text);
1897
+ white-space: pre-wrap;
1898
+ word-break: break-word;
1899
+ line-height: var(--leading-normal);
1900
+ max-height: 240px;
1901
+ overflow-y: auto;
1902
+ }
1903
+
1904
+ .commit-tooltip-meta {
1905
+ display: flex;
1906
+ gap: var(--sp-2);
1907
+ margin-top: var(--sp-2);
1908
+ padding-top: var(--sp-2);
1909
+ border-top: 1px solid var(--color-border-subtle);
1910
+ font-size: 10px;
1911
+ color: var(--color-text-muted);
1808
1912
  }
1809
1913
 
1810
1914
  .commit-detail-diff {
@@ -1849,8 +1953,48 @@ body {
1849
1953
  overflow: hidden;
1850
1954
  text-overflow: ellipsis;
1851
1955
  white-space: nowrap;
1956
+ flex: 1;
1957
+ min-width: 0;
1852
1958
  }
1853
1959
 
1960
+ /* File status icon (left of filename) */
1961
+ .commit-file-status-icon {
1962
+ display: inline-flex;
1963
+ align-items: center;
1964
+ justify-content: center;
1965
+ width: 20px;
1966
+ height: 20px;
1967
+ border-radius: var(--radius-sm);
1968
+ flex-shrink: 0;
1969
+ }
1970
+
1971
+ .commit-file-status-icon.added { color: var(--color-success); background: var(--color-success-subtle); }
1972
+ .commit-file-status-icon.modified { color: var(--color-warning); background: var(--color-warning-subtle); }
1973
+ .commit-file-status-icon.deleted { color: var(--color-danger); background: var(--color-danger-subtle); }
1974
+ .commit-file-status-icon.renamed { color: var(--color-purple); background: var(--color-purple-subtle); }
1975
+
1976
+ /* File status text tag (right side) */
1977
+ .commit-file-status-tag {
1978
+ font-size: 10px;
1979
+ font-weight: 700;
1980
+ letter-spacing: 0.06em;
1981
+ padding: 2px 8px;
1982
+ border-radius: var(--radius-sm);
1983
+ flex-shrink: 0;
1984
+ }
1985
+
1986
+ .commit-file-status-tag.added { color: var(--color-success); background: var(--color-success-subtle); }
1987
+ .commit-file-status-tag.modified { color: var(--color-warning); background: var(--color-warning-subtle); }
1988
+ .commit-file-status-tag.deleted { color: var(--color-danger); background: var(--color-danger-subtle); }
1989
+ .commit-file-status-tag.renamed { color: var(--color-purple); background: var(--color-purple-subtle); }
1990
+
1991
+ /* Filename color hints based on status */
1992
+ .commit-file-header.file-status-deleted .commit-file-name {
1993
+ text-decoration: line-through;
1994
+ color: var(--color-text-muted);
1995
+ }
1996
+ .commit-file-header.file-status-added .commit-file-name { color: var(--color-success); }
1997
+
1854
1998
  .commit-file-body {
1855
1999
  display: none;
1856
2000
  overflow-x: auto;
@@ -2011,6 +2155,75 @@ body {
2011
2155
  font-weight: 500;
2012
2156
  }
2013
2157
 
2158
+ /* ============================================================
2159
+ Settings Tab
2160
+ ============================================================ */
2161
+ .settings-container { max-width: 800px; width: 100%; }
2162
+
2163
+ .settings-section {
2164
+ background: var(--color-surface);
2165
+ border: 1px solid var(--color-border);
2166
+ border-radius: var(--radius-lg);
2167
+ padding: var(--sp-5) var(--sp-6);
2168
+ }
2169
+
2170
+ .settings-section h2 {
2171
+ font-size: var(--text-md);
2172
+ font-weight: 600;
2173
+ margin-bottom: var(--sp-2);
2174
+ }
2175
+
2176
+ .settings-subheader {
2177
+ font-size: var(--text-xs);
2178
+ font-weight: 700;
2179
+ text-transform: uppercase;
2180
+ letter-spacing: 0.08em;
2181
+ color: var(--color-text-muted);
2182
+ margin: var(--sp-5) 0 var(--sp-3);
2183
+ }
2184
+
2185
+ .settings-presets {
2186
+ display: grid;
2187
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
2188
+ gap: var(--sp-2);
2189
+ }
2190
+
2191
+ .preset-checkbox {
2192
+ display: flex;
2193
+ align-items: center;
2194
+ gap: var(--sp-2);
2195
+ padding: var(--sp-2) var(--sp-3);
2196
+ background: var(--color-bg);
2197
+ border: 1px solid var(--color-border-subtle);
2198
+ border-radius: var(--radius-sm);
2199
+ cursor: pointer;
2200
+ transition: all var(--duration-fast) var(--ease);
2201
+ font-size: var(--text-sm);
2202
+ }
2203
+
2204
+ .preset-checkbox:hover { border-color: var(--color-text-muted); }
2205
+ .preset-checkbox input { cursor: pointer; }
2206
+ .preset-name { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-text); }
2207
+
2208
+ .settings-textarea {
2209
+ width: 100%;
2210
+ background: var(--color-bg);
2211
+ border: 1px solid var(--color-border);
2212
+ border-radius: var(--radius-md);
2213
+ color: var(--color-text);
2214
+ font-family: var(--font-mono);
2215
+ font-size: var(--text-sm);
2216
+ padding: var(--sp-3) var(--sp-4);
2217
+ resize: vertical;
2218
+ min-height: 120px;
2219
+ }
2220
+
2221
+ .settings-textarea:focus {
2222
+ outline: none;
2223
+ border-color: var(--color-primary);
2224
+ box-shadow: 0 0 0 3px var(--color-primary-subtle);
2225
+ }
2226
+
2014
2227
  /* ============================================================
2015
2228
  Responsive
2016
2229
  ============================================================ */
package/public/index.html CHANGED
@@ -63,6 +63,12 @@
63
63
  </svg>
64
64
  <span>Integrations</span>
65
65
  </button>
66
+ <button class="nav-item" data-tab="settings" aria-label="Settings">
67
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
68
+ <circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
69
+ </svg>
70
+ <span>Settings</span>
71
+ </button>
66
72
  </nav>
67
73
 
68
74
  <div class="sidebar-footer">
@@ -88,11 +94,11 @@
88
94
  </div>
89
95
  <div class="divider-v"></div>
90
96
  <div class="btn-group">
91
- <button class="btn btn-ghost" data-view="side-by-side">
97
+ <button class="btn btn-ghost active" data-view="side-by-side">
92
98
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="8" height="18" rx="1"/><rect x="13" y="3" width="8" height="18" rx="1"/></svg>
93
99
  Split
94
100
  </button>
95
- <button class="btn btn-ghost active" data-view="line-by-line">
101
+ <button class="btn btn-ghost" data-view="line-by-line">
96
102
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="12" x2="21" y2="12"/></svg>
97
103
  Unified
98
104
  </button>
@@ -118,10 +124,10 @@
118
124
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
119
125
  </button>
120
126
  <div class="file-list-divider"></div>
121
- <button class="btn-icon btn-icon-sm" id="file-view-tree" title="Folder view" aria-label="Folder view">
127
+ <button class="btn-icon btn-icon-sm active" id="file-view-tree" title="Folder view" aria-label="Folder view">
122
128
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
123
129
  </button>
124
- <button class="btn-icon btn-icon-sm active" id="file-view-flat" title="Flat list" aria-label="Flat list">
130
+ <button class="btn-icon btn-icon-sm" id="file-view-flat" title="Flat list" aria-label="Flat list">
125
131
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
126
132
  </button>
127
133
  <span class="file-count" id="file-count">0</span>
@@ -378,6 +384,32 @@
378
384
 
379
385
  </div>
380
386
  </section>
387
+
388
+ <!-- Settings View -->
389
+ <section id="settings-view" class="tab-content">
390
+ <header class="view-header">
391
+ <h1>Settings</h1>
392
+ <div class="header-actions">
393
+ <button class="btn btn-primary" id="save-settings-btn">Save Settings</button>
394
+ </div>
395
+ </header>
396
+
397
+ <div class="settings-container">
398
+ <div class="settings-section">
399
+ <h2>Ignored Patterns</h2>
400
+ <p class="section-desc">Patterns ignored by the file watcher and the file explorer. Reduces lag for projects with large dependency folders. Changes apply immediately on save.</p>
401
+
402
+ <h3 class="settings-subheader">Common presets</h3>
403
+ <div id="settings-presets" class="settings-presets">
404
+ <p class="panel-empty">Loading...</p>
405
+ </div>
406
+
407
+ <h3 class="settings-subheader">Custom patterns</h3>
408
+ <p class="section-desc">One pattern per line. Plain names match anywhere in the tree (e.g. <code>node_modules</code>). Globs supported (e.g. <code>**/*.log</code>).</p>
409
+ <textarea id="settings-custom" class="settings-textarea" rows="6" placeholder="my-cache&#10;**/*.log"></textarea>
410
+ </div>
411
+ </div>
412
+ </section>
381
413
  </main>
382
414
 
383
415
  <!-- Task Modal -->
@@ -482,6 +514,7 @@
482
514
  <script src="/js/rules.js"></script>
483
515
  <script src="/js/browser.js"></script>
484
516
  <script src="/js/history.js"></script>
517
+ <script src="/js/settings.js"></script>
485
518
  <script src="/js/integrations.js"></script>
486
519
  </body>
487
520
  </html>
package/public/js/app.js CHANGED
@@ -40,7 +40,7 @@ window.addEventListener('popstate', () => {
40
40
  // Load initial tab from URL — redirect / to /diff
41
41
  (function() {
42
42
  const path = location.pathname.replace('/', '');
43
- const tab = ['diff', 'tasks', 'browser', 'history', 'rules', 'integrations'].includes(path) ? path : 'diff';
43
+ const tab = ['diff', 'tasks', 'browser', 'history', 'rules', 'integrations', 'settings'].includes(path) ? path : 'diff';
44
44
  if (!path || path === '') {
45
45
  history.replaceState(null, '', '/diff');
46
46
  }
package/public/js/diff.js CHANGED
@@ -1,12 +1,12 @@
1
1
  // Diff viewer
2
2
  var currentFilter = 'all';
3
- var currentViewMode = 'line-by-line';
4
- var fileListMode = localStorage.getItem('devlens-file-view') || 'flat';
3
+ var currentViewMode = localStorage.getItem('devlens-diff-view') || 'side-by-side';
4
+ var fileListMode = localStorage.getItem('devlens-file-view') || 'tree';
5
5
  var diffFiles = [];
6
6
  var currentFiles = [];
7
7
 
8
- // Restore file list view mode from localStorage
9
- (function restoreFileViewMode() {
8
+ // Restore view mode + file list mode from localStorage
9
+ (function restoreDiffSettings() {
10
10
  const flatBtn = document.getElementById('file-view-flat');
11
11
  const treeBtn = document.getElementById('file-view-tree');
12
12
  if (fileListMode === 'tree') {
@@ -16,6 +16,12 @@ var currentFiles = [];
16
16
  flatBtn?.classList.add('active');
17
17
  treeBtn?.classList.remove('active');
18
18
  }
19
+
20
+ // Restore active button for diff view mode (split / unified)
21
+ document.querySelectorAll('[data-view]').forEach(b => {
22
+ if (b.dataset.view === currentViewMode) b.classList.add('active');
23
+ else b.classList.remove('active');
24
+ });
19
25
  })();
20
26
 
21
27
  // Filter and view toggle
@@ -34,6 +40,7 @@ document.querySelector('.header-actions')?.addEventListener('click', (e) => {
34
40
  document.querySelectorAll('[data-view]').forEach(b => b.classList.remove('active'));
35
41
  btn.classList.add('active');
36
42
  currentViewMode = btn.dataset.view;
43
+ localStorage.setItem('devlens-diff-view', currentViewMode);
37
44
  renderAllFiles();
38
45
  }
39
46
  });
@@ -56,11 +63,12 @@ document.getElementById('file-list-items').addEventListener('click', (e) => {
56
63
  document.querySelectorAll('#file-list-items li').forEach(l => l.classList.remove('selected'));
57
64
  li.classList.add('selected');
58
65
 
59
- // Collapse all, expand only the clicked file
66
+ // Collapse all, expand only the clicked file (lazy-render its body)
60
67
  const sections = document.querySelectorAll('.diff-file-section');
61
68
  for (const section of sections) {
62
69
  if (section.dataset.file === fileName) {
63
70
  section.classList.add('expanded');
71
+ renderFileBodyIfNeeded(section);
64
72
  } else {
65
73
  section.classList.remove('expanded');
66
74
  }
@@ -198,21 +206,12 @@ function renderAllFiles() {
198
206
  return;
199
207
  }
200
208
 
201
- const outputFormat = currentViewMode === 'side-by-side' ? 'side-by-side' : 'line-by-line';
202
-
203
- // First file expanded, rest collapsed
209
+ // Render only headers diffs are computed lazily on expand
210
+ // diffFiles[i].diff holds the raw unified diff string for this file
204
211
  container.innerHTML = diffFiles.map((file, i) => {
205
- const diffHtml = Diff2Html.html(file.diff, {
206
- drawFileList: false,
207
- matching: 'lines',
208
- outputFormat: outputFormat,
209
- colorScheme: 'dark',
210
- });
211
-
212
212
  const shortName = file.name.split('/').pop();
213
-
214
213
  return `
215
- <div class="diff-file-section ${i === 0 ? 'expanded' : ''}" data-file="${file.name}">
214
+ <div class="diff-file-section ${i === 0 ? 'expanded' : ''}" data-file="${file.name}" data-idx="${i}">
216
215
  <div class="diff-file-header" onclick="toggleFileSection(this)">
217
216
  <svg class="chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
218
217
  <polyline points="9 18 15 12 9 6"/>
@@ -220,16 +219,42 @@ function renderAllFiles() {
220
219
  <span class="diff-file-name">${file.name}</span>
221
220
  <span class="diff-file-badge">${shortName}</span>
222
221
  </div>
223
- <div class="diff-file-body">${diffHtml}</div>
222
+ <div class="diff-file-body" data-rendered="false"></div>
224
223
  </div>
225
224
  `;
226
225
  }).join('');
226
+
227
+ // Pre-render only the first (expanded by default) file
228
+ const first = container.querySelector('.diff-file-section.expanded');
229
+ if (first) renderFileBodyIfNeeded(first);
227
230
  }
228
231
 
229
- // Chevron click toggle just this file, don't touch others
232
+ // Render the diff HTML for a file section if not already done
233
+ function renderFileBodyIfNeeded(section) {
234
+ const body = section.querySelector('.diff-file-body');
235
+ if (!body || body.dataset.rendered === 'true') return;
236
+
237
+ const idx = parseInt(section.dataset.idx, 10);
238
+ const file = diffFiles[idx];
239
+ if (!file) return;
240
+
241
+ const outputFormat = currentViewMode === 'side-by-side' ? 'side-by-side' : 'line-by-line';
242
+ body.innerHTML = Diff2Html.html(file.diff, {
243
+ drawFileList: false,
244
+ matching: 'lines',
245
+ outputFormat: outputFormat,
246
+ colorScheme: 'dark',
247
+ });
248
+ body.dataset.rendered = 'true';
249
+ }
250
+
251
+ // Chevron click — toggle just this file, lazy-render on first expand
230
252
  function toggleFileSection(headerEl) {
231
253
  const section = headerEl.closest('.diff-file-section');
232
254
  section.classList.toggle('expanded');
255
+ if (section.classList.contains('expanded')) {
256
+ renderFileBodyIfNeeded(section);
257
+ }
233
258
  }
234
259
 
235
260
  var STATUS_LABELS = { modified: 'M', added: 'A', deleted: 'D', untracked: 'U', renamed: 'R' };
@@ -2,8 +2,9 @@
2
2
 
3
3
  var historyLoaded = false;
4
4
  var historySelectedHash = null;
5
- var historyViewMode = localStorage.getItem('devlens-history-view') || 'line-by-line';
5
+ var historyViewMode = localStorage.getItem('devlens-history-view') || 'side-by-side';
6
6
  var historyCachedData = null; // last loaded commit { hash, files, diff }
7
+ var historyCommits = []; // last loaded commit list (for full message lookup)
7
8
 
8
9
  async function loadBranchInfo() {
9
10
  try {
@@ -20,6 +21,7 @@ async function loadCommits() {
20
21
  try {
21
22
  const res = await fetch('/api/browser/commits?limit=100');
22
23
  const commits = await res.json();
24
+ historyCommits = commits;
23
25
  document.getElementById('commit-count').textContent = commits.length;
24
26
 
25
27
  if (!commits.length) {
@@ -27,7 +29,9 @@ async function loadCommits() {
27
29
  return;
28
30
  }
29
31
 
30
- list.innerHTML = commits.map(c => `
32
+ list.innerHTML = commits.map(c => {
33
+ const fullMessage = c.body ? `${c.message}\n\n${c.body}` : c.message;
34
+ return `
31
35
  <li class="commit-item" data-hash="${c.hash}">
32
36
  <div class="commit-marker"></div>
33
37
  <div class="commit-content">
@@ -38,8 +42,16 @@ async function loadCommits() {
38
42
  <span class="commit-date">${formatRelativeDate(c.date)}</span>
39
43
  </div>
40
44
  </div>
41
- </li>
42
- `).join('');
45
+ <div class="commit-tooltip">
46
+ <div class="commit-tooltip-message">${escapeHtmlHistory(fullMessage)}</div>
47
+ <div class="commit-tooltip-meta">
48
+ <span>${escapeHtmlHistory(c.author)}</span>
49
+ <span>·</span>
50
+ <span>${new Date(c.date).toLocaleString()}</span>
51
+ </div>
52
+ </div>
53
+ </li>`;
54
+ }).join('');
43
55
 
44
56
  list.querySelectorAll('.commit-item').forEach(item => {
45
57
  item.addEventListener('click', () => {
@@ -99,11 +111,26 @@ function renderCommitDetails(hash, data) {
99
111
  if (!headerEl || !diffEl) return;
100
112
 
101
113
  const isUnified = historyViewMode === 'line-by-line';
114
+ const commit = historyCommits.find(c => c.hash === hash) || {};
115
+ const subject = commit.message || '';
116
+ const body = commit.body || '';
117
+ const author = commit.author || '';
118
+ const date = commit.date ? new Date(commit.date).toLocaleString() : '';
102
119
 
103
120
  headerEl.innerHTML = `
104
121
  <div class="commit-header-content">
105
- <div class="commit-header-hash">${hash}</div>
106
- <div class="commit-header-files">${data.files.length} file(s) changed</div>
122
+ <div class="commit-header-top">
123
+ <div class="commit-header-hash">${hash}</div>
124
+ <div class="commit-header-meta">
125
+ ${author ? `<span>${escapeHtmlHistory(author)}</span>` : ''}
126
+ ${date ? `<span>·</span><span>${date}</span>` : ''}
127
+ <span>·</span><span>${data.files.length} file(s)</span>
128
+ </div>
129
+ </div>
130
+ <div class="commit-header-message">
131
+ <div class="commit-header-subject">${escapeHtmlHistory(subject)}</div>
132
+ ${body ? `<pre class="commit-header-body">${escapeHtmlHistory(body)}</pre>` : ''}
133
+ </div>
107
134
  <div class="commit-header-actions">
108
135
  <div class="btn-group">
109
136
  <button class="btn btn-ghost btn-sm ${!isUnified ? 'active' : ''}" id="history-view-split" title="Side by side">
@@ -133,33 +160,58 @@ function renderCommitDetails(hash, data) {
133
160
  }
134
161
 
135
162
  const files = historySplitDiffByFile(data.diff);
136
- diffEl.innerHTML = files.map((file) => {
137
- const html = Diff2Html.html(file.diff, {
163
+
164
+ // Build a path → status map from data.files (e.g. "added", "modified", "deleted", "renamed")
165
+ const statusByPath = {};
166
+ for (const f of (data.files || [])) statusByPath[f.path] = f.status;
167
+
168
+ // Stash raw diffs on a closure-accessible array indexed by data-idx
169
+ const renderCommitFileBody = (section) => {
170
+ const body = section.querySelector('.commit-file-body');
171
+ if (!body || body.dataset.rendered === 'true') return;
172
+ const idx = parseInt(section.dataset.idx, 10);
173
+ const f = files[idx];
174
+ if (!f) return;
175
+ body.innerHTML = Diff2Html.html(f.diff, {
138
176
  drawFileList: false,
139
177
  matching: 'lines',
140
178
  outputFormat: historyViewMode,
141
179
  colorScheme: 'dark',
142
180
  });
181
+ body.dataset.rendered = 'true';
182
+ };
183
+
184
+ diffEl.innerHTML = files.map((file, i) => {
185
+ const status = statusByPath[file.name] || 'modified';
143
186
  return `
144
- <div class="commit-file-section" data-file="${escapeAttrHistory(file.name)}">
145
- <div class="commit-file-header">
146
- <svg class="commit-file-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
147
- <span class="commit-file-name">${escapeHtmlHistory(file.name)}</span>
148
- </div>
149
- <div class="commit-file-body">${html}</div>
187
+ <div class="commit-file-section" data-file="${escapeAttrHistory(file.name)}" data-idx="${i}">
188
+ <div class="commit-file-header file-status-${status}">
189
+ <svg class="commit-file-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
190
+ <span class="commit-file-status-icon ${status}" title="${status}">${commitFileStatusIcon(status)}</span>
191
+ <span class="commit-file-name">${escapeHtmlHistory(file.name)}</span>
192
+ <span class="commit-file-status-tag ${status}">${commitFileStatusLabel(status)}</span>
150
193
  </div>
194
+ <div class="commit-file-body" data-rendered="false"></div>
195
+ </div>
151
196
  `;
152
197
  }).join('');
153
198
 
154
- // Wire interactions
199
+ // Wire collapse/expand with lazy render on first expand
155
200
  diffEl.querySelectorAll('.commit-file-header').forEach(h => {
156
201
  h.addEventListener('click', () => {
157
- h.closest('.commit-file-section').classList.toggle('expanded');
202
+ const section = h.closest('.commit-file-section');
203
+ section.classList.toggle('expanded');
204
+ if (section.classList.contains('expanded')) {
205
+ renderCommitFileBody(section);
206
+ }
158
207
  });
159
208
  });
160
209
 
161
210
  document.getElementById('commit-expand-all')?.addEventListener('click', () => {
162
- diffEl.querySelectorAll('.commit-file-section').forEach(s => s.classList.add('expanded'));
211
+ diffEl.querySelectorAll('.commit-file-section').forEach(s => {
212
+ s.classList.add('expanded');
213
+ renderCommitFileBody(s);
214
+ });
163
215
  });
164
216
  document.getElementById('commit-collapse-all')?.addEventListener('click', () => {
165
217
  diffEl.querySelectorAll('.commit-file-section').forEach(s => s.classList.remove('expanded'));
@@ -182,6 +234,28 @@ function escapeAttrHistory(str) {
182
234
  return String(str).replace(/"/g, '&quot;');
183
235
  }
184
236
 
237
+ function commitFileStatusIcon(status) {
238
+ // SVG icons for each git status
239
+ const svg = (path) => `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">${path}</svg>`;
240
+ switch (status) {
241
+ case 'added': return svg('<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>'); // +
242
+ case 'deleted': return svg('<line x1="5" y1="12" x2="19" y2="12"/>'); // —
243
+ case 'renamed': return svg('<polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/>'); // ↻
244
+ case 'modified':
245
+ default: return svg('<circle cx="12" cy="12" r="3"/>'); // •
246
+ }
247
+ }
248
+
249
+ function commitFileStatusLabel(status) {
250
+ switch (status) {
251
+ case 'added': return 'NEW';
252
+ case 'deleted': return 'DEL';
253
+ case 'renamed': return 'REN';
254
+ case 'modified': return 'MOD';
255
+ default: return status.toUpperCase();
256
+ }
257
+ }
258
+
185
259
  function escapeHtmlHistory(str) {
186
260
  if (str == null) return '';
187
261
  const div = document.createElement('div');
@@ -0,0 +1,85 @@
1
+ // Settings tab — manage .devlens/settings.json (ignore patterns)
2
+
3
+ var settingsLoaded = false;
4
+
5
+ async function loadSettings() {
6
+ try {
7
+ const res = await fetch('/api/settings');
8
+ const data = await res.json();
9
+ renderSettings(data);
10
+ settingsLoaded = true;
11
+ } catch {
12
+ showToast('Failed to load settings', 'error');
13
+ }
14
+ }
15
+
16
+ function renderSettings(data) {
17
+ const presetsEl = document.getElementById('settings-presets');
18
+ const customEl = document.getElementById('settings-custom');
19
+ if (!presetsEl || !customEl) return;
20
+
21
+ const active = new Set(data.ignorePatterns || []);
22
+ const presets = data.presets || [];
23
+
24
+ // Render preset checkboxes
25
+ presetsEl.innerHTML = presets.map(p => `
26
+ <label class="preset-checkbox">
27
+ <input type="checkbox" data-preset="${escapeAttrSettings(p)}" ${active.has(p) ? 'checked' : ''}>
28
+ <span class="preset-name">${escapeHtmlSettings(p)}</span>
29
+ </label>
30
+ `).join('');
31
+
32
+ // Custom = active patterns NOT in presets
33
+ const customPatterns = (data.ignorePatterns || []).filter(p => !presets.includes(p));
34
+ customEl.value = customPatterns.join('\n');
35
+ }
36
+
37
+ function collectCurrentPatterns() {
38
+ const checked = Array.from(document.querySelectorAll('#settings-presets input[type="checkbox"]:checked'))
39
+ .map(cb => cb.dataset.preset);
40
+ const custom = (document.getElementById('settings-custom')?.value || '')
41
+ .split('\n')
42
+ .map(l => l.trim())
43
+ .filter(Boolean);
44
+ // Dedupe
45
+ return Array.from(new Set([...checked, ...custom]));
46
+ }
47
+
48
+ async function saveSettings() {
49
+ const patterns = collectCurrentPatterns();
50
+ try {
51
+ const res = await fetch('/api/settings', {
52
+ method: 'PUT',
53
+ headers: { 'Content-Type': 'application/json' },
54
+ body: JSON.stringify({ ignorePatterns: patterns }),
55
+ });
56
+ if (!res.ok) {
57
+ showToast('Failed to save settings', 'error');
58
+ return;
59
+ }
60
+ showToast('Settings saved — watcher restarted', 'success');
61
+ } catch {
62
+ showToast('Failed to save settings', 'error');
63
+ }
64
+ }
65
+
66
+ function escapeHtmlSettings(str) {
67
+ if (str == null) return '';
68
+ const div = document.createElement('div');
69
+ div.textContent = str;
70
+ return div.innerHTML;
71
+ }
72
+
73
+ function escapeAttrSettings(str) {
74
+ return String(str).replace(/"/g, '&quot;');
75
+ }
76
+
77
+ document.getElementById('save-settings-btn')?.addEventListener('click', saveSettings);
78
+
79
+ document.querySelector('[data-tab="settings"]')?.addEventListener('click', () => {
80
+ if (!settingsLoaded) loadSettings();
81
+ });
82
+
83
+ if (location.pathname === '/settings') {
84
+ loadSettings();
85
+ }