specsmd 0.1.61 → 0.1.62
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/lib/dashboard/tui/app.js +0 -6
- package/lib/dashboard/tui/preview.js +93 -18
- package/package.json +1 -1
package/lib/dashboard/tui/app.js
CHANGED
|
@@ -1127,12 +1127,6 @@ function createDashboardApp(deps) {
|
|
|
1127
1127
|
columns: Math.max(1, stdout.columns || process.stdout.columns || 120),
|
|
1128
1128
|
rows: Math.max(1, stdout.rows || process.stdout.rows || 40)
|
|
1129
1129
|
});
|
|
1130
|
-
|
|
1131
|
-
// Resize in some terminals can leave stale frame rows behind.
|
|
1132
|
-
// Keep the clear operation minimal to avoid triggering scrollback churn.
|
|
1133
|
-
if (typeof stdout.write === 'function' && stdout.isTTY !== false) {
|
|
1134
|
-
stdout.write('\u001B[H\u001B[J');
|
|
1135
|
-
}
|
|
1136
1130
|
};
|
|
1137
1131
|
|
|
1138
1132
|
updateSize();
|
|
@@ -6,6 +6,73 @@ const {
|
|
|
6
6
|
loadGitCommitPreview
|
|
7
7
|
} = require('../git/changes');
|
|
8
8
|
|
|
9
|
+
const MAX_PREVIEW_CACHE_ENTRIES = 64;
|
|
10
|
+
const previewContentCache = new Map();
|
|
11
|
+
|
|
12
|
+
function getFilePreviewCacheKey(filePath) {
|
|
13
|
+
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const stat = fs.statSync(filePath);
|
|
19
|
+
return `file:${filePath}:${stat.size}:${Math.floor(stat.mtimeMs)}`;
|
|
20
|
+
} catch {
|
|
21
|
+
return `file:${filePath}:missing`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getGitPreviewCacheKey(fileEntry, isGitCommitPreview) {
|
|
26
|
+
if (!fileEntry || typeof fileEntry !== 'object') {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const repoRoot = typeof fileEntry.repoRoot === 'string' ? fileEntry.repoRoot : '';
|
|
31
|
+
if (isGitCommitPreview) {
|
|
32
|
+
const commitHash = typeof fileEntry.commitHash === 'string' ? fileEntry.commitHash : '';
|
|
33
|
+
return `git-commit:${repoRoot}:${commitHash}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const bucket = typeof fileEntry.bucket === 'string' ? fileEntry.bucket : '';
|
|
37
|
+
const relativePath = typeof fileEntry.relativePath === 'string' ? fileEntry.relativePath : '';
|
|
38
|
+
const pathValue = typeof fileEntry.path === 'string' ? fileEntry.path : '';
|
|
39
|
+
return `git-diff:${repoRoot}:${bucket}:${relativePath}:${pathValue}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getCachedPreviewContent(cacheKey) {
|
|
43
|
+
if (!cacheKey || !previewContentCache.has(cacheKey)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const cached = previewContentCache.get(cacheKey);
|
|
48
|
+
previewContentCache.delete(cacheKey);
|
|
49
|
+
previewContentCache.set(cacheKey, cached);
|
|
50
|
+
return Array.isArray(cached) ? cached : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function setCachedPreviewContent(cacheKey, lines) {
|
|
54
|
+
if (!cacheKey || !Array.isArray(lines)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (previewContentCache.has(cacheKey)) {
|
|
59
|
+
previewContentCache.delete(cacheKey);
|
|
60
|
+
}
|
|
61
|
+
previewContentCache.set(cacheKey, lines);
|
|
62
|
+
|
|
63
|
+
while (previewContentCache.size > MAX_PREVIEW_CACHE_ENTRIES) {
|
|
64
|
+
const oldest = previewContentCache.keys().next().value;
|
|
65
|
+
if (!oldest) {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
previewContentCache.delete(oldest);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function clearPreviewContentCache() {
|
|
73
|
+
previewContentCache.clear();
|
|
74
|
+
}
|
|
75
|
+
|
|
9
76
|
function buildPreviewLines(fileEntry, width, scrollOffset, options = {}) {
|
|
10
77
|
const fullDocument = options?.fullDocument === true;
|
|
11
78
|
|
|
@@ -16,24 +83,31 @@ function buildPreviewLines(fileEntry, width, scrollOffset, options = {}) {
|
|
|
16
83
|
const isGitFilePreview = fileEntry.previewType === 'git-diff';
|
|
17
84
|
const isGitCommitPreview = fileEntry.previewType === 'git-commit-diff';
|
|
18
85
|
const isGitPreview = isGitFilePreview || isGitCommitPreview;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
86
|
+
const cacheKey = isGitPreview
|
|
87
|
+
? getGitPreviewCacheKey(fileEntry, isGitCommitPreview)
|
|
88
|
+
: getFilePreviewCacheKey(fileEntry.path);
|
|
89
|
+
let rawLines = getCachedPreviewContent(cacheKey);
|
|
90
|
+
if (!rawLines) {
|
|
91
|
+
if (isGitPreview) {
|
|
92
|
+
const diffText = isGitCommitPreview
|
|
93
|
+
? loadGitCommitPreview(fileEntry)
|
|
94
|
+
: loadGitDiffPreview(fileEntry);
|
|
95
|
+
rawLines = String(diffText || '').split(/\r?\n/);
|
|
96
|
+
} else {
|
|
97
|
+
let content;
|
|
98
|
+
try {
|
|
99
|
+
content = fs.readFileSync(fileEntry.path, 'utf8');
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return [{
|
|
102
|
+
text: truncate(`Unable to read ${fileEntry.label || fileEntry.path}: ${error.message}`, width),
|
|
103
|
+
color: 'red',
|
|
104
|
+
bold: false
|
|
105
|
+
}];
|
|
106
|
+
}
|
|
107
|
+
rawLines = String(content).split(/\r?\n/);
|
|
35
108
|
}
|
|
36
|
-
|
|
109
|
+
|
|
110
|
+
setCachedPreviewContent(cacheKey, rawLines);
|
|
37
111
|
}
|
|
38
112
|
|
|
39
113
|
const headLine = {
|
|
@@ -141,5 +215,6 @@ function allocateSingleColumnPanels(candidates, rowsBudget) {
|
|
|
141
215
|
|
|
142
216
|
module.exports = {
|
|
143
217
|
buildPreviewLines,
|
|
144
|
-
allocateSingleColumnPanels
|
|
218
|
+
allocateSingleColumnPanels,
|
|
219
|
+
clearPreviewContentCache
|
|
145
220
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.62",
|
|
4
4
|
"description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
|
|
5
5
|
"main": "lib/installer.js",
|
|
6
6
|
"bin": {
|