@threadbase-sh/scanner 0.11.0 → 0.11.2
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/dist/cli.js +69 -43
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +77 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -42
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
import pino2 from "pino";
|
|
6
6
|
|
|
7
7
|
// package.json
|
|
8
|
-
var version = "0.11.
|
|
8
|
+
var version = "0.11.2";
|
|
9
9
|
|
|
10
10
|
// src/logger.ts
|
|
11
11
|
import pino from "pino";
|
|
@@ -62,7 +62,7 @@ async function saveProfiles(profiles, configPath) {
|
|
|
62
62
|
import { EventEmitter } from "events";
|
|
63
63
|
import { closeSync as closeSync2, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
64
64
|
import { homedir as homedir2 } from "os";
|
|
65
|
-
import { join as
|
|
65
|
+
import { join as join5 } from "path";
|
|
66
66
|
|
|
67
67
|
// src/cache.ts
|
|
68
68
|
var LRUCache = class {
|
|
@@ -100,6 +100,12 @@ var LRUCache = class {
|
|
|
100
100
|
}
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
+
// src/canonical-path.ts
|
|
104
|
+
import { sep } from "path";
|
|
105
|
+
function canonicalPath(p) {
|
|
106
|
+
return sep === "\\" ? p.replace(/\//g, "\\") : p;
|
|
107
|
+
}
|
|
108
|
+
|
|
103
109
|
// src/discovery.ts
|
|
104
110
|
import fg from "fast-glob";
|
|
105
111
|
import { stat } from "fs/promises";
|
|
@@ -141,7 +147,7 @@ async function discoverJsonlFiles(dirs, onProgress) {
|
|
|
141
147
|
if (size < 0) {
|
|
142
148
|
skippedInaccessible++;
|
|
143
149
|
} else if (size > 0) {
|
|
144
|
-
results.push({ filePath, account });
|
|
150
|
+
results.push({ filePath: canonicalPath(filePath), account });
|
|
145
151
|
kept++;
|
|
146
152
|
} else {
|
|
147
153
|
skippedEmpty++;
|
|
@@ -1173,7 +1179,7 @@ var CodexCliProvider = class {
|
|
|
1173
1179
|
for (const filePath of paths) {
|
|
1174
1180
|
try {
|
|
1175
1181
|
const s = await stat2(filePath);
|
|
1176
|
-
if (s.size > 0) results.push({ filePath, account: "codex" });
|
|
1182
|
+
if (s.size > 0) results.push({ filePath: canonicalPath(filePath), account: "codex" });
|
|
1177
1183
|
} catch (err) {
|
|
1178
1184
|
log.warn({ filePath, err }, "codex discovery: stat failed");
|
|
1179
1185
|
}
|
|
@@ -1632,6 +1638,7 @@ function openDatabase(dbPath) {
|
|
|
1632
1638
|
|
|
1633
1639
|
// src/persistent/dir-watermark.ts
|
|
1634
1640
|
import { readdir, stat as stat3 } from "fs/promises";
|
|
1641
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
1635
1642
|
var FULL_RECONCILE_EVERY_N_SCANS = 20;
|
|
1636
1643
|
async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
1637
1644
|
const log = getLogger();
|
|
@@ -1641,7 +1648,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
|
1641
1648
|
const results = [];
|
|
1642
1649
|
for (const rawDir of dirs) {
|
|
1643
1650
|
const { account } = rawDir;
|
|
1644
|
-
const projectsDir = rawDir.projectsDir
|
|
1651
|
+
const projectsDir = canonicalPath(rawDir.projectsDir);
|
|
1645
1652
|
const resolved = await resolveProjectDirs(projectsDir, scannedDirs);
|
|
1646
1653
|
if (resolved === null) continue;
|
|
1647
1654
|
for (const projectDir of resolved.entries) {
|
|
@@ -1702,11 +1709,10 @@ async function resolveProjectDirs(projectsDir, scannedDirs) {
|
|
|
1702
1709
|
return { entries, commitRoot: { mtimeMs: rootStat.mtimeMs } };
|
|
1703
1710
|
}
|
|
1704
1711
|
function dirnameOf(filePath) {
|
|
1705
|
-
|
|
1706
|
-
return idx === -1 ? filePath : filePath.slice(0, idx);
|
|
1712
|
+
return dirname4(filePath);
|
|
1707
1713
|
}
|
|
1708
1714
|
function joinPath(dir, name) {
|
|
1709
|
-
return
|
|
1715
|
+
return join4(dir, name);
|
|
1710
1716
|
}
|
|
1711
1717
|
|
|
1712
1718
|
// src/persistent/repositories/checkpoints.repo.ts
|
|
@@ -1716,15 +1722,16 @@ var CheckpointsRepo = class {
|
|
|
1716
1722
|
}
|
|
1717
1723
|
db;
|
|
1718
1724
|
replaceAll(sourcePath, checkpoints) {
|
|
1725
|
+
const path = canonicalPath(sourcePath);
|
|
1719
1726
|
const tx = this.db.transaction(() => {
|
|
1720
|
-
this.db.prepare("DELETE FROM message_checkpoints WHERE source_path = ?").run(
|
|
1727
|
+
this.db.prepare("DELETE FROM message_checkpoints WHERE source_path = ?").run(path);
|
|
1721
1728
|
const insert = this.db.prepare(
|
|
1722
1729
|
`INSERT INTO message_checkpoints
|
|
1723
1730
|
(source_path, message_index, byte_offset, line_number, parser_state)
|
|
1724
1731
|
VALUES (?, ?, ?, ?, ?)`
|
|
1725
1732
|
);
|
|
1726
1733
|
for (const c of checkpoints) {
|
|
1727
|
-
insert.run(
|
|
1734
|
+
insert.run(path, c.messageIndex, c.byteOffset, c.lineNumber, JSON.stringify(c.state));
|
|
1728
1735
|
}
|
|
1729
1736
|
});
|
|
1730
1737
|
tx();
|
|
@@ -1733,6 +1740,7 @@ var CheckpointsRepo = class {
|
|
|
1733
1740
|
// the chain covering the immutable prefix (Kafka sparse-index style); rows are
|
|
1734
1741
|
// only ever removed on truncation/replace or deletion.
|
|
1735
1742
|
append(sourcePath, checkpoints) {
|
|
1743
|
+
const path = canonicalPath(sourcePath);
|
|
1736
1744
|
const tx = this.db.transaction(() => {
|
|
1737
1745
|
const insert = this.db.prepare(
|
|
1738
1746
|
`INSERT INTO message_checkpoints
|
|
@@ -1740,7 +1748,7 @@ var CheckpointsRepo = class {
|
|
|
1740
1748
|
VALUES (?, ?, ?, ?, ?)`
|
|
1741
1749
|
);
|
|
1742
1750
|
for (const c of checkpoints) {
|
|
1743
|
-
insert.run(
|
|
1751
|
+
insert.run(path, c.messageIndex, c.byteOffset, c.lineNumber, JSON.stringify(c.state));
|
|
1744
1752
|
}
|
|
1745
1753
|
});
|
|
1746
1754
|
tx();
|
|
@@ -1753,7 +1761,7 @@ var CheckpointsRepo = class {
|
|
|
1753
1761
|
FROM message_checkpoints
|
|
1754
1762
|
WHERE source_path = ? AND message_index <= ?
|
|
1755
1763
|
ORDER BY message_index DESC LIMIT 1`
|
|
1756
|
-
).get(sourcePath, messageIndex);
|
|
1764
|
+
).get(canonicalPath(sourcePath), messageIndex);
|
|
1757
1765
|
return row ? toCheckpoint(row) : null;
|
|
1758
1766
|
}
|
|
1759
1767
|
// The highest-index checkpoint for a file, or null if none. The resume point
|
|
@@ -1764,14 +1772,14 @@ var CheckpointsRepo = class {
|
|
|
1764
1772
|
FROM message_checkpoints
|
|
1765
1773
|
WHERE source_path = ?
|
|
1766
1774
|
ORDER BY message_index DESC LIMIT 1`
|
|
1767
|
-
).get(sourcePath);
|
|
1775
|
+
).get(canonicalPath(sourcePath));
|
|
1768
1776
|
return row ? toCheckpoint(row) : null;
|
|
1769
1777
|
}
|
|
1770
1778
|
count(sourcePath) {
|
|
1771
|
-
return this.db.prepare("SELECT COUNT(*) AS n FROM message_checkpoints WHERE source_path = ?").get(sourcePath).n;
|
|
1779
|
+
return this.db.prepare("SELECT COUNT(*) AS n FROM message_checkpoints WHERE source_path = ?").get(canonicalPath(sourcePath)).n;
|
|
1772
1780
|
}
|
|
1773
1781
|
remove(sourcePath) {
|
|
1774
|
-
this.db.prepare("DELETE FROM message_checkpoints WHERE source_path = ?").run(sourcePath);
|
|
1782
|
+
this.db.prepare("DELETE FROM message_checkpoints WHERE source_path = ?").run(canonicalPath(sourcePath));
|
|
1775
1783
|
}
|
|
1776
1784
|
};
|
|
1777
1785
|
function toCheckpoint(row) {
|
|
@@ -1784,24 +1792,30 @@ function toCheckpoint(row) {
|
|
|
1784
1792
|
}
|
|
1785
1793
|
|
|
1786
1794
|
// src/persistent/repositories/conversation-files.repo.ts
|
|
1787
|
-
import { basename as basename5, dirname as
|
|
1795
|
+
import { basename as basename5, dirname as dirname5 } from "path";
|
|
1788
1796
|
var ConversationFilesRepo = class {
|
|
1789
1797
|
constructor(db) {
|
|
1790
1798
|
this.db = db;
|
|
1791
1799
|
}
|
|
1792
1800
|
db;
|
|
1793
1801
|
getByPath(absolutePath) {
|
|
1794
|
-
return this.db.prepare("SELECT * FROM conversation_files WHERE absolute_path = ?").get(absolutePath);
|
|
1802
|
+
return this.db.prepare("SELECT * FROM conversation_files WHERE absolute_path = ?").get(canonicalPath(absolutePath));
|
|
1795
1803
|
}
|
|
1796
1804
|
// Insert a freshly-discovered file at offset 0; returns its row id. Existing
|
|
1797
1805
|
// path is left untouched (returns the existing id) so a re-discovery is safe.
|
|
1806
|
+
//
|
|
1807
|
+
// absolute_path/parent_dir are stored canonicalized so a caller that built the
|
|
1808
|
+
// path with the native separator (watcher, path.join) and one that got it from
|
|
1809
|
+
// fast-glob (forward slashes, even on Windows) land on the same row instead of
|
|
1810
|
+
// inserting a duplicate.
|
|
1798
1811
|
ensure(absolutePath, account) {
|
|
1799
|
-
const
|
|
1812
|
+
const canonical = canonicalPath(absolutePath);
|
|
1813
|
+
const existing = this.getByPath(canonical);
|
|
1800
1814
|
if (existing) return existing.id;
|
|
1801
1815
|
const info = this.db.prepare(
|
|
1802
1816
|
`INSERT INTO conversation_files (absolute_path, parent_dir, file_name, account)
|
|
1803
1817
|
VALUES (?, ?, ?, ?)`
|
|
1804
|
-
).run(
|
|
1818
|
+
).run(canonical, dirname5(canonical), basename5(canonical), account);
|
|
1805
1819
|
return Number(info.lastInsertRowid);
|
|
1806
1820
|
}
|
|
1807
1821
|
// Advance the cursor + persisted reducer state after a successful index pass.
|
|
@@ -1863,7 +1877,7 @@ var ConversationFilesRepo = class {
|
|
|
1863
1877
|
activePathsByParentDir(parentDir) {
|
|
1864
1878
|
return this.db.prepare(
|
|
1865
1879
|
"SELECT absolute_path, account FROM conversation_files WHERE parent_dir = ? AND status != 'deleted'"
|
|
1866
|
-
).all(parentDir);
|
|
1880
|
+
).all(canonicalPath(parentDir));
|
|
1867
1881
|
}
|
|
1868
1882
|
};
|
|
1869
1883
|
|
|
@@ -1958,7 +1972,10 @@ var ConversationsRepo = class {
|
|
|
1958
1972
|
updated_at = CURRENT_TIMESTAMP`
|
|
1959
1973
|
).run({
|
|
1960
1974
|
file_id: fileId,
|
|
1961
|
-
|
|
1975
|
+
// Canonical form, matching conversation_files.absolute_path — otherwise
|
|
1976
|
+
// a native-separator caller writes a second spelling of the same file
|
|
1977
|
+
// that every by-path lookup (and the deletion-reconcile) then misses.
|
|
1978
|
+
source_path: canonicalPath(meta.id),
|
|
1962
1979
|
provider: meta.provider ?? CLAUDE_CODE_PROVIDER,
|
|
1963
1980
|
kind: meta.kind ?? null,
|
|
1964
1981
|
external_session_id: meta.externalSessionId ?? null,
|
|
@@ -1988,7 +2005,7 @@ var ConversationsRepo = class {
|
|
|
1988
2005
|
});
|
|
1989
2006
|
}
|
|
1990
2007
|
getBySourcePath(sourcePath) {
|
|
1991
|
-
const row = this.db.prepare("SELECT * FROM conversations WHERE source_path = ? AND status = 'active'").get(sourcePath);
|
|
2008
|
+
const row = this.db.prepare("SELECT * FROM conversations WHERE source_path = ? AND status = 'active'").get(canonicalPath(sourcePath));
|
|
1992
2009
|
return row ? rowToMeta(row) : null;
|
|
1993
2010
|
}
|
|
1994
2011
|
// Dual lookup matching scanner.getConversation: resolve by source_path (the
|
|
@@ -2052,7 +2069,7 @@ var ConversationsRepo = class {
|
|
|
2052
2069
|
pageMessageCount(sourcePath) {
|
|
2053
2070
|
const row = this.db.prepare(
|
|
2054
2071
|
"SELECT page_message_count AS n FROM conversations WHERE source_path = ? AND status = 'active'"
|
|
2055
|
-
).get(sourcePath);
|
|
2072
|
+
).get(canonicalPath(sourcePath));
|
|
2056
2073
|
return row?.n ?? 0;
|
|
2057
2074
|
}
|
|
2058
2075
|
count() {
|
|
@@ -2067,14 +2084,15 @@ var FtsRepo = class {
|
|
|
2067
2084
|
}
|
|
2068
2085
|
db;
|
|
2069
2086
|
upsert(meta) {
|
|
2087
|
+
const sourcePath = canonicalPath(meta.id);
|
|
2070
2088
|
const tx = this.db.transaction(() => {
|
|
2071
|
-
this.db.prepare("DELETE FROM conversation_messages_fts WHERE source_path = ?").run(
|
|
2089
|
+
this.db.prepare("DELETE FROM conversation_messages_fts WHERE source_path = ?").run(sourcePath);
|
|
2072
2090
|
this.db.prepare(
|
|
2073
2091
|
`INSERT INTO conversation_messages_fts
|
|
2074
2092
|
(source_path, content, project_name, session_id, session_name, account, model, branch, tool_names)
|
|
2075
2093
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
2076
2094
|
).run(
|
|
2077
|
-
|
|
2095
|
+
sourcePath,
|
|
2078
2096
|
meta.contentSnippet ?? "",
|
|
2079
2097
|
meta.projectName ?? "",
|
|
2080
2098
|
meta.sessionId ?? "",
|
|
@@ -2088,7 +2106,7 @@ var FtsRepo = class {
|
|
|
2088
2106
|
tx();
|
|
2089
2107
|
}
|
|
2090
2108
|
remove(sourcePath) {
|
|
2091
|
-
this.db.prepare("DELETE FROM conversation_messages_fts WHERE source_path = ?").run(sourcePath);
|
|
2109
|
+
this.db.prepare("DELETE FROM conversation_messages_fts WHERE source_path = ?").run(canonicalPath(sourcePath));
|
|
2092
2110
|
}
|
|
2093
2111
|
// Ranked source_paths matching the query, best first. Returns [] on an empty
|
|
2094
2112
|
// query (callers fall back to a recency listing).
|
|
@@ -2120,11 +2138,11 @@ var ScannedDirsRepo = class {
|
|
|
2120
2138
|
}
|
|
2121
2139
|
db;
|
|
2122
2140
|
get(path) {
|
|
2123
|
-
return this.db.prepare("SELECT * FROM scanned_dirs WHERE path = ?").get(path);
|
|
2141
|
+
return this.db.prepare("SELECT * FROM scanned_dirs WHERE path = ?").get(canonicalPath(path));
|
|
2124
2142
|
}
|
|
2125
2143
|
// Known project subdirectories under a root, path ascending (stable order).
|
|
2126
2144
|
childrenOf(parentRoot) {
|
|
2127
|
-
return this.db.prepare("SELECT * FROM scanned_dirs WHERE parent_root = ? ORDER BY path ASC").all(parentRoot);
|
|
2145
|
+
return this.db.prepare("SELECT * FROM scanned_dirs WHERE parent_root = ? ORDER BY path ASC").all(canonicalPath(parentRoot));
|
|
2128
2146
|
}
|
|
2129
2147
|
upsert(path, parentRoot, mtimeMs, hasNested) {
|
|
2130
2148
|
this.db.prepare(
|
|
@@ -2135,11 +2153,16 @@ var ScannedDirsRepo = class {
|
|
|
2135
2153
|
mtime_ms = excluded.mtime_ms,
|
|
2136
2154
|
has_nested = excluded.has_nested,
|
|
2137
2155
|
updated_at = CURRENT_TIMESTAMP`
|
|
2138
|
-
).run(
|
|
2156
|
+
).run(
|
|
2157
|
+
canonicalPath(path),
|
|
2158
|
+
parentRoot === null ? null : canonicalPath(parentRoot),
|
|
2159
|
+
mtimeMs,
|
|
2160
|
+
hasNested ? 1 : 0
|
|
2161
|
+
);
|
|
2139
2162
|
}
|
|
2140
2163
|
// Drop a project subdirectory's watermark row (it vanished from disk).
|
|
2141
2164
|
remove(path) {
|
|
2142
|
-
this.db.prepare("DELETE FROM scanned_dirs WHERE path = ?").run(path);
|
|
2165
|
+
this.db.prepare("DELETE FROM scanned_dirs WHERE path = ?").run(canonicalPath(path));
|
|
2143
2166
|
}
|
|
2144
2167
|
};
|
|
2145
2168
|
|
|
@@ -2272,7 +2295,7 @@ var PersistentEngine = class {
|
|
|
2272
2295
|
if (enabled.includes(CODEX_CLI_PROVIDER) && (options.codexRoots?.length ?? 0) > 0) {
|
|
2273
2296
|
coveredAccounts.add("codex");
|
|
2274
2297
|
}
|
|
2275
|
-
const seen = new Set(discovered.map((d) => d.filePath));
|
|
2298
|
+
const seen = new Set(discovered.map((d) => canonicalPath(d.filePath)));
|
|
2276
2299
|
for (const path of this.files.activePathsByAccounts([...coveredAccounts])) {
|
|
2277
2300
|
if (!seen.has(path)) this.markDeleted(path);
|
|
2278
2301
|
}
|
|
@@ -2286,9 +2309,10 @@ var PersistentEngine = class {
|
|
|
2286
2309
|
// half-written row or an over-advanced cursor. Returns the classification
|
|
2287
2310
|
// alongside the meta so callers (refreshFile) can keep, extend, or evict
|
|
2288
2311
|
// their own per-file caches without re-stat'ing the file (racy) themselves.
|
|
2289
|
-
async indexFile(
|
|
2312
|
+
async indexFile(rawFilePath, account, tierName, customTiers, resolveGitBranch, force = false, provider) {
|
|
2290
2313
|
const log = getLogger();
|
|
2291
2314
|
const tier = resolveTier(tierName, customTiers);
|
|
2315
|
+
const filePath = canonicalPath(rawFilePath);
|
|
2292
2316
|
const existing = this.files.getByPath(filePath);
|
|
2293
2317
|
const { change, stat: stat4 } = classify(filePath, existing);
|
|
2294
2318
|
if (change === "vanished" || !stat4) {
|
|
@@ -2635,7 +2659,7 @@ var IndexQueue = class {
|
|
|
2635
2659
|
var BATCH_SIZE2 = 12;
|
|
2636
2660
|
var DEFAULT_CONFIG_PATH = "~/.config/threadbase-scanner";
|
|
2637
2661
|
function defaultDbPath() {
|
|
2638
|
-
return process.env.TB_SCANNER_DB ??
|
|
2662
|
+
return process.env.TB_SCANNER_DB ?? join5(homedir2(), ".config", "threadbase-scanner", "index.db");
|
|
2639
2663
|
}
|
|
2640
2664
|
var ConversationScanner = class {
|
|
2641
2665
|
metadataCache = /* @__PURE__ */ new Map();
|
|
@@ -2928,12 +2952,13 @@ var ConversationScanner = class {
|
|
|
2928
2952
|
}
|
|
2929
2953
|
async getConversation(id, _options) {
|
|
2930
2954
|
const log = getLogger();
|
|
2931
|
-
const
|
|
2955
|
+
const cid = canonicalPath(id);
|
|
2956
|
+
const cached = this.conversationLRU.get(cid);
|
|
2932
2957
|
if (cached) {
|
|
2933
2958
|
log.debug({ id }, "getConversation: cache hit");
|
|
2934
2959
|
return cached.conversation;
|
|
2935
2960
|
}
|
|
2936
|
-
const meta = this.persistent ? this.engine().getByIdOrSession(
|
|
2961
|
+
const meta = this.persistent ? this.engine().getByIdOrSession(cid) : this.metadataCache.get(cid) ?? this.resolveSessionId(cid);
|
|
2937
2962
|
if (!meta) {
|
|
2938
2963
|
log.debug({ id }, "getConversation: not found in metadata");
|
|
2939
2964
|
return null;
|
|
@@ -2942,12 +2967,12 @@ var ConversationScanner = class {
|
|
|
2942
2967
|
try {
|
|
2943
2968
|
if (this.persistent && meta.provider !== CODEX_CLI_PROVIDER) {
|
|
2944
2969
|
const parsed = await parseConversationResumable(meta.filePath, meta.account);
|
|
2945
|
-
if (parsed) this.conversationLRU.set(
|
|
2970
|
+
if (parsed) this.conversationLRU.set(cid, parsed);
|
|
2946
2971
|
return parsed?.conversation ?? null;
|
|
2947
2972
|
}
|
|
2948
2973
|
const conversation = meta.provider === CODEX_CLI_PROVIDER ? await parseCodexConversation(meta.filePath, meta.account) : await parseConversation(meta.filePath, meta.account);
|
|
2949
2974
|
if (conversation) {
|
|
2950
|
-
this.conversationLRU.set(
|
|
2975
|
+
this.conversationLRU.set(cid, { conversation });
|
|
2951
2976
|
}
|
|
2952
2977
|
return conversation;
|
|
2953
2978
|
} catch (err) {
|
|
@@ -2975,7 +3000,7 @@ var ConversationScanner = class {
|
|
|
2975
3000
|
// which is identical by construction.
|
|
2976
3001
|
async getConversationPage(id, options) {
|
|
2977
3002
|
if (this.persistent) {
|
|
2978
|
-
return this.engine().getPage(id, options);
|
|
3003
|
+
return this.engine().getPage(canonicalPath(id), options);
|
|
2979
3004
|
}
|
|
2980
3005
|
const conversation = await this.getConversation(id);
|
|
2981
3006
|
if (!conversation) return null;
|
|
@@ -3025,14 +3050,15 @@ var ConversationScanner = class {
|
|
|
3025
3050
|
// each re-reading the file.
|
|
3026
3051
|
refreshesInFlight = /* @__PURE__ */ new Map();
|
|
3027
3052
|
refreshFile(filePath, account) {
|
|
3028
|
-
const
|
|
3053
|
+
const cpath = canonicalPath(filePath);
|
|
3054
|
+
const inFlight = this.refreshesInFlight.get(cpath);
|
|
3029
3055
|
if (inFlight) return inFlight;
|
|
3030
|
-
const refresh = this.doRefreshFile(
|
|
3031
|
-
if (this.refreshesInFlight.get(
|
|
3032
|
-
this.refreshesInFlight.delete(
|
|
3056
|
+
const refresh = this.doRefreshFile(cpath, account).finally(() => {
|
|
3057
|
+
if (this.refreshesInFlight.get(cpath) === refresh) {
|
|
3058
|
+
this.refreshesInFlight.delete(cpath);
|
|
3033
3059
|
}
|
|
3034
3060
|
});
|
|
3035
|
-
this.refreshesInFlight.set(
|
|
3061
|
+
this.refreshesInFlight.set(cpath, refresh);
|
|
3036
3062
|
return refresh;
|
|
3037
3063
|
}
|
|
3038
3064
|
async doRefreshFile(filePath, account) {
|