grepmax 0.26.20 → 0.26.22
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/.claude-plugin/marketplace.json +1 -1
- package/dist/commands/watch.js +21 -2
- package/dist/lib/daemon/daemon.js +58 -14
- package/dist/lib/index/ignore-patterns.js +34 -25
- package/dist/lib/index/watcher.js +6 -0
- package/dist/lib/store/vector-db.js +11 -0
- package/dist/lib/utils/keyed-mutex.js +6 -0
- package/dist/lib/utils/operation-coordinator.js +13 -2
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "grepmax",
|
|
11
11
|
"source": "./plugins/grepmax",
|
|
12
12
|
"description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
|
|
13
|
-
"version": "0.26.
|
|
13
|
+
"version": "0.26.22",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
package/dist/commands/watch.js
CHANGED
|
@@ -59,6 +59,9 @@ const process_1 = require("../lib/utils/process");
|
|
|
59
59
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
60
60
|
const project_root_1 = require("../lib/utils/project-root");
|
|
61
61
|
const watcher_store_1 = require("../lib/utils/watcher-store");
|
|
62
|
+
// Hard ceiling on signal-driven shutdown; comfortably above the daemon's own
|
|
63
|
+
// 30s operation-drain grace so the orderly path normally wins.
|
|
64
|
+
const SIGNAL_EXIT_BACKSTOP_MS = 90000;
|
|
62
65
|
const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
63
66
|
const IDLE_CHECK_INTERVAL_MS = 60 * 1000; // check every minute
|
|
64
67
|
exports.watch = new commander_1.Command("watch")
|
|
@@ -157,8 +160,24 @@ exports.watch = new commander_1.Command("watch")
|
|
|
157
160
|
installTimestampedOutput();
|
|
158
161
|
const { Daemon } = yield Promise.resolve().then(() => __importStar(require("../lib/daemon/daemon")));
|
|
159
162
|
const daemon = new Daemon();
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
// A shutdown that never resolves must still end the process: both
|
|
164
|
+
// signals arm a hard-exit backstop, the same way the lock-compromised
|
|
165
|
+
// path does. Without it the daemon sat idle in uv_run for minutes after
|
|
166
|
+
// SIGTERM (and ignored Activity Monitor's Quit) while a remove waited on
|
|
167
|
+
// a store lease that could never free.
|
|
168
|
+
const shutdownOnSignal = (signal) => {
|
|
169
|
+
const backstop = setTimeout(() => {
|
|
170
|
+
console.error(`[daemon] shutdown did not complete within ${SIGNAL_EXIT_BACKSTOP_MS / 1000}s of ${signal} — forcing exit`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}, SIGNAL_EXIT_BACKSTOP_MS);
|
|
173
|
+
backstop.unref();
|
|
174
|
+
daemon.shutdown().then(() => {
|
|
175
|
+
clearTimeout(backstop);
|
|
176
|
+
return (0, exit_1.gracefulExit)();
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
process.on("SIGINT", () => shutdownOnSignal("SIGINT"));
|
|
180
|
+
process.on("SIGTERM", () => shutdownOnSignal("SIGTERM"));
|
|
162
181
|
process.on("uncaughtException", (err) => {
|
|
163
182
|
console.error("[daemon] uncaughtException:", err);
|
|
164
183
|
daemon.shutdown().then(() => (0, exit_1.gracefulExit)(1));
|
|
@@ -44,6 +44,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
44
44
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
45
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
46
|
};
|
|
47
|
+
var _a;
|
|
47
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
49
|
exports.Daemon = void 0;
|
|
49
50
|
const fs = __importStar(require("node:fs"));
|
|
@@ -81,6 +82,10 @@ const watcher_manager_1 = require("./watcher-manager");
|
|
|
81
82
|
// drops, and orphan MLX cleanup. 4 hours keeps the daemon resident through a
|
|
82
83
|
// normal workday while still freeing resources overnight. Override with
|
|
83
84
|
// GMAX_DAEMON_IDLE_TIMEOUT_MS=<ms>; set to 0 (or negative) to disable.
|
|
85
|
+
// Grace period for admitted operations to settle during shutdown. See
|
|
86
|
+
// drainOperationsBounded. Env override exists for tests and for a user who
|
|
87
|
+
// would rather wait on a slow-but-progressing operation.
|
|
88
|
+
const SHUTDOWN_DRAIN_TIMEOUT_MS = Number((_a = process.env.GMAX_SHUTDOWN_DRAIN_TIMEOUT_MS) !== null && _a !== void 0 ? _a : 30000);
|
|
84
89
|
const DEFAULT_IDLE_TIMEOUT_MS = 4 * 60 * 60 * 1000;
|
|
85
90
|
const IDLE_TIMEOUT_MS = (() => {
|
|
86
91
|
const raw = process.env.GMAX_DAEMON_IDLE_TIMEOUT_MS;
|
|
@@ -1755,6 +1760,40 @@ class Daemon {
|
|
|
1755
1760
|
this.recycling = true;
|
|
1756
1761
|
void this.shutdown().finally(() => process.exit(0));
|
|
1757
1762
|
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Wait for admitted operations to settle, but never forever. Every operation
|
|
1765
|
+
* has just been aborted; one that still does not return within the grace
|
|
1766
|
+
* period is wedged on something shutdown cannot influence, and holding the
|
|
1767
|
+
* daemon alive for it only leaves the user with a process that ignores
|
|
1768
|
+
* SIGTERM. Resources are released regardless — a wedged op loses its work
|
|
1769
|
+
* either way, and the next start reconciles the store.
|
|
1770
|
+
*/
|
|
1771
|
+
drainOperationsBounded(...drains) {
|
|
1772
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1773
|
+
let timer;
|
|
1774
|
+
const timeout = new Promise((resolve) => {
|
|
1775
|
+
timer = setTimeout(() => resolve("timeout"), SHUTDOWN_DRAIN_TIMEOUT_MS);
|
|
1776
|
+
timer.unref();
|
|
1777
|
+
});
|
|
1778
|
+
try {
|
|
1779
|
+
const outcome = yield Promise.race([
|
|
1780
|
+
Promise.all(drains).then(() => "drained"),
|
|
1781
|
+
timeout,
|
|
1782
|
+
]);
|
|
1783
|
+
if (outcome === "timeout") {
|
|
1784
|
+
const ops = this.operations.activeOperationNames();
|
|
1785
|
+
const locks = this.projectMutex.pendingKeys();
|
|
1786
|
+
console.error(`[daemon] shutdown drain timed out after ${SHUTDOWN_DRAIN_TIMEOUT_MS / 1000}s — ` +
|
|
1787
|
+
`abandoning ${ops.length} operation(s) [${ops.join(", ")}] and ` +
|
|
1788
|
+
`${locks.length} project lock(s) [${locks.join(", ")}] to finish shutdown`);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
finally {
|
|
1792
|
+
if (timer)
|
|
1793
|
+
clearTimeout(timer);
|
|
1794
|
+
}
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1758
1797
|
shutdown(opts = {}) {
|
|
1759
1798
|
if (!this.shutdownPromise) {
|
|
1760
1799
|
this.shutdownPromise = this.performShutdown(opts);
|
|
@@ -1763,7 +1802,7 @@ class Daemon {
|
|
|
1763
1802
|
}
|
|
1764
1803
|
performShutdown(opts) {
|
|
1765
1804
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1766
|
-
var _a, _b, _c, _d;
|
|
1805
|
+
var _a, _b, _c, _d, _e;
|
|
1767
1806
|
this.shuttingDown = true;
|
|
1768
1807
|
this.ready = false;
|
|
1769
1808
|
const strictResourceShutdown = this.hasUnfinishedRebuild();
|
|
@@ -1795,18 +1834,18 @@ class Daemon {
|
|
|
1795
1834
|
try {
|
|
1796
1835
|
fs.unlinkSync(config_1.PATHS.daemonSocket);
|
|
1797
1836
|
}
|
|
1798
|
-
catch (
|
|
1837
|
+
catch (_f) { }
|
|
1799
1838
|
try {
|
|
1800
1839
|
fs.unlinkSync(config_1.PATHS.daemonPidFile);
|
|
1801
1840
|
}
|
|
1802
|
-
catch (
|
|
1841
|
+
catch (_g) { }
|
|
1803
1842
|
if (this.releaseLock) {
|
|
1804
1843
|
const release = this.releaseLock;
|
|
1805
1844
|
this.releaseLock = null;
|
|
1806
1845
|
try {
|
|
1807
1846
|
yield release();
|
|
1808
1847
|
}
|
|
1809
|
-
catch (
|
|
1848
|
+
catch (_h) { }
|
|
1810
1849
|
}
|
|
1811
1850
|
if (this.heartbeatInterval)
|
|
1812
1851
|
clearInterval(this.heartbeatInterval);
|
|
@@ -1823,16 +1862,21 @@ class Daemon {
|
|
|
1823
1862
|
for (const ac of this.shutdownAbortControllers) {
|
|
1824
1863
|
ac.abort(new operation_coordinator_1.OperationClosedError());
|
|
1825
1864
|
}
|
|
1865
|
+
// An operation blocked in StoreLease.acquireExclusive (remove, repair)
|
|
1866
|
+
// only listens to the VectorDB's own lease abort, which `vectorDb.close()`
|
|
1867
|
+
// fires — after the drain below. Fire it now, or a lease that never frees
|
|
1868
|
+
// (see known-limitations: recycled-PID reader marker) deadlocks shutdown.
|
|
1869
|
+
(_a = this.vectorDb) === null || _a === void 0 ? void 0 : _a.abortLeaseWaits();
|
|
1826
1870
|
const operationDrain = this.operations.close();
|
|
1827
1871
|
const projectDrain = this.projectMutex.close();
|
|
1828
1872
|
// Abort catchup/recovery and remove each processor before worker teardown.
|
|
1829
1873
|
yield this.watcherManager.quiesceAll();
|
|
1830
|
-
yield
|
|
1874
|
+
yield this.drainOperationsBounded(operationDrain, projectDrain);
|
|
1831
1875
|
// Stop LLM server if running
|
|
1832
1876
|
try {
|
|
1833
|
-
yield ((
|
|
1877
|
+
yield ((_b = this.llmServer) === null || _b === void 0 ? void 0 : _b.stop());
|
|
1834
1878
|
}
|
|
1835
|
-
catch (
|
|
1879
|
+
catch (_j) { }
|
|
1836
1880
|
// Destroy worker pool to prevent orphaned child processes
|
|
1837
1881
|
if (this.workerPool) {
|
|
1838
1882
|
if (strictResourceShutdown) {
|
|
@@ -1844,7 +1888,7 @@ class Daemon {
|
|
|
1844
1888
|
try {
|
|
1845
1889
|
yield this.workerPool.destroy();
|
|
1846
1890
|
}
|
|
1847
|
-
catch (
|
|
1891
|
+
catch (_k) { }
|
|
1848
1892
|
}
|
|
1849
1893
|
this.workerPool = null;
|
|
1850
1894
|
this.resources = null;
|
|
@@ -1853,7 +1897,7 @@ class Daemon {
|
|
|
1853
1897
|
try {
|
|
1854
1898
|
yield (0, pool_1.destroyWorkerPool)();
|
|
1855
1899
|
}
|
|
1856
|
-
catch (
|
|
1900
|
+
catch (_l) { }
|
|
1857
1901
|
}
|
|
1858
1902
|
// Stop MLX embed server only after worker requests have drained.
|
|
1859
1903
|
yield this.mlxServerManager.stopMlxServer();
|
|
@@ -1865,17 +1909,17 @@ class Daemon {
|
|
|
1865
1909
|
this.processors.clear();
|
|
1866
1910
|
// Close shared resources
|
|
1867
1911
|
try {
|
|
1868
|
-
yield ((
|
|
1912
|
+
yield ((_c = this.metaCache) === null || _c === void 0 ? void 0 : _c.close());
|
|
1869
1913
|
}
|
|
1870
|
-
catch (
|
|
1914
|
+
catch (_m) { }
|
|
1871
1915
|
if (strictResourceShutdown) {
|
|
1872
|
-
yield ((
|
|
1916
|
+
yield ((_d = this.vectorDb) === null || _d === void 0 ? void 0 : _d.close({ requireClosed: true }));
|
|
1873
1917
|
}
|
|
1874
1918
|
else {
|
|
1875
1919
|
try {
|
|
1876
|
-
yield ((
|
|
1920
|
+
yield ((_e = this.vectorDb) === null || _e === void 0 ? void 0 : _e.close());
|
|
1877
1921
|
}
|
|
1878
|
-
catch (
|
|
1922
|
+
catch (_o) { }
|
|
1879
1923
|
}
|
|
1880
1924
|
yield serverClosed;
|
|
1881
1925
|
clearTimeout(forceCloseConnections);
|
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_IGNORE_PATTERNS = void 0;
|
|
4
2
|
// Shared ignore patterns for filesystem walks.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DEFAULT_IGNORE_PATTERNS = exports.GENERATED_SOURCE_PATTERNS = void 0;
|
|
5
|
+
// Machine-generated source (floods the index + ranks codegen as god nodes).
|
|
6
|
+
// Content-based @generated/DO-NOT-EDIT header sniff (file-utils.ts) catches the
|
|
7
|
+
// rest; these are the unambiguous filename/dir conventions.
|
|
8
|
+
//
|
|
9
|
+
// Exported separately because the FSEvents watcher must ignore these at the
|
|
10
|
+
// event source too: a codegen run rewriting thousands of *.graphql.swift files
|
|
11
|
+
// overflowed the FSEvents client buffer ("Events were dropped") ~290 times in
|
|
12
|
+
// three days and pushed the project into 5-minute poll mode, even though the
|
|
13
|
+
// file policy then discarded every one of those events as "0 reindexed".
|
|
14
|
+
exports.GENERATED_SOURCE_PATTERNS = [
|
|
15
|
+
"**/__generated__/**", // Relay / graphql-codegen
|
|
16
|
+
"**/Generated/**", // Apollo iOS, Xcode codegen
|
|
17
|
+
"*.graphql.swift", // Apollo iOS operations
|
|
18
|
+
"*.pb.go", // protobuf (Go)
|
|
19
|
+
"*.pb.cc",
|
|
20
|
+
"*.pb.h", // protobuf (C++)
|
|
21
|
+
"*_pb2.py",
|
|
22
|
+
"*_pb2.pyi",
|
|
23
|
+
"*_pb2_grpc.py", // protobuf (Python)
|
|
24
|
+
"*.g.dart",
|
|
25
|
+
"*.freezed.dart",
|
|
26
|
+
"*.gr.dart", // Dart codegen
|
|
27
|
+
"*.designer.cs", // C# designer
|
|
28
|
+
"*.generated.ts",
|
|
29
|
+
"*.generated.tsx", // graphql-codegen / common TS
|
|
30
|
+
// graphql-codegen client-preset output dir (emits no @generated banner, so
|
|
31
|
+
// the header sniff can't catch these — match the canonical filenames).
|
|
32
|
+
"**/gql/graphql.ts",
|
|
33
|
+
"**/gql/gql.ts",
|
|
34
|
+
"**/gql/fragment-masking.ts",
|
|
35
|
+
];
|
|
5
36
|
// Keep JSON files (package.json, tsconfig.json, etc.) but skip lockfiles and obvious binaries.
|
|
6
37
|
exports.DEFAULT_IGNORE_PATTERNS = [
|
|
7
38
|
"*.lock",
|
|
@@ -43,29 +74,7 @@ exports.DEFAULT_IGNORE_PATTERNS = [
|
|
|
43
74
|
"*.min.css",
|
|
44
75
|
"*.map",
|
|
45
76
|
"*.wasm",
|
|
46
|
-
|
|
47
|
-
// Content-based @generated/DO-NOT-EDIT header sniff (file-utils.ts) catches the
|
|
48
|
-
// rest; these are the unambiguous filename/dir conventions.
|
|
49
|
-
"**/__generated__/**", // Relay / graphql-codegen
|
|
50
|
-
"**/Generated/**", // Apollo iOS, Xcode codegen
|
|
51
|
-
"*.graphql.swift", // Apollo iOS operations
|
|
52
|
-
"*.pb.go", // protobuf (Go)
|
|
53
|
-
"*.pb.cc",
|
|
54
|
-
"*.pb.h", // protobuf (C++)
|
|
55
|
-
"*_pb2.py",
|
|
56
|
-
"*_pb2.pyi",
|
|
57
|
-
"*_pb2_grpc.py", // protobuf (Python)
|
|
58
|
-
"*.g.dart",
|
|
59
|
-
"*.freezed.dart",
|
|
60
|
-
"*.gr.dart", // Dart codegen
|
|
61
|
-
"*.designer.cs", // C# designer
|
|
62
|
-
"*.generated.ts",
|
|
63
|
-
"*.generated.tsx", // graphql-codegen / common TS
|
|
64
|
-
// graphql-codegen client-preset output dir (emits no @generated banner, so
|
|
65
|
-
// the header sniff can't catch these — match the canonical filenames).
|
|
66
|
-
"**/gql/graphql.ts",
|
|
67
|
-
"**/gql/gql.ts",
|
|
68
|
-
"**/gql/fragment-masking.ts",
|
|
77
|
+
...exports.GENERATED_SOURCE_PATTERNS,
|
|
69
78
|
// Test fixtures and benchmark data
|
|
70
79
|
"**/fixtures/**",
|
|
71
80
|
"**/benchmark/**",
|
|
@@ -56,6 +56,7 @@ const watcher = __importStar(require("@parcel/watcher"));
|
|
|
56
56
|
const batch_processor_1 = require("./batch-processor");
|
|
57
57
|
const cache_coherence_1 = require("./cache-coherence");
|
|
58
58
|
const file_policy_1 = require("./file-policy");
|
|
59
|
+
const ignore_patterns_1 = require("./ignore-patterns");
|
|
59
60
|
const walker_1 = require("./walker");
|
|
60
61
|
// Directory names ignored at ANY depth. @parcel/watcher treats a non-glob
|
|
61
62
|
// ignore entry as a literal path resolved against the watch root, so a bare
|
|
@@ -94,6 +95,11 @@ exports.WATCHER_IGNORE_GLOBS = [
|
|
|
94
95
|
...IGNORED_DIR_NAMES.flatMap((name) => [`**/${name}`, `**/${name}/**`]),
|
|
95
96
|
"**/*.tmp.*", // editor atomic save artifacts
|
|
96
97
|
"**/*.sb-*", // Xcode swap files
|
|
98
|
+
// Codegen output never reaches the index (file policy drops it), so don't
|
|
99
|
+
// let it reach the watcher either — it is the dominant source of FSEvents
|
|
100
|
+
// buffer overflows on large projects. Bare "*.ext" patterns are anchored to
|
|
101
|
+
// the root by picomatch, so prefix them to match at any depth.
|
|
102
|
+
...ignore_patterns_1.GENERATED_SOURCE_PATTERNS.map((p) => p.startsWith("**/") ? p : `**/${p}`),
|
|
97
103
|
];
|
|
98
104
|
function startWatcher(opts) {
|
|
99
105
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -497,6 +497,17 @@ class VectorDB {
|
|
|
497
497
|
* Run a destructive table mutation while holding the process-wide exclusive
|
|
498
498
|
* store intent. New local writes stop before existing activity is drained.
|
|
499
499
|
*/
|
|
500
|
+
/**
|
|
501
|
+
* Cancel every in-flight wait on the store lease (exclusive-mutation
|
|
502
|
+
* acquisition, initial lease attach). Called by the daemon at the start of
|
|
503
|
+
* shutdown, *before* it drains active operations: a `remove`/`repair` that is
|
|
504
|
+
* polling for the exclusive lease would otherwise hold its operation slot
|
|
505
|
+
* until the lease deadline, and shutdown would wait on it — the lease abort
|
|
506
|
+
* in `close()` never fires because `close()` runs after the drain. Idempotent.
|
|
507
|
+
*/
|
|
508
|
+
abortLeaseWaits() {
|
|
509
|
+
this.leaseAbort.abort();
|
|
510
|
+
}
|
|
500
511
|
withExclusiveTableMutation(mutation) {
|
|
501
512
|
return __awaiter(this, void 0, void 0, function* () {
|
|
502
513
|
if (this.closed)
|
|
@@ -28,6 +28,12 @@ class KeyedMutex {
|
|
|
28
28
|
}
|
|
29
29
|
return count;
|
|
30
30
|
}
|
|
31
|
+
/** Keys currently held or queued — for shutdown diagnostics. */
|
|
32
|
+
pendingKeys() {
|
|
33
|
+
return [...this.keys.entries()]
|
|
34
|
+
.filter(([, state]) => state.locked || state.queue.length > 0)
|
|
35
|
+
.map(([key]) => key);
|
|
36
|
+
}
|
|
31
37
|
run(key, signal, fn) {
|
|
32
38
|
const task = (() => __awaiter(this, void 0, void 0, function* () {
|
|
33
39
|
yield this.acquire(key, signal);
|
|
@@ -39,6 +39,7 @@ class OperationCoordinator {
|
|
|
39
39
|
this.controllers = new Set();
|
|
40
40
|
this.activeTasks = new Set();
|
|
41
41
|
this.sharedTasks = new Set();
|
|
42
|
+
this.taskNames = new Map();
|
|
42
43
|
this.closePromise = null;
|
|
43
44
|
}
|
|
44
45
|
get status() {
|
|
@@ -47,7 +48,11 @@ class OperationCoordinator {
|
|
|
47
48
|
get activeCount() {
|
|
48
49
|
return this.activeTasks.size;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
/** Names of admitted operations that have not settled — for shutdown diagnostics. */
|
|
52
|
+
activeOperationNames() {
|
|
53
|
+
return [...this.activeTasks].map((task) => { var _a; return (_a = this.taskNames.get(task)) !== null && _a !== void 0 ? _a : "?"; });
|
|
54
|
+
}
|
|
55
|
+
runShared(name, signal, fn) {
|
|
51
56
|
try {
|
|
52
57
|
this.assertSharedAdmission();
|
|
53
58
|
}
|
|
@@ -65,11 +70,13 @@ class OperationCoordinator {
|
|
|
65
70
|
}))();
|
|
66
71
|
this.activeTasks.add(task);
|
|
67
72
|
this.sharedTasks.add(task);
|
|
73
|
+
this.taskNames.set(task, name);
|
|
68
74
|
const cleanup = () => {
|
|
69
75
|
unlink();
|
|
70
76
|
this.controllers.delete(controller);
|
|
71
77
|
this.activeTasks.delete(task);
|
|
72
78
|
this.sharedTasks.delete(task);
|
|
79
|
+
this.taskNames.delete(task);
|
|
73
80
|
};
|
|
74
81
|
void task.then(cleanup, cleanup);
|
|
75
82
|
return task;
|
|
@@ -107,7 +114,11 @@ class OperationCoordinator {
|
|
|
107
114
|
}
|
|
108
115
|
}))();
|
|
109
116
|
this.activeTasks.add(task);
|
|
110
|
-
|
|
117
|
+
this.taskNames.set(task, name);
|
|
118
|
+
const cleanup = () => {
|
|
119
|
+
this.activeTasks.delete(task);
|
|
120
|
+
this.taskNames.delete(task);
|
|
121
|
+
};
|
|
111
122
|
void task.then(cleanup, cleanup);
|
|
112
123
|
return task;
|
|
113
124
|
}
|
package/package.json
CHANGED