ccsini 0.1.51 → 0.1.53
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/index.js +1971 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27876,7 +27876,7 @@ function decodeProjectPath(encoded) {
|
|
|
27876
27876
|
}
|
|
27877
27877
|
|
|
27878
27878
|
// ../shared/src/constants.ts
|
|
27879
|
-
var DEFAULT_CATEGORY_PATTERNS, MERGE_STRATEGIES, NEVER_SYNC_PATTERNS, SESSION_SYNC_DEFAULTS, JWT_EXPIRY_SECONDS = 900, MAX_CONCURRENT_TRANSFERS = 50;
|
|
27879
|
+
var DEFAULT_CATEGORY_PATTERNS, MERGE_STRATEGIES, NEVER_SYNC_PATTERNS, SESSION_SYNC_DEFAULTS, JWT_EXPIRY_SECONDS = 900, DAEMON_DEBOUNCE_MS = 5000, DAEMON_INTERVAL_MS = 30000, MAX_CONCURRENT_TRANSFERS = 50;
|
|
27880
27880
|
var init_constants = __esm(() => {
|
|
27881
27881
|
DEFAULT_CATEGORY_PATTERNS = {
|
|
27882
27882
|
session: ["projects/**/*.jsonl"],
|
|
@@ -28020,7 +28020,7 @@ var {
|
|
|
28020
28020
|
} = import__.default;
|
|
28021
28021
|
|
|
28022
28022
|
// src/version.ts
|
|
28023
|
-
var VERSION = "0.1.
|
|
28023
|
+
var VERSION = "0.1.53";
|
|
28024
28024
|
|
|
28025
28025
|
// src/commands/init.ts
|
|
28026
28026
|
init_source();
|
|
@@ -29080,10 +29080,11 @@ class CcsiniClient {
|
|
|
29080
29080
|
throw new Error("Failed to reset account data");
|
|
29081
29081
|
return res.json();
|
|
29082
29082
|
}
|
|
29083
|
-
async heartbeat() {
|
|
29083
|
+
async heartbeat(mode) {
|
|
29084
29084
|
await fetch(`${this.apiUrl}/api/sync/heartbeat`, {
|
|
29085
29085
|
method: "POST",
|
|
29086
|
-
headers: this.getHeaders()
|
|
29086
|
+
headers: this.getHeaders(),
|
|
29087
|
+
body: JSON.stringify({ mode: mode ?? "hook" })
|
|
29087
29088
|
});
|
|
29088
29089
|
}
|
|
29089
29090
|
async logSyncEvent(event) {
|
|
@@ -29754,6 +29755,7 @@ async function uninstallLinux() {
|
|
|
29754
29755
|
}
|
|
29755
29756
|
|
|
29756
29757
|
// src/commands/init.ts
|
|
29758
|
+
import { spawn as spawn2 } from "child_process";
|
|
29757
29759
|
function registerInitCommand(program2) {
|
|
29758
29760
|
program2.command("init").description("Connect this device to your ccsini account").option("--token <token>", "Setup token from dashboard").action(async (opts) => {
|
|
29759
29761
|
const configDir = getConfigDir();
|
|
@@ -29932,12 +29934,25 @@ function registerInitCommand(program2) {
|
|
|
29932
29934
|
try {
|
|
29933
29935
|
await installHeartbeatScheduler();
|
|
29934
29936
|
} catch {}
|
|
29937
|
+
saveSpinner.text = "Starting background daemon...";
|
|
29938
|
+
let daemonStarted = false;
|
|
29939
|
+
try {
|
|
29940
|
+
const isWin = platform2() === "win32";
|
|
29941
|
+
const child = spawn2("ccsini", ["daemon", "_run"], {
|
|
29942
|
+
detached: true,
|
|
29943
|
+
stdio: "ignore",
|
|
29944
|
+
...isWin ? { shell: true } : {}
|
|
29945
|
+
});
|
|
29946
|
+
child.unref();
|
|
29947
|
+
daemonStarted = true;
|
|
29948
|
+
} catch {}
|
|
29935
29949
|
saveSpinner.succeed("Setup complete!");
|
|
29936
29950
|
console.log(source_default.green(`
|
|
29937
29951
|
\u2713 Encryption keys generated`));
|
|
29938
29952
|
console.log(source_default.green(" \u2713 Device registered"));
|
|
29939
29953
|
console.log(source_default.green(" \u2713 Claude Code hooks installed"));
|
|
29940
29954
|
console.log(source_default.green(" \u2713 Heartbeat scheduler installed"));
|
|
29955
|
+
console.log(source_default.green(daemonStarted ? " \u2713 Background daemon started" : " \u2717 Daemon not started (run 'ccsini daemon start')"));
|
|
29941
29956
|
console.log(source_default.green(" \u2713 Auto-sync is active"));
|
|
29942
29957
|
console.log(source_default.dim(`
|
|
29943
29958
|
Just use 'claude' as normal. Sync happens automatically.
|
|
@@ -30743,6 +30758,1956 @@ ${remaining.length} conflict(s) remaining.`));
|
|
|
30743
30758
|
});
|
|
30744
30759
|
}
|
|
30745
30760
|
|
|
30761
|
+
// src/commands/daemon.ts
|
|
30762
|
+
import { spawn as spawn3 } from "child_process";
|
|
30763
|
+
import { readFile as readFile11, rm as rm2 } from "fs/promises";
|
|
30764
|
+
import { platform as platform4 } from "os";
|
|
30765
|
+
|
|
30766
|
+
// src/daemon/runner.ts
|
|
30767
|
+
import { readFile as readFile10, writeFile as writeFile10 } from "fs/promises";
|
|
30768
|
+
import { join as join15 } from "path";
|
|
30769
|
+
import { platform as platform3 } from "os";
|
|
30770
|
+
import { appendFileSync } from "fs";
|
|
30771
|
+
init_auth();
|
|
30772
|
+
|
|
30773
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
30774
|
+
import { EventEmitter } from "events";
|
|
30775
|
+
import { stat as statcb, Stats } from "fs";
|
|
30776
|
+
import { readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
30777
|
+
import * as sp2 from "path";
|
|
30778
|
+
|
|
30779
|
+
// ../../node_modules/.bun/readdirp@5.0.0/node_modules/readdirp/index.js
|
|
30780
|
+
import { lstat, readdir as readdir3, realpath, stat as stat2 } from "fs/promises";
|
|
30781
|
+
import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "path";
|
|
30782
|
+
import { Readable } from "stream";
|
|
30783
|
+
var EntryTypes = {
|
|
30784
|
+
FILE_TYPE: "files",
|
|
30785
|
+
DIR_TYPE: "directories",
|
|
30786
|
+
FILE_DIR_TYPE: "files_directories",
|
|
30787
|
+
EVERYTHING_TYPE: "all"
|
|
30788
|
+
};
|
|
30789
|
+
var defaultOptions = {
|
|
30790
|
+
root: ".",
|
|
30791
|
+
fileFilter: (_entryInfo) => true,
|
|
30792
|
+
directoryFilter: (_entryInfo) => true,
|
|
30793
|
+
type: EntryTypes.FILE_TYPE,
|
|
30794
|
+
lstat: false,
|
|
30795
|
+
depth: 2147483648,
|
|
30796
|
+
alwaysStat: false,
|
|
30797
|
+
highWaterMark: 4096
|
|
30798
|
+
};
|
|
30799
|
+
Object.freeze(defaultOptions);
|
|
30800
|
+
var RECURSIVE_ERROR_CODE = "READDIRP_RECURSIVE_ERROR";
|
|
30801
|
+
var NORMAL_FLOW_ERRORS = new Set(["ENOENT", "EPERM", "EACCES", "ELOOP", RECURSIVE_ERROR_CODE]);
|
|
30802
|
+
var ALL_TYPES = [
|
|
30803
|
+
EntryTypes.DIR_TYPE,
|
|
30804
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
30805
|
+
EntryTypes.FILE_DIR_TYPE,
|
|
30806
|
+
EntryTypes.FILE_TYPE
|
|
30807
|
+
];
|
|
30808
|
+
var DIR_TYPES = new Set([
|
|
30809
|
+
EntryTypes.DIR_TYPE,
|
|
30810
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
30811
|
+
EntryTypes.FILE_DIR_TYPE
|
|
30812
|
+
]);
|
|
30813
|
+
var FILE_TYPES = new Set([
|
|
30814
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
30815
|
+
EntryTypes.FILE_DIR_TYPE,
|
|
30816
|
+
EntryTypes.FILE_TYPE
|
|
30817
|
+
]);
|
|
30818
|
+
var isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);
|
|
30819
|
+
var wantBigintFsStats = process.platform === "win32";
|
|
30820
|
+
var emptyFn = (_entryInfo) => true;
|
|
30821
|
+
var normalizeFilter = (filter2) => {
|
|
30822
|
+
if (filter2 === undefined)
|
|
30823
|
+
return emptyFn;
|
|
30824
|
+
if (typeof filter2 === "function")
|
|
30825
|
+
return filter2;
|
|
30826
|
+
if (typeof filter2 === "string") {
|
|
30827
|
+
const fl = filter2.trim();
|
|
30828
|
+
return (entry) => entry.basename === fl;
|
|
30829
|
+
}
|
|
30830
|
+
if (Array.isArray(filter2)) {
|
|
30831
|
+
const trItems = filter2.map((item) => item.trim());
|
|
30832
|
+
return (entry) => trItems.some((f) => entry.basename === f);
|
|
30833
|
+
}
|
|
30834
|
+
return emptyFn;
|
|
30835
|
+
};
|
|
30836
|
+
|
|
30837
|
+
class ReaddirpStream extends Readable {
|
|
30838
|
+
parents;
|
|
30839
|
+
reading;
|
|
30840
|
+
parent;
|
|
30841
|
+
_stat;
|
|
30842
|
+
_maxDepth;
|
|
30843
|
+
_wantsDir;
|
|
30844
|
+
_wantsFile;
|
|
30845
|
+
_wantsEverything;
|
|
30846
|
+
_root;
|
|
30847
|
+
_isDirent;
|
|
30848
|
+
_statsProp;
|
|
30849
|
+
_rdOptions;
|
|
30850
|
+
_fileFilter;
|
|
30851
|
+
_directoryFilter;
|
|
30852
|
+
constructor(options = {}) {
|
|
30853
|
+
super({
|
|
30854
|
+
objectMode: true,
|
|
30855
|
+
autoDestroy: true,
|
|
30856
|
+
highWaterMark: options.highWaterMark
|
|
30857
|
+
});
|
|
30858
|
+
const opts = { ...defaultOptions, ...options };
|
|
30859
|
+
const { root, type } = opts;
|
|
30860
|
+
this._fileFilter = normalizeFilter(opts.fileFilter);
|
|
30861
|
+
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
30862
|
+
const statMethod = opts.lstat ? lstat : stat2;
|
|
30863
|
+
if (wantBigintFsStats) {
|
|
30864
|
+
this._stat = (path2) => statMethod(path2, { bigint: true });
|
|
30865
|
+
} else {
|
|
30866
|
+
this._stat = statMethod;
|
|
30867
|
+
}
|
|
30868
|
+
this._maxDepth = opts.depth != null && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
|
|
30869
|
+
this._wantsDir = type ? DIR_TYPES.has(type) : false;
|
|
30870
|
+
this._wantsFile = type ? FILE_TYPES.has(type) : false;
|
|
30871
|
+
this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
|
|
30872
|
+
this._root = presolve(root);
|
|
30873
|
+
this._isDirent = !opts.alwaysStat;
|
|
30874
|
+
this._statsProp = this._isDirent ? "dirent" : "stats";
|
|
30875
|
+
this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
|
|
30876
|
+
this.parents = [this._exploreDir(root, 1)];
|
|
30877
|
+
this.reading = false;
|
|
30878
|
+
this.parent = undefined;
|
|
30879
|
+
}
|
|
30880
|
+
async _read(batch) {
|
|
30881
|
+
if (this.reading)
|
|
30882
|
+
return;
|
|
30883
|
+
this.reading = true;
|
|
30884
|
+
try {
|
|
30885
|
+
while (!this.destroyed && batch > 0) {
|
|
30886
|
+
const par = this.parent;
|
|
30887
|
+
const fil = par && par.files;
|
|
30888
|
+
if (fil && fil.length > 0) {
|
|
30889
|
+
const { path: path2, depth } = par;
|
|
30890
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path2));
|
|
30891
|
+
const awaited = await Promise.all(slice);
|
|
30892
|
+
for (const entry of awaited) {
|
|
30893
|
+
if (!entry)
|
|
30894
|
+
continue;
|
|
30895
|
+
if (this.destroyed)
|
|
30896
|
+
return;
|
|
30897
|
+
const entryType = await this._getEntryType(entry);
|
|
30898
|
+
if (entryType === "directory" && this._directoryFilter(entry)) {
|
|
30899
|
+
if (depth <= this._maxDepth) {
|
|
30900
|
+
this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
|
|
30901
|
+
}
|
|
30902
|
+
if (this._wantsDir) {
|
|
30903
|
+
this.push(entry);
|
|
30904
|
+
batch--;
|
|
30905
|
+
}
|
|
30906
|
+
} else if ((entryType === "file" || this._includeAsFile(entry)) && this._fileFilter(entry)) {
|
|
30907
|
+
if (this._wantsFile) {
|
|
30908
|
+
this.push(entry);
|
|
30909
|
+
batch--;
|
|
30910
|
+
}
|
|
30911
|
+
}
|
|
30912
|
+
}
|
|
30913
|
+
} else {
|
|
30914
|
+
const parent = this.parents.pop();
|
|
30915
|
+
if (!parent) {
|
|
30916
|
+
this.push(null);
|
|
30917
|
+
break;
|
|
30918
|
+
}
|
|
30919
|
+
this.parent = await parent;
|
|
30920
|
+
if (this.destroyed)
|
|
30921
|
+
return;
|
|
30922
|
+
}
|
|
30923
|
+
}
|
|
30924
|
+
} catch (error) {
|
|
30925
|
+
this.destroy(error);
|
|
30926
|
+
} finally {
|
|
30927
|
+
this.reading = false;
|
|
30928
|
+
}
|
|
30929
|
+
}
|
|
30930
|
+
async _exploreDir(path2, depth) {
|
|
30931
|
+
let files;
|
|
30932
|
+
try {
|
|
30933
|
+
files = await readdir3(path2, this._rdOptions);
|
|
30934
|
+
} catch (error) {
|
|
30935
|
+
this._onError(error);
|
|
30936
|
+
}
|
|
30937
|
+
return { files, depth, path: path2 };
|
|
30938
|
+
}
|
|
30939
|
+
async _formatEntry(dirent, path2) {
|
|
30940
|
+
let entry;
|
|
30941
|
+
const basename = this._isDirent ? dirent.name : dirent;
|
|
30942
|
+
try {
|
|
30943
|
+
const fullPath = presolve(pjoin(path2, basename));
|
|
30944
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename };
|
|
30945
|
+
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
30946
|
+
} catch (err) {
|
|
30947
|
+
this._onError(err);
|
|
30948
|
+
return;
|
|
30949
|
+
}
|
|
30950
|
+
return entry;
|
|
30951
|
+
}
|
|
30952
|
+
_onError(err) {
|
|
30953
|
+
if (isNormalFlowError(err) && !this.destroyed) {
|
|
30954
|
+
this.emit("warn", err);
|
|
30955
|
+
} else {
|
|
30956
|
+
this.destroy(err);
|
|
30957
|
+
}
|
|
30958
|
+
}
|
|
30959
|
+
async _getEntryType(entry) {
|
|
30960
|
+
if (!entry && this._statsProp in entry) {
|
|
30961
|
+
return "";
|
|
30962
|
+
}
|
|
30963
|
+
const stats = entry[this._statsProp];
|
|
30964
|
+
if (stats.isFile())
|
|
30965
|
+
return "file";
|
|
30966
|
+
if (stats.isDirectory())
|
|
30967
|
+
return "directory";
|
|
30968
|
+
if (stats && stats.isSymbolicLink()) {
|
|
30969
|
+
const full = entry.fullPath;
|
|
30970
|
+
try {
|
|
30971
|
+
const entryRealPath = await realpath(full);
|
|
30972
|
+
const entryRealPathStats = await lstat(entryRealPath);
|
|
30973
|
+
if (entryRealPathStats.isFile()) {
|
|
30974
|
+
return "file";
|
|
30975
|
+
}
|
|
30976
|
+
if (entryRealPathStats.isDirectory()) {
|
|
30977
|
+
const len = entryRealPath.length;
|
|
30978
|
+
if (full.startsWith(entryRealPath) && full.substr(len, 1) === psep) {
|
|
30979
|
+
const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
|
|
30980
|
+
recursiveError.code = RECURSIVE_ERROR_CODE;
|
|
30981
|
+
return this._onError(recursiveError);
|
|
30982
|
+
}
|
|
30983
|
+
return "directory";
|
|
30984
|
+
}
|
|
30985
|
+
} catch (error) {
|
|
30986
|
+
this._onError(error);
|
|
30987
|
+
return "";
|
|
30988
|
+
}
|
|
30989
|
+
}
|
|
30990
|
+
}
|
|
30991
|
+
_includeAsFile(entry) {
|
|
30992
|
+
const stats = entry && entry[this._statsProp];
|
|
30993
|
+
return stats && this._wantsEverything && !stats.isDirectory();
|
|
30994
|
+
}
|
|
30995
|
+
}
|
|
30996
|
+
function readdirp(root, options = {}) {
|
|
30997
|
+
let type = options.entryType || options.type;
|
|
30998
|
+
if (type === "both")
|
|
30999
|
+
type = EntryTypes.FILE_DIR_TYPE;
|
|
31000
|
+
if (type)
|
|
31001
|
+
options.type = type;
|
|
31002
|
+
if (!root) {
|
|
31003
|
+
throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");
|
|
31004
|
+
} else if (typeof root !== "string") {
|
|
31005
|
+
throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");
|
|
31006
|
+
} else if (type && !ALL_TYPES.includes(type)) {
|
|
31007
|
+
throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(", ")}`);
|
|
31008
|
+
}
|
|
31009
|
+
options.root = root;
|
|
31010
|
+
return new ReaddirpStream(options);
|
|
31011
|
+
}
|
|
31012
|
+
|
|
31013
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
31014
|
+
import { watch as fs_watch, unwatchFile, watchFile } from "fs";
|
|
31015
|
+
import { realpath as fsrealpath, lstat as lstat2, open, stat as stat3 } from "fs/promises";
|
|
31016
|
+
import { type as osType } from "os";
|
|
31017
|
+
import * as sp from "path";
|
|
31018
|
+
var STR_DATA = "data";
|
|
31019
|
+
var STR_END = "end";
|
|
31020
|
+
var STR_CLOSE = "close";
|
|
31021
|
+
var EMPTY_FN = () => {};
|
|
31022
|
+
var pl = process.platform;
|
|
31023
|
+
var isWindows = pl === "win32";
|
|
31024
|
+
var isMacos = pl === "darwin";
|
|
31025
|
+
var isLinux = pl === "linux";
|
|
31026
|
+
var isFreeBSD = pl === "freebsd";
|
|
31027
|
+
var isIBMi = osType() === "OS400";
|
|
31028
|
+
var EVENTS = {
|
|
31029
|
+
ALL: "all",
|
|
31030
|
+
READY: "ready",
|
|
31031
|
+
ADD: "add",
|
|
31032
|
+
CHANGE: "change",
|
|
31033
|
+
ADD_DIR: "addDir",
|
|
31034
|
+
UNLINK: "unlink",
|
|
31035
|
+
UNLINK_DIR: "unlinkDir",
|
|
31036
|
+
RAW: "raw",
|
|
31037
|
+
ERROR: "error"
|
|
31038
|
+
};
|
|
31039
|
+
var EV = EVENTS;
|
|
31040
|
+
var THROTTLE_MODE_WATCH = "watch";
|
|
31041
|
+
var statMethods = { lstat: lstat2, stat: stat3 };
|
|
31042
|
+
var KEY_LISTENERS = "listeners";
|
|
31043
|
+
var KEY_ERR = "errHandlers";
|
|
31044
|
+
var KEY_RAW = "rawEmitters";
|
|
31045
|
+
var HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
|
|
31046
|
+
var binaryExtensions = new Set([
|
|
31047
|
+
"3dm",
|
|
31048
|
+
"3ds",
|
|
31049
|
+
"3g2",
|
|
31050
|
+
"3gp",
|
|
31051
|
+
"7z",
|
|
31052
|
+
"a",
|
|
31053
|
+
"aac",
|
|
31054
|
+
"adp",
|
|
31055
|
+
"afdesign",
|
|
31056
|
+
"afphoto",
|
|
31057
|
+
"afpub",
|
|
31058
|
+
"ai",
|
|
31059
|
+
"aif",
|
|
31060
|
+
"aiff",
|
|
31061
|
+
"alz",
|
|
31062
|
+
"ape",
|
|
31063
|
+
"apk",
|
|
31064
|
+
"appimage",
|
|
31065
|
+
"ar",
|
|
31066
|
+
"arj",
|
|
31067
|
+
"asf",
|
|
31068
|
+
"au",
|
|
31069
|
+
"avi",
|
|
31070
|
+
"bak",
|
|
31071
|
+
"baml",
|
|
31072
|
+
"bh",
|
|
31073
|
+
"bin",
|
|
31074
|
+
"bk",
|
|
31075
|
+
"bmp",
|
|
31076
|
+
"btif",
|
|
31077
|
+
"bz2",
|
|
31078
|
+
"bzip2",
|
|
31079
|
+
"cab",
|
|
31080
|
+
"caf",
|
|
31081
|
+
"cgm",
|
|
31082
|
+
"class",
|
|
31083
|
+
"cmx",
|
|
31084
|
+
"cpio",
|
|
31085
|
+
"cr2",
|
|
31086
|
+
"cur",
|
|
31087
|
+
"dat",
|
|
31088
|
+
"dcm",
|
|
31089
|
+
"deb",
|
|
31090
|
+
"dex",
|
|
31091
|
+
"djvu",
|
|
31092
|
+
"dll",
|
|
31093
|
+
"dmg",
|
|
31094
|
+
"dng",
|
|
31095
|
+
"doc",
|
|
31096
|
+
"docm",
|
|
31097
|
+
"docx",
|
|
31098
|
+
"dot",
|
|
31099
|
+
"dotm",
|
|
31100
|
+
"dra",
|
|
31101
|
+
"DS_Store",
|
|
31102
|
+
"dsk",
|
|
31103
|
+
"dts",
|
|
31104
|
+
"dtshd",
|
|
31105
|
+
"dvb",
|
|
31106
|
+
"dwg",
|
|
31107
|
+
"dxf",
|
|
31108
|
+
"ecelp4800",
|
|
31109
|
+
"ecelp7470",
|
|
31110
|
+
"ecelp9600",
|
|
31111
|
+
"egg",
|
|
31112
|
+
"eol",
|
|
31113
|
+
"eot",
|
|
31114
|
+
"epub",
|
|
31115
|
+
"exe",
|
|
31116
|
+
"f4v",
|
|
31117
|
+
"fbs",
|
|
31118
|
+
"fh",
|
|
31119
|
+
"fla",
|
|
31120
|
+
"flac",
|
|
31121
|
+
"flatpak",
|
|
31122
|
+
"fli",
|
|
31123
|
+
"flv",
|
|
31124
|
+
"fpx",
|
|
31125
|
+
"fst",
|
|
31126
|
+
"fvt",
|
|
31127
|
+
"g3",
|
|
31128
|
+
"gh",
|
|
31129
|
+
"gif",
|
|
31130
|
+
"graffle",
|
|
31131
|
+
"gz",
|
|
31132
|
+
"gzip",
|
|
31133
|
+
"h261",
|
|
31134
|
+
"h263",
|
|
31135
|
+
"h264",
|
|
31136
|
+
"icns",
|
|
31137
|
+
"ico",
|
|
31138
|
+
"ief",
|
|
31139
|
+
"img",
|
|
31140
|
+
"ipa",
|
|
31141
|
+
"iso",
|
|
31142
|
+
"jar",
|
|
31143
|
+
"jpeg",
|
|
31144
|
+
"jpg",
|
|
31145
|
+
"jpgv",
|
|
31146
|
+
"jpm",
|
|
31147
|
+
"jxr",
|
|
31148
|
+
"key",
|
|
31149
|
+
"ktx",
|
|
31150
|
+
"lha",
|
|
31151
|
+
"lib",
|
|
31152
|
+
"lvp",
|
|
31153
|
+
"lz",
|
|
31154
|
+
"lzh",
|
|
31155
|
+
"lzma",
|
|
31156
|
+
"lzo",
|
|
31157
|
+
"m3u",
|
|
31158
|
+
"m4a",
|
|
31159
|
+
"m4v",
|
|
31160
|
+
"mar",
|
|
31161
|
+
"mdi",
|
|
31162
|
+
"mht",
|
|
31163
|
+
"mid",
|
|
31164
|
+
"midi",
|
|
31165
|
+
"mj2",
|
|
31166
|
+
"mka",
|
|
31167
|
+
"mkv",
|
|
31168
|
+
"mmr",
|
|
31169
|
+
"mng",
|
|
31170
|
+
"mobi",
|
|
31171
|
+
"mov",
|
|
31172
|
+
"movie",
|
|
31173
|
+
"mp3",
|
|
31174
|
+
"mp4",
|
|
31175
|
+
"mp4a",
|
|
31176
|
+
"mpeg",
|
|
31177
|
+
"mpg",
|
|
31178
|
+
"mpga",
|
|
31179
|
+
"mxu",
|
|
31180
|
+
"nef",
|
|
31181
|
+
"npx",
|
|
31182
|
+
"numbers",
|
|
31183
|
+
"nupkg",
|
|
31184
|
+
"o",
|
|
31185
|
+
"odp",
|
|
31186
|
+
"ods",
|
|
31187
|
+
"odt",
|
|
31188
|
+
"oga",
|
|
31189
|
+
"ogg",
|
|
31190
|
+
"ogv",
|
|
31191
|
+
"otf",
|
|
31192
|
+
"ott",
|
|
31193
|
+
"pages",
|
|
31194
|
+
"pbm",
|
|
31195
|
+
"pcx",
|
|
31196
|
+
"pdb",
|
|
31197
|
+
"pdf",
|
|
31198
|
+
"pea",
|
|
31199
|
+
"pgm",
|
|
31200
|
+
"pic",
|
|
31201
|
+
"png",
|
|
31202
|
+
"pnm",
|
|
31203
|
+
"pot",
|
|
31204
|
+
"potm",
|
|
31205
|
+
"potx",
|
|
31206
|
+
"ppa",
|
|
31207
|
+
"ppam",
|
|
31208
|
+
"ppm",
|
|
31209
|
+
"pps",
|
|
31210
|
+
"ppsm",
|
|
31211
|
+
"ppsx",
|
|
31212
|
+
"ppt",
|
|
31213
|
+
"pptm",
|
|
31214
|
+
"pptx",
|
|
31215
|
+
"psd",
|
|
31216
|
+
"pya",
|
|
31217
|
+
"pyc",
|
|
31218
|
+
"pyo",
|
|
31219
|
+
"pyv",
|
|
31220
|
+
"qt",
|
|
31221
|
+
"rar",
|
|
31222
|
+
"ras",
|
|
31223
|
+
"raw",
|
|
31224
|
+
"resources",
|
|
31225
|
+
"rgb",
|
|
31226
|
+
"rip",
|
|
31227
|
+
"rlc",
|
|
31228
|
+
"rmf",
|
|
31229
|
+
"rmvb",
|
|
31230
|
+
"rpm",
|
|
31231
|
+
"rtf",
|
|
31232
|
+
"rz",
|
|
31233
|
+
"s3m",
|
|
31234
|
+
"s7z",
|
|
31235
|
+
"scpt",
|
|
31236
|
+
"sgi",
|
|
31237
|
+
"shar",
|
|
31238
|
+
"snap",
|
|
31239
|
+
"sil",
|
|
31240
|
+
"sketch",
|
|
31241
|
+
"slk",
|
|
31242
|
+
"smv",
|
|
31243
|
+
"snk",
|
|
31244
|
+
"so",
|
|
31245
|
+
"stl",
|
|
31246
|
+
"suo",
|
|
31247
|
+
"sub",
|
|
31248
|
+
"swf",
|
|
31249
|
+
"tar",
|
|
31250
|
+
"tbz",
|
|
31251
|
+
"tbz2",
|
|
31252
|
+
"tga",
|
|
31253
|
+
"tgz",
|
|
31254
|
+
"thmx",
|
|
31255
|
+
"tif",
|
|
31256
|
+
"tiff",
|
|
31257
|
+
"tlz",
|
|
31258
|
+
"ttc",
|
|
31259
|
+
"ttf",
|
|
31260
|
+
"txz",
|
|
31261
|
+
"udf",
|
|
31262
|
+
"uvh",
|
|
31263
|
+
"uvi",
|
|
31264
|
+
"uvm",
|
|
31265
|
+
"uvp",
|
|
31266
|
+
"uvs",
|
|
31267
|
+
"uvu",
|
|
31268
|
+
"viv",
|
|
31269
|
+
"vob",
|
|
31270
|
+
"war",
|
|
31271
|
+
"wav",
|
|
31272
|
+
"wax",
|
|
31273
|
+
"wbmp",
|
|
31274
|
+
"wdp",
|
|
31275
|
+
"weba",
|
|
31276
|
+
"webm",
|
|
31277
|
+
"webp",
|
|
31278
|
+
"whl",
|
|
31279
|
+
"wim",
|
|
31280
|
+
"wm",
|
|
31281
|
+
"wma",
|
|
31282
|
+
"wmv",
|
|
31283
|
+
"wmx",
|
|
31284
|
+
"woff",
|
|
31285
|
+
"woff2",
|
|
31286
|
+
"wrm",
|
|
31287
|
+
"wvx",
|
|
31288
|
+
"xbm",
|
|
31289
|
+
"xif",
|
|
31290
|
+
"xla",
|
|
31291
|
+
"xlam",
|
|
31292
|
+
"xls",
|
|
31293
|
+
"xlsb",
|
|
31294
|
+
"xlsm",
|
|
31295
|
+
"xlsx",
|
|
31296
|
+
"xlt",
|
|
31297
|
+
"xltm",
|
|
31298
|
+
"xltx",
|
|
31299
|
+
"xm",
|
|
31300
|
+
"xmind",
|
|
31301
|
+
"xpi",
|
|
31302
|
+
"xpm",
|
|
31303
|
+
"xwd",
|
|
31304
|
+
"xz",
|
|
31305
|
+
"z",
|
|
31306
|
+
"zip",
|
|
31307
|
+
"zipx"
|
|
31308
|
+
]);
|
|
31309
|
+
var isBinaryPath = (filePath) => binaryExtensions.has(sp.extname(filePath).slice(1).toLowerCase());
|
|
31310
|
+
var foreach = (val, fn) => {
|
|
31311
|
+
if (val instanceof Set) {
|
|
31312
|
+
val.forEach(fn);
|
|
31313
|
+
} else {
|
|
31314
|
+
fn(val);
|
|
31315
|
+
}
|
|
31316
|
+
};
|
|
31317
|
+
var addAndConvert = (main2, prop, item) => {
|
|
31318
|
+
let container = main2[prop];
|
|
31319
|
+
if (!(container instanceof Set)) {
|
|
31320
|
+
main2[prop] = container = new Set([container]);
|
|
31321
|
+
}
|
|
31322
|
+
container.add(item);
|
|
31323
|
+
};
|
|
31324
|
+
var clearItem = (cont) => (key) => {
|
|
31325
|
+
const set = cont[key];
|
|
31326
|
+
if (set instanceof Set) {
|
|
31327
|
+
set.clear();
|
|
31328
|
+
} else {
|
|
31329
|
+
delete cont[key];
|
|
31330
|
+
}
|
|
31331
|
+
};
|
|
31332
|
+
var delFromSet = (main2, prop, item) => {
|
|
31333
|
+
const container = main2[prop];
|
|
31334
|
+
if (container instanceof Set) {
|
|
31335
|
+
container.delete(item);
|
|
31336
|
+
} else if (container === item) {
|
|
31337
|
+
delete main2[prop];
|
|
31338
|
+
}
|
|
31339
|
+
};
|
|
31340
|
+
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
31341
|
+
var FsWatchInstances = new Map;
|
|
31342
|
+
function createFsWatchInstance(path2, options, listener, errHandler, emitRaw) {
|
|
31343
|
+
const handleEvent = (rawEvent, evPath) => {
|
|
31344
|
+
listener(path2);
|
|
31345
|
+
emitRaw(rawEvent, evPath, { watchedPath: path2 });
|
|
31346
|
+
if (evPath && path2 !== evPath) {
|
|
31347
|
+
fsWatchBroadcast(sp.resolve(path2, evPath), KEY_LISTENERS, sp.join(path2, evPath));
|
|
31348
|
+
}
|
|
31349
|
+
};
|
|
31350
|
+
try {
|
|
31351
|
+
return fs_watch(path2, {
|
|
31352
|
+
persistent: options.persistent
|
|
31353
|
+
}, handleEvent);
|
|
31354
|
+
} catch (error) {
|
|
31355
|
+
errHandler(error);
|
|
31356
|
+
return;
|
|
31357
|
+
}
|
|
31358
|
+
}
|
|
31359
|
+
var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
31360
|
+
const cont = FsWatchInstances.get(fullPath);
|
|
31361
|
+
if (!cont)
|
|
31362
|
+
return;
|
|
31363
|
+
foreach(cont[listenerType], (listener) => {
|
|
31364
|
+
listener(val1, val2, val3);
|
|
31365
|
+
});
|
|
31366
|
+
};
|
|
31367
|
+
var setFsWatchListener = (path2, fullPath, options, handlers) => {
|
|
31368
|
+
const { listener, errHandler, rawEmitter } = handlers;
|
|
31369
|
+
let cont = FsWatchInstances.get(fullPath);
|
|
31370
|
+
let watcher;
|
|
31371
|
+
if (!options.persistent) {
|
|
31372
|
+
watcher = createFsWatchInstance(path2, options, listener, errHandler, rawEmitter);
|
|
31373
|
+
if (!watcher)
|
|
31374
|
+
return;
|
|
31375
|
+
return watcher.close.bind(watcher);
|
|
31376
|
+
}
|
|
31377
|
+
if (cont) {
|
|
31378
|
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
|
31379
|
+
addAndConvert(cont, KEY_ERR, errHandler);
|
|
31380
|
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
31381
|
+
} else {
|
|
31382
|
+
watcher = createFsWatchInstance(path2, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
|
|
31383
|
+
if (!watcher)
|
|
31384
|
+
return;
|
|
31385
|
+
watcher.on(EV.ERROR, async (error) => {
|
|
31386
|
+
const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
|
|
31387
|
+
if (cont)
|
|
31388
|
+
cont.watcherUnusable = true;
|
|
31389
|
+
if (isWindows && error.code === "EPERM") {
|
|
31390
|
+
try {
|
|
31391
|
+
const fd = await open(path2, "r");
|
|
31392
|
+
await fd.close();
|
|
31393
|
+
broadcastErr(error);
|
|
31394
|
+
} catch (err) {}
|
|
31395
|
+
} else {
|
|
31396
|
+
broadcastErr(error);
|
|
31397
|
+
}
|
|
31398
|
+
});
|
|
31399
|
+
cont = {
|
|
31400
|
+
listeners: listener,
|
|
31401
|
+
errHandlers: errHandler,
|
|
31402
|
+
rawEmitters: rawEmitter,
|
|
31403
|
+
watcher
|
|
31404
|
+
};
|
|
31405
|
+
FsWatchInstances.set(fullPath, cont);
|
|
31406
|
+
}
|
|
31407
|
+
return () => {
|
|
31408
|
+
delFromSet(cont, KEY_LISTENERS, listener);
|
|
31409
|
+
delFromSet(cont, KEY_ERR, errHandler);
|
|
31410
|
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
31411
|
+
if (isEmptySet(cont.listeners)) {
|
|
31412
|
+
cont.watcher.close();
|
|
31413
|
+
FsWatchInstances.delete(fullPath);
|
|
31414
|
+
HANDLER_KEYS.forEach(clearItem(cont));
|
|
31415
|
+
cont.watcher = undefined;
|
|
31416
|
+
Object.freeze(cont);
|
|
31417
|
+
}
|
|
31418
|
+
};
|
|
31419
|
+
};
|
|
31420
|
+
var FsWatchFileInstances = new Map;
|
|
31421
|
+
var setFsWatchFileListener = (path2, fullPath, options, handlers) => {
|
|
31422
|
+
const { listener, rawEmitter } = handlers;
|
|
31423
|
+
let cont = FsWatchFileInstances.get(fullPath);
|
|
31424
|
+
const copts = cont && cont.options;
|
|
31425
|
+
if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
|
|
31426
|
+
unwatchFile(fullPath);
|
|
31427
|
+
cont = undefined;
|
|
31428
|
+
}
|
|
31429
|
+
if (cont) {
|
|
31430
|
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
|
31431
|
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
31432
|
+
} else {
|
|
31433
|
+
cont = {
|
|
31434
|
+
listeners: listener,
|
|
31435
|
+
rawEmitters: rawEmitter,
|
|
31436
|
+
options,
|
|
31437
|
+
watcher: watchFile(fullPath, options, (curr, prev) => {
|
|
31438
|
+
foreach(cont.rawEmitters, (rawEmitter2) => {
|
|
31439
|
+
rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
|
|
31440
|
+
});
|
|
31441
|
+
const currmtime = curr.mtimeMs;
|
|
31442
|
+
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
31443
|
+
foreach(cont.listeners, (listener2) => listener2(path2, curr));
|
|
31444
|
+
}
|
|
31445
|
+
})
|
|
31446
|
+
};
|
|
31447
|
+
FsWatchFileInstances.set(fullPath, cont);
|
|
31448
|
+
}
|
|
31449
|
+
return () => {
|
|
31450
|
+
delFromSet(cont, KEY_LISTENERS, listener);
|
|
31451
|
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
31452
|
+
if (isEmptySet(cont.listeners)) {
|
|
31453
|
+
FsWatchFileInstances.delete(fullPath);
|
|
31454
|
+
unwatchFile(fullPath);
|
|
31455
|
+
cont.options = cont.watcher = undefined;
|
|
31456
|
+
Object.freeze(cont);
|
|
31457
|
+
}
|
|
31458
|
+
};
|
|
31459
|
+
};
|
|
31460
|
+
|
|
31461
|
+
class NodeFsHandler {
|
|
31462
|
+
fsw;
|
|
31463
|
+
_boundHandleError;
|
|
31464
|
+
constructor(fsW) {
|
|
31465
|
+
this.fsw = fsW;
|
|
31466
|
+
this._boundHandleError = (error) => fsW._handleError(error);
|
|
31467
|
+
}
|
|
31468
|
+
_watchWithNodeFs(path2, listener) {
|
|
31469
|
+
const opts = this.fsw.options;
|
|
31470
|
+
const directory = sp.dirname(path2);
|
|
31471
|
+
const basename2 = sp.basename(path2);
|
|
31472
|
+
const parent = this.fsw._getWatchedDir(directory);
|
|
31473
|
+
parent.add(basename2);
|
|
31474
|
+
const absolutePath = sp.resolve(path2);
|
|
31475
|
+
const options = {
|
|
31476
|
+
persistent: opts.persistent
|
|
31477
|
+
};
|
|
31478
|
+
if (!listener)
|
|
31479
|
+
listener = EMPTY_FN;
|
|
31480
|
+
let closer;
|
|
31481
|
+
if (opts.usePolling) {
|
|
31482
|
+
const enableBin = opts.interval !== opts.binaryInterval;
|
|
31483
|
+
options.interval = enableBin && isBinaryPath(basename2) ? opts.binaryInterval : opts.interval;
|
|
31484
|
+
closer = setFsWatchFileListener(path2, absolutePath, options, {
|
|
31485
|
+
listener,
|
|
31486
|
+
rawEmitter: this.fsw._emitRaw
|
|
31487
|
+
});
|
|
31488
|
+
} else {
|
|
31489
|
+
closer = setFsWatchListener(path2, absolutePath, options, {
|
|
31490
|
+
listener,
|
|
31491
|
+
errHandler: this._boundHandleError,
|
|
31492
|
+
rawEmitter: this.fsw._emitRaw
|
|
31493
|
+
});
|
|
31494
|
+
}
|
|
31495
|
+
return closer;
|
|
31496
|
+
}
|
|
31497
|
+
_handleFile(file, stats, initialAdd) {
|
|
31498
|
+
if (this.fsw.closed) {
|
|
31499
|
+
return;
|
|
31500
|
+
}
|
|
31501
|
+
const dirname3 = sp.dirname(file);
|
|
31502
|
+
const basename2 = sp.basename(file);
|
|
31503
|
+
const parent = this.fsw._getWatchedDir(dirname3);
|
|
31504
|
+
let prevStats = stats;
|
|
31505
|
+
if (parent.has(basename2))
|
|
31506
|
+
return;
|
|
31507
|
+
const listener = async (path2, newStats) => {
|
|
31508
|
+
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
31509
|
+
return;
|
|
31510
|
+
if (!newStats || newStats.mtimeMs === 0) {
|
|
31511
|
+
try {
|
|
31512
|
+
const newStats2 = await stat3(file);
|
|
31513
|
+
if (this.fsw.closed)
|
|
31514
|
+
return;
|
|
31515
|
+
const at = newStats2.atimeMs;
|
|
31516
|
+
const mt = newStats2.mtimeMs;
|
|
31517
|
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
31518
|
+
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
31519
|
+
}
|
|
31520
|
+
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
31521
|
+
this.fsw._closeFile(path2);
|
|
31522
|
+
prevStats = newStats2;
|
|
31523
|
+
const closer2 = this._watchWithNodeFs(file, listener);
|
|
31524
|
+
if (closer2)
|
|
31525
|
+
this.fsw._addPathCloser(path2, closer2);
|
|
31526
|
+
} else {
|
|
31527
|
+
prevStats = newStats2;
|
|
31528
|
+
}
|
|
31529
|
+
} catch (error) {
|
|
31530
|
+
this.fsw._remove(dirname3, basename2);
|
|
31531
|
+
}
|
|
31532
|
+
} else if (parent.has(basename2)) {
|
|
31533
|
+
const at = newStats.atimeMs;
|
|
31534
|
+
const mt = newStats.mtimeMs;
|
|
31535
|
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
31536
|
+
this.fsw._emit(EV.CHANGE, file, newStats);
|
|
31537
|
+
}
|
|
31538
|
+
prevStats = newStats;
|
|
31539
|
+
}
|
|
31540
|
+
};
|
|
31541
|
+
const closer = this._watchWithNodeFs(file, listener);
|
|
31542
|
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
|
|
31543
|
+
if (!this.fsw._throttle(EV.ADD, file, 0))
|
|
31544
|
+
return;
|
|
31545
|
+
this.fsw._emit(EV.ADD, file, stats);
|
|
31546
|
+
}
|
|
31547
|
+
return closer;
|
|
31548
|
+
}
|
|
31549
|
+
async _handleSymlink(entry, directory, path2, item) {
|
|
31550
|
+
if (this.fsw.closed) {
|
|
31551
|
+
return;
|
|
31552
|
+
}
|
|
31553
|
+
const full = entry.fullPath;
|
|
31554
|
+
const dir = this.fsw._getWatchedDir(directory);
|
|
31555
|
+
if (!this.fsw.options.followSymlinks) {
|
|
31556
|
+
this.fsw._incrReadyCount();
|
|
31557
|
+
let linkPath;
|
|
31558
|
+
try {
|
|
31559
|
+
linkPath = await fsrealpath(path2);
|
|
31560
|
+
} catch (e) {
|
|
31561
|
+
this.fsw._emitReady();
|
|
31562
|
+
return true;
|
|
31563
|
+
}
|
|
31564
|
+
if (this.fsw.closed)
|
|
31565
|
+
return;
|
|
31566
|
+
if (dir.has(item)) {
|
|
31567
|
+
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
31568
|
+
this.fsw._symlinkPaths.set(full, linkPath);
|
|
31569
|
+
this.fsw._emit(EV.CHANGE, path2, entry.stats);
|
|
31570
|
+
}
|
|
31571
|
+
} else {
|
|
31572
|
+
dir.add(item);
|
|
31573
|
+
this.fsw._symlinkPaths.set(full, linkPath);
|
|
31574
|
+
this.fsw._emit(EV.ADD, path2, entry.stats);
|
|
31575
|
+
}
|
|
31576
|
+
this.fsw._emitReady();
|
|
31577
|
+
return true;
|
|
31578
|
+
}
|
|
31579
|
+
if (this.fsw._symlinkPaths.has(full)) {
|
|
31580
|
+
return true;
|
|
31581
|
+
}
|
|
31582
|
+
this.fsw._symlinkPaths.set(full, true);
|
|
31583
|
+
}
|
|
31584
|
+
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
|
|
31585
|
+
directory = sp.join(directory, "");
|
|
31586
|
+
const throttleKey = target ? `${directory}:${target}` : directory;
|
|
31587
|
+
throttler = this.fsw._throttle("readdir", throttleKey, 1000);
|
|
31588
|
+
if (!throttler)
|
|
31589
|
+
return;
|
|
31590
|
+
const previous = this.fsw._getWatchedDir(wh.path);
|
|
31591
|
+
const current = new Set;
|
|
31592
|
+
let stream = this.fsw._readdirp(directory, {
|
|
31593
|
+
fileFilter: (entry) => wh.filterPath(entry),
|
|
31594
|
+
directoryFilter: (entry) => wh.filterDir(entry)
|
|
31595
|
+
});
|
|
31596
|
+
if (!stream)
|
|
31597
|
+
return;
|
|
31598
|
+
stream.on(STR_DATA, async (entry) => {
|
|
31599
|
+
if (this.fsw.closed) {
|
|
31600
|
+
stream = undefined;
|
|
31601
|
+
return;
|
|
31602
|
+
}
|
|
31603
|
+
const item = entry.path;
|
|
31604
|
+
let path2 = sp.join(directory, item);
|
|
31605
|
+
current.add(item);
|
|
31606
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path2, item)) {
|
|
31607
|
+
return;
|
|
31608
|
+
}
|
|
31609
|
+
if (this.fsw.closed) {
|
|
31610
|
+
stream = undefined;
|
|
31611
|
+
return;
|
|
31612
|
+
}
|
|
31613
|
+
if (item === target || !target && !previous.has(item)) {
|
|
31614
|
+
this.fsw._incrReadyCount();
|
|
31615
|
+
path2 = sp.join(dir, sp.relative(dir, path2));
|
|
31616
|
+
this._addToNodeFs(path2, initialAdd, wh, depth + 1);
|
|
31617
|
+
}
|
|
31618
|
+
}).on(EV.ERROR, this._boundHandleError);
|
|
31619
|
+
return new Promise((resolve2, reject) => {
|
|
31620
|
+
if (!stream)
|
|
31621
|
+
return reject();
|
|
31622
|
+
stream.once(STR_END, () => {
|
|
31623
|
+
if (this.fsw.closed) {
|
|
31624
|
+
stream = undefined;
|
|
31625
|
+
return;
|
|
31626
|
+
}
|
|
31627
|
+
const wasThrottled = throttler ? throttler.clear() : false;
|
|
31628
|
+
resolve2(undefined);
|
|
31629
|
+
previous.getChildren().filter((item) => {
|
|
31630
|
+
return item !== directory && !current.has(item);
|
|
31631
|
+
}).forEach((item) => {
|
|
31632
|
+
this.fsw._remove(directory, item);
|
|
31633
|
+
});
|
|
31634
|
+
stream = undefined;
|
|
31635
|
+
if (wasThrottled)
|
|
31636
|
+
this._handleRead(directory, false, wh, target, dir, depth, throttler);
|
|
31637
|
+
});
|
|
31638
|
+
});
|
|
31639
|
+
}
|
|
31640
|
+
async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath2) {
|
|
31641
|
+
const parentDir = this.fsw._getWatchedDir(sp.dirname(dir));
|
|
31642
|
+
const tracked = parentDir.has(sp.basename(dir));
|
|
31643
|
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
|
|
31644
|
+
this.fsw._emit(EV.ADD_DIR, dir, stats);
|
|
31645
|
+
}
|
|
31646
|
+
parentDir.add(sp.basename(dir));
|
|
31647
|
+
this.fsw._getWatchedDir(dir);
|
|
31648
|
+
let throttler;
|
|
31649
|
+
let closer;
|
|
31650
|
+
const oDepth = this.fsw.options.depth;
|
|
31651
|
+
if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath2)) {
|
|
31652
|
+
if (!target) {
|
|
31653
|
+
await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
|
|
31654
|
+
if (this.fsw.closed)
|
|
31655
|
+
return;
|
|
31656
|
+
}
|
|
31657
|
+
closer = this._watchWithNodeFs(dir, (dirPath, stats2) => {
|
|
31658
|
+
if (stats2 && stats2.mtimeMs === 0)
|
|
31659
|
+
return;
|
|
31660
|
+
this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
|
|
31661
|
+
});
|
|
31662
|
+
}
|
|
31663
|
+
return closer;
|
|
31664
|
+
}
|
|
31665
|
+
async _addToNodeFs(path2, initialAdd, priorWh, depth, target) {
|
|
31666
|
+
const ready = this.fsw._emitReady;
|
|
31667
|
+
if (this.fsw._isIgnored(path2) || this.fsw.closed) {
|
|
31668
|
+
ready();
|
|
31669
|
+
return false;
|
|
31670
|
+
}
|
|
31671
|
+
const wh = this.fsw._getWatchHelpers(path2);
|
|
31672
|
+
if (priorWh) {
|
|
31673
|
+
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
31674
|
+
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
31675
|
+
}
|
|
31676
|
+
try {
|
|
31677
|
+
const stats = await statMethods[wh.statMethod](wh.watchPath);
|
|
31678
|
+
if (this.fsw.closed)
|
|
31679
|
+
return;
|
|
31680
|
+
if (this.fsw._isIgnored(wh.watchPath, stats)) {
|
|
31681
|
+
ready();
|
|
31682
|
+
return false;
|
|
31683
|
+
}
|
|
31684
|
+
const follow = this.fsw.options.followSymlinks;
|
|
31685
|
+
let closer;
|
|
31686
|
+
if (stats.isDirectory()) {
|
|
31687
|
+
const absPath = sp.resolve(path2);
|
|
31688
|
+
const targetPath = follow ? await fsrealpath(path2) : path2;
|
|
31689
|
+
if (this.fsw.closed)
|
|
31690
|
+
return;
|
|
31691
|
+
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
31692
|
+
if (this.fsw.closed)
|
|
31693
|
+
return;
|
|
31694
|
+
if (absPath !== targetPath && targetPath !== undefined) {
|
|
31695
|
+
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
31696
|
+
}
|
|
31697
|
+
} else if (stats.isSymbolicLink()) {
|
|
31698
|
+
const targetPath = follow ? await fsrealpath(path2) : path2;
|
|
31699
|
+
if (this.fsw.closed)
|
|
31700
|
+
return;
|
|
31701
|
+
const parent = sp.dirname(wh.watchPath);
|
|
31702
|
+
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
31703
|
+
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
31704
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path2, wh, targetPath);
|
|
31705
|
+
if (this.fsw.closed)
|
|
31706
|
+
return;
|
|
31707
|
+
if (targetPath !== undefined) {
|
|
31708
|
+
this.fsw._symlinkPaths.set(sp.resolve(path2), targetPath);
|
|
31709
|
+
}
|
|
31710
|
+
} else {
|
|
31711
|
+
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
31712
|
+
}
|
|
31713
|
+
ready();
|
|
31714
|
+
if (closer)
|
|
31715
|
+
this.fsw._addPathCloser(path2, closer);
|
|
31716
|
+
return false;
|
|
31717
|
+
} catch (error) {
|
|
31718
|
+
if (this.fsw._handleError(error)) {
|
|
31719
|
+
ready();
|
|
31720
|
+
return path2;
|
|
31721
|
+
}
|
|
31722
|
+
}
|
|
31723
|
+
}
|
|
31724
|
+
}
|
|
31725
|
+
|
|
31726
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
31727
|
+
/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
|
|
31728
|
+
var SLASH = "/";
|
|
31729
|
+
var SLASH_SLASH = "//";
|
|
31730
|
+
var ONE_DOT = ".";
|
|
31731
|
+
var TWO_DOTS = "..";
|
|
31732
|
+
var STRING_TYPE = "string";
|
|
31733
|
+
var BACK_SLASH_RE = /\\/g;
|
|
31734
|
+
var DOUBLE_SLASH_RE = /\/\//g;
|
|
31735
|
+
var DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
|
|
31736
|
+
var REPLACER_RE = /^\.[/\\]/;
|
|
31737
|
+
function arrify(item) {
|
|
31738
|
+
return Array.isArray(item) ? item : [item];
|
|
31739
|
+
}
|
|
31740
|
+
var isMatcherObject = (matcher) => typeof matcher === "object" && matcher !== null && !(matcher instanceof RegExp);
|
|
31741
|
+
function createPattern(matcher) {
|
|
31742
|
+
if (typeof matcher === "function")
|
|
31743
|
+
return matcher;
|
|
31744
|
+
if (typeof matcher === "string")
|
|
31745
|
+
return (string) => matcher === string;
|
|
31746
|
+
if (matcher instanceof RegExp)
|
|
31747
|
+
return (string) => matcher.test(string);
|
|
31748
|
+
if (typeof matcher === "object" && matcher !== null) {
|
|
31749
|
+
return (string) => {
|
|
31750
|
+
if (matcher.path === string)
|
|
31751
|
+
return true;
|
|
31752
|
+
if (matcher.recursive) {
|
|
31753
|
+
const relative5 = sp2.relative(matcher.path, string);
|
|
31754
|
+
if (!relative5) {
|
|
31755
|
+
return false;
|
|
31756
|
+
}
|
|
31757
|
+
return !relative5.startsWith("..") && !sp2.isAbsolute(relative5);
|
|
31758
|
+
}
|
|
31759
|
+
return false;
|
|
31760
|
+
};
|
|
31761
|
+
}
|
|
31762
|
+
return () => false;
|
|
31763
|
+
}
|
|
31764
|
+
function normalizePath(path2) {
|
|
31765
|
+
if (typeof path2 !== "string")
|
|
31766
|
+
throw new Error("string expected");
|
|
31767
|
+
path2 = sp2.normalize(path2);
|
|
31768
|
+
path2 = path2.replace(/\\/g, "/");
|
|
31769
|
+
let prepend = false;
|
|
31770
|
+
if (path2.startsWith("//"))
|
|
31771
|
+
prepend = true;
|
|
31772
|
+
path2 = path2.replace(DOUBLE_SLASH_RE, "/");
|
|
31773
|
+
if (prepend)
|
|
31774
|
+
path2 = "/" + path2;
|
|
31775
|
+
return path2;
|
|
31776
|
+
}
|
|
31777
|
+
function matchPatterns(patterns, testString, stats) {
|
|
31778
|
+
const path2 = normalizePath(testString);
|
|
31779
|
+
for (let index = 0;index < patterns.length; index++) {
|
|
31780
|
+
const pattern = patterns[index];
|
|
31781
|
+
if (pattern(path2, stats)) {
|
|
31782
|
+
return true;
|
|
31783
|
+
}
|
|
31784
|
+
}
|
|
31785
|
+
return false;
|
|
31786
|
+
}
|
|
31787
|
+
function anymatch(matchers, testString) {
|
|
31788
|
+
if (matchers == null) {
|
|
31789
|
+
throw new TypeError("anymatch: specify first argument");
|
|
31790
|
+
}
|
|
31791
|
+
const matchersArray = arrify(matchers);
|
|
31792
|
+
const patterns = matchersArray.map((matcher) => createPattern(matcher));
|
|
31793
|
+
if (testString == null) {
|
|
31794
|
+
return (testString2, stats) => {
|
|
31795
|
+
return matchPatterns(patterns, testString2, stats);
|
|
31796
|
+
};
|
|
31797
|
+
}
|
|
31798
|
+
return matchPatterns(patterns, testString);
|
|
31799
|
+
}
|
|
31800
|
+
var unifyPaths = (paths_) => {
|
|
31801
|
+
const paths = arrify(paths_).flat();
|
|
31802
|
+
if (!paths.every((p) => typeof p === STRING_TYPE)) {
|
|
31803
|
+
throw new TypeError(`Non-string provided as watch path: ${paths}`);
|
|
31804
|
+
}
|
|
31805
|
+
return paths.map(normalizePathToUnix);
|
|
31806
|
+
};
|
|
31807
|
+
var toUnix = (string) => {
|
|
31808
|
+
let str = string.replace(BACK_SLASH_RE, SLASH);
|
|
31809
|
+
let prepend = false;
|
|
31810
|
+
if (str.startsWith(SLASH_SLASH)) {
|
|
31811
|
+
prepend = true;
|
|
31812
|
+
}
|
|
31813
|
+
str = str.replace(DOUBLE_SLASH_RE, SLASH);
|
|
31814
|
+
if (prepend) {
|
|
31815
|
+
str = SLASH + str;
|
|
31816
|
+
}
|
|
31817
|
+
return str;
|
|
31818
|
+
};
|
|
31819
|
+
var normalizePathToUnix = (path2) => toUnix(sp2.normalize(toUnix(path2)));
|
|
31820
|
+
var normalizeIgnored = (cwd = "") => (path2) => {
|
|
31821
|
+
if (typeof path2 === "string") {
|
|
31822
|
+
return normalizePathToUnix(sp2.isAbsolute(path2) ? path2 : sp2.join(cwd, path2));
|
|
31823
|
+
} else {
|
|
31824
|
+
return path2;
|
|
31825
|
+
}
|
|
31826
|
+
};
|
|
31827
|
+
var getAbsolutePath = (path2, cwd) => {
|
|
31828
|
+
if (sp2.isAbsolute(path2)) {
|
|
31829
|
+
return path2;
|
|
31830
|
+
}
|
|
31831
|
+
return sp2.join(cwd, path2);
|
|
31832
|
+
};
|
|
31833
|
+
var EMPTY_SET = Object.freeze(new Set);
|
|
31834
|
+
|
|
31835
|
+
class DirEntry {
|
|
31836
|
+
path;
|
|
31837
|
+
_removeWatcher;
|
|
31838
|
+
items;
|
|
31839
|
+
constructor(dir, removeWatcher) {
|
|
31840
|
+
this.path = dir;
|
|
31841
|
+
this._removeWatcher = removeWatcher;
|
|
31842
|
+
this.items = new Set;
|
|
31843
|
+
}
|
|
31844
|
+
add(item) {
|
|
31845
|
+
const { items } = this;
|
|
31846
|
+
if (!items)
|
|
31847
|
+
return;
|
|
31848
|
+
if (item !== ONE_DOT && item !== TWO_DOTS)
|
|
31849
|
+
items.add(item);
|
|
31850
|
+
}
|
|
31851
|
+
async remove(item) {
|
|
31852
|
+
const { items } = this;
|
|
31853
|
+
if (!items)
|
|
31854
|
+
return;
|
|
31855
|
+
items.delete(item);
|
|
31856
|
+
if (items.size > 0)
|
|
31857
|
+
return;
|
|
31858
|
+
const dir = this.path;
|
|
31859
|
+
try {
|
|
31860
|
+
await readdir4(dir);
|
|
31861
|
+
} catch (err) {
|
|
31862
|
+
if (this._removeWatcher) {
|
|
31863
|
+
this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
|
|
31864
|
+
}
|
|
31865
|
+
}
|
|
31866
|
+
}
|
|
31867
|
+
has(item) {
|
|
31868
|
+
const { items } = this;
|
|
31869
|
+
if (!items)
|
|
31870
|
+
return;
|
|
31871
|
+
return items.has(item);
|
|
31872
|
+
}
|
|
31873
|
+
getChildren() {
|
|
31874
|
+
const { items } = this;
|
|
31875
|
+
if (!items)
|
|
31876
|
+
return [];
|
|
31877
|
+
return [...items.values()];
|
|
31878
|
+
}
|
|
31879
|
+
dispose() {
|
|
31880
|
+
this.items.clear();
|
|
31881
|
+
this.path = "";
|
|
31882
|
+
this._removeWatcher = EMPTY_FN;
|
|
31883
|
+
this.items = EMPTY_SET;
|
|
31884
|
+
Object.freeze(this);
|
|
31885
|
+
}
|
|
31886
|
+
}
|
|
31887
|
+
var STAT_METHOD_F = "stat";
|
|
31888
|
+
var STAT_METHOD_L = "lstat";
|
|
31889
|
+
|
|
31890
|
+
class WatchHelper {
|
|
31891
|
+
fsw;
|
|
31892
|
+
path;
|
|
31893
|
+
watchPath;
|
|
31894
|
+
fullWatchPath;
|
|
31895
|
+
dirParts;
|
|
31896
|
+
followSymlinks;
|
|
31897
|
+
statMethod;
|
|
31898
|
+
constructor(path2, follow, fsw) {
|
|
31899
|
+
this.fsw = fsw;
|
|
31900
|
+
const watchPath = path2;
|
|
31901
|
+
this.path = path2 = path2.replace(REPLACER_RE, "");
|
|
31902
|
+
this.watchPath = watchPath;
|
|
31903
|
+
this.fullWatchPath = sp2.resolve(watchPath);
|
|
31904
|
+
this.dirParts = [];
|
|
31905
|
+
this.dirParts.forEach((parts) => {
|
|
31906
|
+
if (parts.length > 1)
|
|
31907
|
+
parts.pop();
|
|
31908
|
+
});
|
|
31909
|
+
this.followSymlinks = follow;
|
|
31910
|
+
this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
|
|
31911
|
+
}
|
|
31912
|
+
entryPath(entry) {
|
|
31913
|
+
return sp2.join(this.watchPath, sp2.relative(this.watchPath, entry.fullPath));
|
|
31914
|
+
}
|
|
31915
|
+
filterPath(entry) {
|
|
31916
|
+
const { stats } = entry;
|
|
31917
|
+
if (stats && stats.isSymbolicLink())
|
|
31918
|
+
return this.filterDir(entry);
|
|
31919
|
+
const resolvedPath = this.entryPath(entry);
|
|
31920
|
+
return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
|
|
31921
|
+
}
|
|
31922
|
+
filterDir(entry) {
|
|
31923
|
+
return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
|
|
31924
|
+
}
|
|
31925
|
+
}
|
|
31926
|
+
|
|
31927
|
+
class FSWatcher extends EventEmitter {
|
|
31928
|
+
closed;
|
|
31929
|
+
options;
|
|
31930
|
+
_closers;
|
|
31931
|
+
_ignoredPaths;
|
|
31932
|
+
_throttled;
|
|
31933
|
+
_streams;
|
|
31934
|
+
_symlinkPaths;
|
|
31935
|
+
_watched;
|
|
31936
|
+
_pendingWrites;
|
|
31937
|
+
_pendingUnlinks;
|
|
31938
|
+
_readyCount;
|
|
31939
|
+
_emitReady;
|
|
31940
|
+
_closePromise;
|
|
31941
|
+
_userIgnored;
|
|
31942
|
+
_readyEmitted;
|
|
31943
|
+
_emitRaw;
|
|
31944
|
+
_boundRemove;
|
|
31945
|
+
_nodeFsHandler;
|
|
31946
|
+
constructor(_opts = {}) {
|
|
31947
|
+
super();
|
|
31948
|
+
this.closed = false;
|
|
31949
|
+
this._closers = new Map;
|
|
31950
|
+
this._ignoredPaths = new Set;
|
|
31951
|
+
this._throttled = new Map;
|
|
31952
|
+
this._streams = new Set;
|
|
31953
|
+
this._symlinkPaths = new Map;
|
|
31954
|
+
this._watched = new Map;
|
|
31955
|
+
this._pendingWrites = new Map;
|
|
31956
|
+
this._pendingUnlinks = new Map;
|
|
31957
|
+
this._readyCount = 0;
|
|
31958
|
+
this._readyEmitted = false;
|
|
31959
|
+
const awf = _opts.awaitWriteFinish;
|
|
31960
|
+
const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
|
|
31961
|
+
const opts = {
|
|
31962
|
+
persistent: true,
|
|
31963
|
+
ignoreInitial: false,
|
|
31964
|
+
ignorePermissionErrors: false,
|
|
31965
|
+
interval: 100,
|
|
31966
|
+
binaryInterval: 300,
|
|
31967
|
+
followSymlinks: true,
|
|
31968
|
+
usePolling: false,
|
|
31969
|
+
atomic: true,
|
|
31970
|
+
..._opts,
|
|
31971
|
+
ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
|
|
31972
|
+
awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === "object" ? { ...DEF_AWF, ...awf } : false
|
|
31973
|
+
};
|
|
31974
|
+
if (isIBMi)
|
|
31975
|
+
opts.usePolling = true;
|
|
31976
|
+
if (opts.atomic === undefined)
|
|
31977
|
+
opts.atomic = !opts.usePolling;
|
|
31978
|
+
const envPoll = process.env.CHOKIDAR_USEPOLLING;
|
|
31979
|
+
if (envPoll !== undefined) {
|
|
31980
|
+
const envLower = envPoll.toLowerCase();
|
|
31981
|
+
if (envLower === "false" || envLower === "0")
|
|
31982
|
+
opts.usePolling = false;
|
|
31983
|
+
else if (envLower === "true" || envLower === "1")
|
|
31984
|
+
opts.usePolling = true;
|
|
31985
|
+
else
|
|
31986
|
+
opts.usePolling = !!envLower;
|
|
31987
|
+
}
|
|
31988
|
+
const envInterval = process.env.CHOKIDAR_INTERVAL;
|
|
31989
|
+
if (envInterval)
|
|
31990
|
+
opts.interval = Number.parseInt(envInterval, 10);
|
|
31991
|
+
let readyCalls = 0;
|
|
31992
|
+
this._emitReady = () => {
|
|
31993
|
+
readyCalls++;
|
|
31994
|
+
if (readyCalls >= this._readyCount) {
|
|
31995
|
+
this._emitReady = EMPTY_FN;
|
|
31996
|
+
this._readyEmitted = true;
|
|
31997
|
+
process.nextTick(() => this.emit(EVENTS.READY));
|
|
31998
|
+
}
|
|
31999
|
+
};
|
|
32000
|
+
this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args);
|
|
32001
|
+
this._boundRemove = this._remove.bind(this);
|
|
32002
|
+
this.options = opts;
|
|
32003
|
+
this._nodeFsHandler = new NodeFsHandler(this);
|
|
32004
|
+
Object.freeze(opts);
|
|
32005
|
+
}
|
|
32006
|
+
_addIgnoredPath(matcher) {
|
|
32007
|
+
if (isMatcherObject(matcher)) {
|
|
32008
|
+
for (const ignored of this._ignoredPaths) {
|
|
32009
|
+
if (isMatcherObject(ignored) && ignored.path === matcher.path && ignored.recursive === matcher.recursive) {
|
|
32010
|
+
return;
|
|
32011
|
+
}
|
|
32012
|
+
}
|
|
32013
|
+
}
|
|
32014
|
+
this._ignoredPaths.add(matcher);
|
|
32015
|
+
}
|
|
32016
|
+
_removeIgnoredPath(matcher) {
|
|
32017
|
+
this._ignoredPaths.delete(matcher);
|
|
32018
|
+
if (typeof matcher === "string") {
|
|
32019
|
+
for (const ignored of this._ignoredPaths) {
|
|
32020
|
+
if (isMatcherObject(ignored) && ignored.path === matcher) {
|
|
32021
|
+
this._ignoredPaths.delete(ignored);
|
|
32022
|
+
}
|
|
32023
|
+
}
|
|
32024
|
+
}
|
|
32025
|
+
}
|
|
32026
|
+
add(paths_, _origAdd, _internal) {
|
|
32027
|
+
const { cwd } = this.options;
|
|
32028
|
+
this.closed = false;
|
|
32029
|
+
this._closePromise = undefined;
|
|
32030
|
+
let paths = unifyPaths(paths_);
|
|
32031
|
+
if (cwd) {
|
|
32032
|
+
paths = paths.map((path2) => {
|
|
32033
|
+
const absPath = getAbsolutePath(path2, cwd);
|
|
32034
|
+
return absPath;
|
|
32035
|
+
});
|
|
32036
|
+
}
|
|
32037
|
+
paths.forEach((path2) => {
|
|
32038
|
+
this._removeIgnoredPath(path2);
|
|
32039
|
+
});
|
|
32040
|
+
this._userIgnored = undefined;
|
|
32041
|
+
if (!this._readyCount)
|
|
32042
|
+
this._readyCount = 0;
|
|
32043
|
+
this._readyCount += paths.length;
|
|
32044
|
+
Promise.all(paths.map(async (path2) => {
|
|
32045
|
+
const res = await this._nodeFsHandler._addToNodeFs(path2, !_internal, undefined, 0, _origAdd);
|
|
32046
|
+
if (res)
|
|
32047
|
+
this._emitReady();
|
|
32048
|
+
return res;
|
|
32049
|
+
})).then((results) => {
|
|
32050
|
+
if (this.closed)
|
|
32051
|
+
return;
|
|
32052
|
+
results.forEach((item) => {
|
|
32053
|
+
if (item)
|
|
32054
|
+
this.add(sp2.dirname(item), sp2.basename(_origAdd || item));
|
|
32055
|
+
});
|
|
32056
|
+
});
|
|
32057
|
+
return this;
|
|
32058
|
+
}
|
|
32059
|
+
unwatch(paths_) {
|
|
32060
|
+
if (this.closed)
|
|
32061
|
+
return this;
|
|
32062
|
+
const paths = unifyPaths(paths_);
|
|
32063
|
+
const { cwd } = this.options;
|
|
32064
|
+
paths.forEach((path2) => {
|
|
32065
|
+
if (!sp2.isAbsolute(path2) && !this._closers.has(path2)) {
|
|
32066
|
+
if (cwd)
|
|
32067
|
+
path2 = sp2.join(cwd, path2);
|
|
32068
|
+
path2 = sp2.resolve(path2);
|
|
32069
|
+
}
|
|
32070
|
+
this._closePath(path2);
|
|
32071
|
+
this._addIgnoredPath(path2);
|
|
32072
|
+
if (this._watched.has(path2)) {
|
|
32073
|
+
this._addIgnoredPath({
|
|
32074
|
+
path: path2,
|
|
32075
|
+
recursive: true
|
|
32076
|
+
});
|
|
32077
|
+
}
|
|
32078
|
+
this._userIgnored = undefined;
|
|
32079
|
+
});
|
|
32080
|
+
return this;
|
|
32081
|
+
}
|
|
32082
|
+
close() {
|
|
32083
|
+
if (this._closePromise) {
|
|
32084
|
+
return this._closePromise;
|
|
32085
|
+
}
|
|
32086
|
+
this.closed = true;
|
|
32087
|
+
this.removeAllListeners();
|
|
32088
|
+
const closers = [];
|
|
32089
|
+
this._closers.forEach((closerList) => closerList.forEach((closer) => {
|
|
32090
|
+
const promise = closer();
|
|
32091
|
+
if (promise instanceof Promise)
|
|
32092
|
+
closers.push(promise);
|
|
32093
|
+
}));
|
|
32094
|
+
this._streams.forEach((stream) => stream.destroy());
|
|
32095
|
+
this._userIgnored = undefined;
|
|
32096
|
+
this._readyCount = 0;
|
|
32097
|
+
this._readyEmitted = false;
|
|
32098
|
+
this._watched.forEach((dirent) => dirent.dispose());
|
|
32099
|
+
this._closers.clear();
|
|
32100
|
+
this._watched.clear();
|
|
32101
|
+
this._streams.clear();
|
|
32102
|
+
this._symlinkPaths.clear();
|
|
32103
|
+
this._throttled.clear();
|
|
32104
|
+
this._closePromise = closers.length ? Promise.all(closers).then(() => {
|
|
32105
|
+
return;
|
|
32106
|
+
}) : Promise.resolve();
|
|
32107
|
+
return this._closePromise;
|
|
32108
|
+
}
|
|
32109
|
+
getWatched() {
|
|
32110
|
+
const watchList = {};
|
|
32111
|
+
this._watched.forEach((entry, dir) => {
|
|
32112
|
+
const key = this.options.cwd ? sp2.relative(this.options.cwd, dir) : dir;
|
|
32113
|
+
const index = key || ONE_DOT;
|
|
32114
|
+
watchList[index] = entry.getChildren().sort();
|
|
32115
|
+
});
|
|
32116
|
+
return watchList;
|
|
32117
|
+
}
|
|
32118
|
+
emitWithAll(event, args) {
|
|
32119
|
+
this.emit(event, ...args);
|
|
32120
|
+
if (event !== EVENTS.ERROR)
|
|
32121
|
+
this.emit(EVENTS.ALL, event, ...args);
|
|
32122
|
+
}
|
|
32123
|
+
async _emit(event, path2, stats) {
|
|
32124
|
+
if (this.closed)
|
|
32125
|
+
return;
|
|
32126
|
+
const opts = this.options;
|
|
32127
|
+
if (isWindows)
|
|
32128
|
+
path2 = sp2.normalize(path2);
|
|
32129
|
+
if (opts.cwd)
|
|
32130
|
+
path2 = sp2.relative(opts.cwd, path2);
|
|
32131
|
+
const args = [path2];
|
|
32132
|
+
if (stats != null)
|
|
32133
|
+
args.push(stats);
|
|
32134
|
+
const awf = opts.awaitWriteFinish;
|
|
32135
|
+
let pw;
|
|
32136
|
+
if (awf && (pw = this._pendingWrites.get(path2))) {
|
|
32137
|
+
pw.lastChange = new Date;
|
|
32138
|
+
return this;
|
|
32139
|
+
}
|
|
32140
|
+
if (opts.atomic) {
|
|
32141
|
+
if (event === EVENTS.UNLINK) {
|
|
32142
|
+
this._pendingUnlinks.set(path2, [event, ...args]);
|
|
32143
|
+
setTimeout(() => {
|
|
32144
|
+
this._pendingUnlinks.forEach((entry, path3) => {
|
|
32145
|
+
this.emit(...entry);
|
|
32146
|
+
this.emit(EVENTS.ALL, ...entry);
|
|
32147
|
+
this._pendingUnlinks.delete(path3);
|
|
32148
|
+
});
|
|
32149
|
+
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
32150
|
+
return this;
|
|
32151
|
+
}
|
|
32152
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path2)) {
|
|
32153
|
+
event = EVENTS.CHANGE;
|
|
32154
|
+
this._pendingUnlinks.delete(path2);
|
|
32155
|
+
}
|
|
32156
|
+
}
|
|
32157
|
+
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
32158
|
+
const awfEmit = (err, stats2) => {
|
|
32159
|
+
if (err) {
|
|
32160
|
+
event = EVENTS.ERROR;
|
|
32161
|
+
args[0] = err;
|
|
32162
|
+
this.emitWithAll(event, args);
|
|
32163
|
+
} else if (stats2) {
|
|
32164
|
+
if (args.length > 1) {
|
|
32165
|
+
args[1] = stats2;
|
|
32166
|
+
} else {
|
|
32167
|
+
args.push(stats2);
|
|
32168
|
+
}
|
|
32169
|
+
this.emitWithAll(event, args);
|
|
32170
|
+
}
|
|
32171
|
+
};
|
|
32172
|
+
this._awaitWriteFinish(path2, awf.stabilityThreshold, event, awfEmit);
|
|
32173
|
+
return this;
|
|
32174
|
+
}
|
|
32175
|
+
if (event === EVENTS.CHANGE) {
|
|
32176
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path2, 50);
|
|
32177
|
+
if (isThrottled)
|
|
32178
|
+
return this;
|
|
32179
|
+
}
|
|
32180
|
+
if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
32181
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path2) : path2;
|
|
32182
|
+
let stats2;
|
|
32183
|
+
try {
|
|
32184
|
+
stats2 = await stat4(fullPath);
|
|
32185
|
+
} catch (err) {}
|
|
32186
|
+
if (!stats2 || this.closed)
|
|
32187
|
+
return;
|
|
32188
|
+
args.push(stats2);
|
|
32189
|
+
}
|
|
32190
|
+
this.emitWithAll(event, args);
|
|
32191
|
+
return this;
|
|
32192
|
+
}
|
|
32193
|
+
_handleError(error) {
|
|
32194
|
+
const code = error && error.code;
|
|
32195
|
+
if (error && code !== "ENOENT" && code !== "ENOTDIR" && (!this.options.ignorePermissionErrors || code !== "EPERM" && code !== "EACCES")) {
|
|
32196
|
+
this.emit(EVENTS.ERROR, error);
|
|
32197
|
+
}
|
|
32198
|
+
return error || this.closed;
|
|
32199
|
+
}
|
|
32200
|
+
_throttle(actionType, path2, timeout) {
|
|
32201
|
+
if (!this._throttled.has(actionType)) {
|
|
32202
|
+
this._throttled.set(actionType, new Map);
|
|
32203
|
+
}
|
|
32204
|
+
const action = this._throttled.get(actionType);
|
|
32205
|
+
if (!action)
|
|
32206
|
+
throw new Error("invalid throttle");
|
|
32207
|
+
const actionPath = action.get(path2);
|
|
32208
|
+
if (actionPath) {
|
|
32209
|
+
actionPath.count++;
|
|
32210
|
+
return false;
|
|
32211
|
+
}
|
|
32212
|
+
let timeoutObject;
|
|
32213
|
+
const clear = () => {
|
|
32214
|
+
const item = action.get(path2);
|
|
32215
|
+
const count = item ? item.count : 0;
|
|
32216
|
+
action.delete(path2);
|
|
32217
|
+
clearTimeout(timeoutObject);
|
|
32218
|
+
if (item)
|
|
32219
|
+
clearTimeout(item.timeoutObject);
|
|
32220
|
+
return count;
|
|
32221
|
+
};
|
|
32222
|
+
timeoutObject = setTimeout(clear, timeout);
|
|
32223
|
+
const thr = { timeoutObject, clear, count: 0 };
|
|
32224
|
+
action.set(path2, thr);
|
|
32225
|
+
return thr;
|
|
32226
|
+
}
|
|
32227
|
+
_incrReadyCount() {
|
|
32228
|
+
return this._readyCount++;
|
|
32229
|
+
}
|
|
32230
|
+
_awaitWriteFinish(path2, threshold, event, awfEmit) {
|
|
32231
|
+
const awf = this.options.awaitWriteFinish;
|
|
32232
|
+
if (typeof awf !== "object")
|
|
32233
|
+
return;
|
|
32234
|
+
const pollInterval = awf.pollInterval;
|
|
32235
|
+
let timeoutHandler;
|
|
32236
|
+
let fullPath = path2;
|
|
32237
|
+
if (this.options.cwd && !sp2.isAbsolute(path2)) {
|
|
32238
|
+
fullPath = sp2.join(this.options.cwd, path2);
|
|
32239
|
+
}
|
|
32240
|
+
const now = new Date;
|
|
32241
|
+
const writes = this._pendingWrites;
|
|
32242
|
+
function awaitWriteFinishFn(prevStat) {
|
|
32243
|
+
statcb(fullPath, (err, curStat) => {
|
|
32244
|
+
if (err || !writes.has(path2)) {
|
|
32245
|
+
if (err && err.code !== "ENOENT")
|
|
32246
|
+
awfEmit(err);
|
|
32247
|
+
return;
|
|
32248
|
+
}
|
|
32249
|
+
const now2 = Number(new Date);
|
|
32250
|
+
if (prevStat && curStat.size !== prevStat.size) {
|
|
32251
|
+
writes.get(path2).lastChange = now2;
|
|
32252
|
+
}
|
|
32253
|
+
const pw = writes.get(path2);
|
|
32254
|
+
const df = now2 - pw.lastChange;
|
|
32255
|
+
if (df >= threshold) {
|
|
32256
|
+
writes.delete(path2);
|
|
32257
|
+
awfEmit(undefined, curStat);
|
|
32258
|
+
} else {
|
|
32259
|
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
32260
|
+
}
|
|
32261
|
+
});
|
|
32262
|
+
}
|
|
32263
|
+
if (!writes.has(path2)) {
|
|
32264
|
+
writes.set(path2, {
|
|
32265
|
+
lastChange: now,
|
|
32266
|
+
cancelWait: () => {
|
|
32267
|
+
writes.delete(path2);
|
|
32268
|
+
clearTimeout(timeoutHandler);
|
|
32269
|
+
return event;
|
|
32270
|
+
}
|
|
32271
|
+
});
|
|
32272
|
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
|
|
32273
|
+
}
|
|
32274
|
+
}
|
|
32275
|
+
_isIgnored(path2, stats) {
|
|
32276
|
+
if (this.options.atomic && DOT_RE.test(path2))
|
|
32277
|
+
return true;
|
|
32278
|
+
if (!this._userIgnored) {
|
|
32279
|
+
const { cwd } = this.options;
|
|
32280
|
+
const ign = this.options.ignored;
|
|
32281
|
+
const ignored = (ign || []).map(normalizeIgnored(cwd));
|
|
32282
|
+
const ignoredPaths = [...this._ignoredPaths];
|
|
32283
|
+
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
32284
|
+
this._userIgnored = anymatch(list, undefined);
|
|
32285
|
+
}
|
|
32286
|
+
return this._userIgnored(path2, stats);
|
|
32287
|
+
}
|
|
32288
|
+
_isntIgnored(path2, stat5) {
|
|
32289
|
+
return !this._isIgnored(path2, stat5);
|
|
32290
|
+
}
|
|
32291
|
+
_getWatchHelpers(path2) {
|
|
32292
|
+
return new WatchHelper(path2, this.options.followSymlinks, this);
|
|
32293
|
+
}
|
|
32294
|
+
_getWatchedDir(directory) {
|
|
32295
|
+
const dir = sp2.resolve(directory);
|
|
32296
|
+
if (!this._watched.has(dir))
|
|
32297
|
+
this._watched.set(dir, new DirEntry(dir, this._boundRemove));
|
|
32298
|
+
return this._watched.get(dir);
|
|
32299
|
+
}
|
|
32300
|
+
_hasReadPermissions(stats) {
|
|
32301
|
+
if (this.options.ignorePermissionErrors)
|
|
32302
|
+
return true;
|
|
32303
|
+
return Boolean(Number(stats.mode) & 256);
|
|
32304
|
+
}
|
|
32305
|
+
_remove(directory, item, isDirectory) {
|
|
32306
|
+
const path2 = sp2.join(directory, item);
|
|
32307
|
+
const fullPath = sp2.resolve(path2);
|
|
32308
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path2) || this._watched.has(fullPath);
|
|
32309
|
+
if (!this._throttle("remove", path2, 100))
|
|
32310
|
+
return;
|
|
32311
|
+
if (!isDirectory && this._watched.size === 1) {
|
|
32312
|
+
this.add(directory, item, true);
|
|
32313
|
+
}
|
|
32314
|
+
const wp = this._getWatchedDir(path2);
|
|
32315
|
+
const nestedDirectoryChildren = wp.getChildren();
|
|
32316
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path2, nested));
|
|
32317
|
+
const parent = this._getWatchedDir(directory);
|
|
32318
|
+
const wasTracked = parent.has(item);
|
|
32319
|
+
parent.remove(item);
|
|
32320
|
+
if (this._symlinkPaths.has(fullPath)) {
|
|
32321
|
+
this._symlinkPaths.delete(fullPath);
|
|
32322
|
+
}
|
|
32323
|
+
let relPath = path2;
|
|
32324
|
+
if (this.options.cwd)
|
|
32325
|
+
relPath = sp2.relative(this.options.cwd, path2);
|
|
32326
|
+
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
32327
|
+
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
32328
|
+
if (event === EVENTS.ADD)
|
|
32329
|
+
return;
|
|
32330
|
+
}
|
|
32331
|
+
this._watched.delete(path2);
|
|
32332
|
+
this._watched.delete(fullPath);
|
|
32333
|
+
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
32334
|
+
if (wasTracked && !this._isIgnored(path2))
|
|
32335
|
+
this._emit(eventName, path2);
|
|
32336
|
+
this._closePath(path2);
|
|
32337
|
+
}
|
|
32338
|
+
_closePath(path2) {
|
|
32339
|
+
this._closeFile(path2);
|
|
32340
|
+
const dir = sp2.dirname(path2);
|
|
32341
|
+
this._getWatchedDir(dir).remove(sp2.basename(path2));
|
|
32342
|
+
}
|
|
32343
|
+
_closeFile(path2) {
|
|
32344
|
+
const closers = this._closers.get(path2);
|
|
32345
|
+
if (!closers)
|
|
32346
|
+
return;
|
|
32347
|
+
closers.forEach((closer) => closer());
|
|
32348
|
+
this._closers.delete(path2);
|
|
32349
|
+
}
|
|
32350
|
+
_addPathCloser(path2, closer) {
|
|
32351
|
+
if (!closer)
|
|
32352
|
+
return;
|
|
32353
|
+
let list = this._closers.get(path2);
|
|
32354
|
+
if (!list) {
|
|
32355
|
+
list = [];
|
|
32356
|
+
this._closers.set(path2, list);
|
|
32357
|
+
}
|
|
32358
|
+
list.push(closer);
|
|
32359
|
+
}
|
|
32360
|
+
_readdirp(root, opts) {
|
|
32361
|
+
if (this.closed)
|
|
32362
|
+
return;
|
|
32363
|
+
const options = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
|
|
32364
|
+
let stream = readdirp(root, options);
|
|
32365
|
+
this._streams.add(stream);
|
|
32366
|
+
stream.once(STR_CLOSE, () => {
|
|
32367
|
+
stream = undefined;
|
|
32368
|
+
});
|
|
32369
|
+
stream.once(STR_END, () => {
|
|
32370
|
+
if (stream) {
|
|
32371
|
+
this._streams.delete(stream);
|
|
32372
|
+
stream = undefined;
|
|
32373
|
+
}
|
|
32374
|
+
});
|
|
32375
|
+
return stream;
|
|
32376
|
+
}
|
|
32377
|
+
}
|
|
32378
|
+
function watch(paths, options = {}) {
|
|
32379
|
+
const watcher = new FSWatcher(options);
|
|
32380
|
+
watcher.add(paths);
|
|
32381
|
+
return watcher;
|
|
32382
|
+
}
|
|
32383
|
+
|
|
32384
|
+
// src/daemon/watcher.ts
|
|
32385
|
+
init_src();
|
|
32386
|
+
function startWatcher(onSync) {
|
|
32387
|
+
const claudeDir = getClaudeDir();
|
|
32388
|
+
let debounceTimer = null;
|
|
32389
|
+
let syncing = false;
|
|
32390
|
+
const watcher = watch(claudeDir, {
|
|
32391
|
+
ignored: NEVER_SYNC_PATTERNS.map((p) => `**/${p}`),
|
|
32392
|
+
persistent: true,
|
|
32393
|
+
ignoreInitial: true,
|
|
32394
|
+
awaitWriteFinish: {
|
|
32395
|
+
stabilityThreshold: 2000,
|
|
32396
|
+
pollInterval: 500
|
|
32397
|
+
}
|
|
32398
|
+
});
|
|
32399
|
+
const triggerSync = () => {
|
|
32400
|
+
if (debounceTimer)
|
|
32401
|
+
clearTimeout(debounceTimer);
|
|
32402
|
+
debounceTimer = setTimeout(async () => {
|
|
32403
|
+
if (syncing)
|
|
32404
|
+
return;
|
|
32405
|
+
syncing = true;
|
|
32406
|
+
try {
|
|
32407
|
+
await onSync();
|
|
32408
|
+
} catch {} finally {
|
|
32409
|
+
syncing = false;
|
|
32410
|
+
}
|
|
32411
|
+
}, DAEMON_DEBOUNCE_MS);
|
|
32412
|
+
};
|
|
32413
|
+
watcher.on("change", triggerSync);
|
|
32414
|
+
watcher.on("add", triggerSync);
|
|
32415
|
+
watcher.on("unlink", triggerSync);
|
|
32416
|
+
return {
|
|
32417
|
+
stop: () => {
|
|
32418
|
+
if (debounceTimer)
|
|
32419
|
+
clearTimeout(debounceTimer);
|
|
32420
|
+
watcher.close();
|
|
32421
|
+
}
|
|
32422
|
+
};
|
|
32423
|
+
}
|
|
32424
|
+
|
|
32425
|
+
// src/daemon/runner.ts
|
|
32426
|
+
init_src();
|
|
32427
|
+
init_src();
|
|
32428
|
+
var HEARTBEAT_INTERVAL_MS = 3 * 60 * 1000;
|
|
32429
|
+
function getStatusPath(configDir) {
|
|
32430
|
+
return join15(configDir, "daemon.status.json");
|
|
32431
|
+
}
|
|
32432
|
+
function getLogPath(configDir) {
|
|
32433
|
+
return join15(configDir, "daemon.log");
|
|
32434
|
+
}
|
|
32435
|
+
function getPidPath(configDir) {
|
|
32436
|
+
return join15(configDir, "daemon.pid");
|
|
32437
|
+
}
|
|
32438
|
+
function log(configDir, message2) {
|
|
32439
|
+
const ts = new Date().toISOString();
|
|
32440
|
+
const line = `[${ts}] ${message2}
|
|
32441
|
+
`;
|
|
32442
|
+
try {
|
|
32443
|
+
appendFileSync(getLogPath(configDir), line);
|
|
32444
|
+
} catch {}
|
|
32445
|
+
}
|
|
32446
|
+
async function getMasterKey3(configDir) {
|
|
32447
|
+
const cachedKeyPath = join15(configDir, ".cached-key");
|
|
32448
|
+
const cached = await readFile10(cachedKeyPath);
|
|
32449
|
+
return new Uint8Array(cached);
|
|
32450
|
+
}
|
|
32451
|
+
async function getAuthenticatedClient3(configDir) {
|
|
32452
|
+
const config = await loadKeys(configDir);
|
|
32453
|
+
const privateKey = await importPrivateKey(config.devicePrivateKey);
|
|
32454
|
+
const jwt = await createDeviceJWT(privateKey, config.deviceId);
|
|
32455
|
+
return new CcsiniClient(config.apiUrl, jwt);
|
|
32456
|
+
}
|
|
32457
|
+
async function getSessionOptions(configDir) {
|
|
32458
|
+
const storedSession = await loadSessionConfig(configDir);
|
|
32459
|
+
return {
|
|
32460
|
+
enabled: storedSession.enabled,
|
|
32461
|
+
maxPerProject: storedSession.maxPerProject,
|
|
32462
|
+
maxFileSize: SESSION_SYNC_DEFAULTS.maxFileSize
|
|
32463
|
+
};
|
|
32464
|
+
}
|
|
32465
|
+
async function writeStatus(configDir, status) {
|
|
32466
|
+
await writeFile10(getStatusPath(configDir), JSON.stringify(status, null, 2));
|
|
32467
|
+
}
|
|
32468
|
+
async function runDaemon() {
|
|
32469
|
+
const configDir = getConfigDir();
|
|
32470
|
+
if (!await configExists(configDir)) {
|
|
32471
|
+
console.error("Not initialized. Run 'ccsini init' first.");
|
|
32472
|
+
process.exit(1);
|
|
32473
|
+
}
|
|
32474
|
+
try {
|
|
32475
|
+
await getMasterKey3(configDir);
|
|
32476
|
+
} catch {
|
|
32477
|
+
console.error("No cached key. Run 'ccsini unlock' first.");
|
|
32478
|
+
process.exit(1);
|
|
32479
|
+
}
|
|
32480
|
+
const pid = process.pid;
|
|
32481
|
+
await writeFile10(getPidPath(configDir), String(pid));
|
|
32482
|
+
const status = {
|
|
32483
|
+
pid,
|
|
32484
|
+
startedAt: Date.now(),
|
|
32485
|
+
lastPushAt: null,
|
|
32486
|
+
lastPullAt: null,
|
|
32487
|
+
lastError: null,
|
|
32488
|
+
pushCount: 0,
|
|
32489
|
+
pullCount: 0
|
|
32490
|
+
};
|
|
32491
|
+
await writeStatus(configDir, status);
|
|
32492
|
+
log(configDir, `Daemon started (PID ${pid})`);
|
|
32493
|
+
async function doPush() {
|
|
32494
|
+
try {
|
|
32495
|
+
const masterKey = await getMasterKey3(configDir);
|
|
32496
|
+
const client = await getAuthenticatedClient3(configDir);
|
|
32497
|
+
const config = await loadKeys(configDir);
|
|
32498
|
+
const sessionOptions = await getSessionOptions(configDir);
|
|
32499
|
+
const result = await pushSync(client, masterKey, config.deviceName, configDir, undefined, sessionOptions, { skipConflictBackup: true });
|
|
32500
|
+
status.lastPushAt = Date.now();
|
|
32501
|
+
status.pushCount++;
|
|
32502
|
+
status.lastError = null;
|
|
32503
|
+
await writeStatus(configDir, status);
|
|
32504
|
+
if (result.filesChanged > 0) {
|
|
32505
|
+
log(configDir, `Push: ${result.filesChanged} files (${result.durationMs}ms)`);
|
|
32506
|
+
}
|
|
32507
|
+
if (result.conflicts.length > 0) {
|
|
32508
|
+
log(configDir, `Push: ${result.conflicts.length} conflict(s)`);
|
|
32509
|
+
}
|
|
32510
|
+
} catch (e) {
|
|
32511
|
+
status.lastError = e.message;
|
|
32512
|
+
await writeStatus(configDir, status).catch(() => {});
|
|
32513
|
+
log(configDir, `Push error: ${e.message}`);
|
|
32514
|
+
}
|
|
32515
|
+
}
|
|
32516
|
+
async function doPull() {
|
|
32517
|
+
try {
|
|
32518
|
+
const masterKey = await getMasterKey3(configDir);
|
|
32519
|
+
const client = await getAuthenticatedClient3(configDir);
|
|
32520
|
+
const config = await loadKeys(configDir);
|
|
32521
|
+
const sessionOptions = await getSessionOptions(configDir);
|
|
32522
|
+
const result = await pullSync(client, masterKey, config.deviceName, configDir, undefined, sessionOptions);
|
|
32523
|
+
status.lastPullAt = Date.now();
|
|
32524
|
+
status.pullCount++;
|
|
32525
|
+
status.lastError = null;
|
|
32526
|
+
await writeStatus(configDir, status);
|
|
32527
|
+
if (result.filesChanged > 0) {
|
|
32528
|
+
log(configDir, `Pull: ${result.filesChanged} files (${result.durationMs}ms)`);
|
|
32529
|
+
}
|
|
32530
|
+
if (result.conflicts.length > 0) {
|
|
32531
|
+
log(configDir, `Pull: ${result.conflicts.length} conflict(s)`);
|
|
32532
|
+
}
|
|
32533
|
+
} catch (e) {
|
|
32534
|
+
status.lastError = e.message;
|
|
32535
|
+
await writeStatus(configDir, status).catch(() => {});
|
|
32536
|
+
log(configDir, `Pull error: ${e.message}`);
|
|
32537
|
+
}
|
|
32538
|
+
}
|
|
32539
|
+
async function doHeartbeat() {
|
|
32540
|
+
try {
|
|
32541
|
+
const client = await getAuthenticatedClient3(configDir);
|
|
32542
|
+
await client.heartbeat("daemon");
|
|
32543
|
+
} catch (e) {
|
|
32544
|
+
log(configDir, `Heartbeat error: ${e.message}`);
|
|
32545
|
+
}
|
|
32546
|
+
}
|
|
32547
|
+
const watcher = startWatcher(doPush);
|
|
32548
|
+
const pullInterval = setInterval(doPull, DAEMON_INTERVAL_MS);
|
|
32549
|
+
const heartbeatInterval = setInterval(doHeartbeat, HEARTBEAT_INTERVAL_MS);
|
|
32550
|
+
await doPull();
|
|
32551
|
+
await doHeartbeat();
|
|
32552
|
+
const shutdown = async () => {
|
|
32553
|
+
log(configDir, "Daemon shutting down...");
|
|
32554
|
+
watcher.stop();
|
|
32555
|
+
clearInterval(pullInterval);
|
|
32556
|
+
clearInterval(heartbeatInterval);
|
|
32557
|
+
const { rm: rm2 } = await import("fs/promises");
|
|
32558
|
+
await rm2(getPidPath(configDir)).catch(() => {});
|
|
32559
|
+
await rm2(getStatusPath(configDir)).catch(() => {});
|
|
32560
|
+
log(configDir, "Daemon stopped");
|
|
32561
|
+
process.exit(0);
|
|
32562
|
+
};
|
|
32563
|
+
process.on("SIGTERM", shutdown);
|
|
32564
|
+
process.on("SIGINT", shutdown);
|
|
32565
|
+
if (platform3() === "win32") {
|
|
32566
|
+
process.on("SIGBREAK", shutdown);
|
|
32567
|
+
}
|
|
32568
|
+
}
|
|
32569
|
+
|
|
32570
|
+
// src/commands/daemon.ts
|
|
32571
|
+
function isProcessRunning(pid) {
|
|
32572
|
+
try {
|
|
32573
|
+
process.kill(pid, 0);
|
|
32574
|
+
return true;
|
|
32575
|
+
} catch {
|
|
32576
|
+
return false;
|
|
32577
|
+
}
|
|
32578
|
+
}
|
|
32579
|
+
async function readPid(configDir) {
|
|
32580
|
+
try {
|
|
32581
|
+
const raw = await readFile11(getPidPath(configDir), "utf-8");
|
|
32582
|
+
const pid = parseInt(raw.trim(), 10);
|
|
32583
|
+
if (isNaN(pid))
|
|
32584
|
+
return null;
|
|
32585
|
+
return pid;
|
|
32586
|
+
} catch {
|
|
32587
|
+
return null;
|
|
32588
|
+
}
|
|
32589
|
+
}
|
|
32590
|
+
function registerDaemonCommands(program2) {
|
|
32591
|
+
const daemonCmd = program2.command("daemon").description("Background sync daemon");
|
|
32592
|
+
daemonCmd.command("_run", { hidden: true }).description("Run daemon in foreground (internal)").action(async () => {
|
|
32593
|
+
await runDaemon();
|
|
32594
|
+
});
|
|
32595
|
+
daemonCmd.command("start").description("Start background sync daemon").action(async () => {
|
|
32596
|
+
const configDir = getConfigDir();
|
|
32597
|
+
if (!await configExists(configDir)) {
|
|
32598
|
+
console.error("Not initialized. Run 'ccsini init' first.");
|
|
32599
|
+
process.exit(1);
|
|
32600
|
+
}
|
|
32601
|
+
const existingPid = await readPid(configDir);
|
|
32602
|
+
if (existingPid !== null && isProcessRunning(existingPid)) {
|
|
32603
|
+
console.log(`Daemon already running (PID ${existingPid})`);
|
|
32604
|
+
return;
|
|
32605
|
+
}
|
|
32606
|
+
if (existingPid !== null) {
|
|
32607
|
+
await rm2(getPidPath(configDir)).catch(() => {});
|
|
32608
|
+
await rm2(getStatusPath(configDir)).catch(() => {});
|
|
32609
|
+
}
|
|
32610
|
+
const isWin = platform4() === "win32";
|
|
32611
|
+
const child = spawn3("ccsini", ["daemon", "_run"], {
|
|
32612
|
+
detached: true,
|
|
32613
|
+
stdio: "ignore",
|
|
32614
|
+
...isWin ? { shell: true } : {}
|
|
32615
|
+
});
|
|
32616
|
+
child.unref();
|
|
32617
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
32618
|
+
const newPid = await readPid(configDir);
|
|
32619
|
+
if (newPid !== null) {
|
|
32620
|
+
console.log(`Daemon started (PID ${newPid})`);
|
|
32621
|
+
} else {
|
|
32622
|
+
console.log(`Daemon started (PID ${child.pid ?? "unknown"})`);
|
|
32623
|
+
}
|
|
32624
|
+
});
|
|
32625
|
+
daemonCmd.command("stop").description("Stop the background sync daemon").action(async () => {
|
|
32626
|
+
const configDir = getConfigDir();
|
|
32627
|
+
const pid = await readPid(configDir);
|
|
32628
|
+
if (pid === null) {
|
|
32629
|
+
console.log("Daemon is not running.");
|
|
32630
|
+
return;
|
|
32631
|
+
}
|
|
32632
|
+
if (!isProcessRunning(pid)) {
|
|
32633
|
+
await rm2(getPidPath(configDir)).catch(() => {});
|
|
32634
|
+
await rm2(getStatusPath(configDir)).catch(() => {});
|
|
32635
|
+
console.log("Daemon is not running (cleaned up stale PID file).");
|
|
32636
|
+
return;
|
|
32637
|
+
}
|
|
32638
|
+
const isWin = platform4() === "win32";
|
|
32639
|
+
if (isWin) {
|
|
32640
|
+
const { execSync: execSync3 } = await import("child_process");
|
|
32641
|
+
try {
|
|
32642
|
+
execSync3(`taskkill /PID ${pid} /F`, { stdio: "ignore" });
|
|
32643
|
+
} catch {
|
|
32644
|
+
console.error(`Failed to stop daemon (PID ${pid}).`);
|
|
32645
|
+
return;
|
|
32646
|
+
}
|
|
32647
|
+
} else {
|
|
32648
|
+
try {
|
|
32649
|
+
process.kill(pid, "SIGTERM");
|
|
32650
|
+
} catch {
|
|
32651
|
+
console.error(`Failed to stop daemon (PID ${pid}).`);
|
|
32652
|
+
return;
|
|
32653
|
+
}
|
|
32654
|
+
}
|
|
32655
|
+
await rm2(getPidPath(configDir)).catch(() => {});
|
|
32656
|
+
await rm2(getStatusPath(configDir)).catch(() => {});
|
|
32657
|
+
console.log("Daemon stopped.");
|
|
32658
|
+
});
|
|
32659
|
+
daemonCmd.command("status").description("Show daemon status").action(async () => {
|
|
32660
|
+
const configDir = getConfigDir();
|
|
32661
|
+
const chalk2 = (await Promise.resolve().then(() => (init_source(), exports_source))).default;
|
|
32662
|
+
const pid = await readPid(configDir);
|
|
32663
|
+
const running = pid !== null && isProcessRunning(pid);
|
|
32664
|
+
console.log(chalk2.bold("Daemon Status"));
|
|
32665
|
+
console.log(` Running: ${running ? chalk2.green("yes") : chalk2.dim("no")}`);
|
|
32666
|
+
if (pid !== null) {
|
|
32667
|
+
console.log(` PID: ${running ? pid : chalk2.dim(`${pid} (stale)`)}`);
|
|
32668
|
+
}
|
|
32669
|
+
try {
|
|
32670
|
+
const raw = await readFile11(getStatusPath(configDir), "utf-8");
|
|
32671
|
+
const status = JSON.parse(raw);
|
|
32672
|
+
const uptime = Date.now() - status.startedAt;
|
|
32673
|
+
const hours = Math.floor(uptime / 3600000);
|
|
32674
|
+
const minutes = Math.floor(uptime % 3600000 / 60000);
|
|
32675
|
+
console.log(` Uptime: ${hours}h ${minutes}m`);
|
|
32676
|
+
console.log(` Pushes: ${status.pushCount}`);
|
|
32677
|
+
console.log(` Pulls: ${status.pullCount}`);
|
|
32678
|
+
if (status.lastPushAt) {
|
|
32679
|
+
console.log(` Last push: ${new Date(status.lastPushAt).toLocaleString()}`);
|
|
32680
|
+
}
|
|
32681
|
+
if (status.lastPullAt) {
|
|
32682
|
+
console.log(` Last pull: ${new Date(status.lastPullAt).toLocaleString()}`);
|
|
32683
|
+
}
|
|
32684
|
+
if (status.lastError) {
|
|
32685
|
+
console.log(` Last error: ${chalk2.red(status.lastError)}`);
|
|
32686
|
+
}
|
|
32687
|
+
} catch {
|
|
32688
|
+
if (!running) {
|
|
32689
|
+
console.log(chalk2.dim(`
|
|
32690
|
+
No status data. Start the daemon with 'ccsini daemon start'.`));
|
|
32691
|
+
}
|
|
32692
|
+
}
|
|
32693
|
+
});
|
|
32694
|
+
daemonCmd.command("logs").description("Show daemon log").option("-n, --lines <number>", "Number of lines to show", "20").action(async (opts) => {
|
|
32695
|
+
const configDir = getConfigDir();
|
|
32696
|
+
const logPath = getLogPath(configDir);
|
|
32697
|
+
const lines = parseInt(opts.lines, 10) || 20;
|
|
32698
|
+
try {
|
|
32699
|
+
const content = await readFile11(logPath, "utf-8");
|
|
32700
|
+
const allLines = content.trimEnd().split(`
|
|
32701
|
+
`);
|
|
32702
|
+
const tail = allLines.slice(-lines);
|
|
32703
|
+
console.log(tail.join(`
|
|
32704
|
+
`));
|
|
32705
|
+
} catch {
|
|
32706
|
+
console.log("No daemon logs found.");
|
|
32707
|
+
}
|
|
32708
|
+
});
|
|
32709
|
+
}
|
|
32710
|
+
|
|
30746
32711
|
// src/commands/menu.ts
|
|
30747
32712
|
init_source();
|
|
30748
32713
|
init_dist16();
|
|
@@ -30761,6 +32726,7 @@ async function showInteractiveMenu(program2) {
|
|
|
30761
32726
|
{ label: "Sync Status", desc: "Show sync status", args: ["sync", "status"] },
|
|
30762
32727
|
{ label: "Sessions", desc: "Configure session sync", args: ["sessions", "status"] },
|
|
30763
32728
|
{ label: "Conflicts", desc: "Resolve sync conflicts", args: ["conflicts"] },
|
|
32729
|
+
{ label: "Daemon", desc: "Background sync daemon", args: ["daemon", "status"] },
|
|
30764
32730
|
{ label: "Doctor", desc: "Check system health", args: ["doctor"] },
|
|
30765
32731
|
{ label: "Hooks Fix", desc: "Repair broken hooks", args: ["hooks", "fix"] },
|
|
30766
32732
|
{ label: "Help", desc: "Show all commands", args: ["--help"] },
|
|
@@ -30811,6 +32777,7 @@ registerHooksCommands(program2);
|
|
|
30811
32777
|
registerResetCommand(program2);
|
|
30812
32778
|
registerSessionsCommand(program2);
|
|
30813
32779
|
registerConflictsCommand(program2);
|
|
32780
|
+
registerDaemonCommands(program2);
|
|
30814
32781
|
program2.command("version").description("Show current version").action(() => {
|
|
30815
32782
|
console.log(VERSION);
|
|
30816
32783
|
});
|