ocx 1.2.1 → 1.3.0
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 +2851 -323
- package/dist/index.js.map +30 -19
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -3761,6 +3761,333 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
3761
3761
|
module.exports = spinners;
|
|
3762
3762
|
});
|
|
3763
3763
|
|
|
3764
|
+
// ../../node_modules/.bun/ignore@7.0.5/node_modules/ignore/index.js
|
|
3765
|
+
var require_ignore = __commonJS((exports, module) => {
|
|
3766
|
+
function makeArray(subject) {
|
|
3767
|
+
return Array.isArray(subject) ? subject : [subject];
|
|
3768
|
+
}
|
|
3769
|
+
var UNDEFINED = undefined;
|
|
3770
|
+
var EMPTY = "";
|
|
3771
|
+
var SPACE = " ";
|
|
3772
|
+
var ESCAPE = "\\";
|
|
3773
|
+
var REGEX_TEST_BLANK_LINE = /^\s+$/;
|
|
3774
|
+
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
3775
|
+
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
3776
|
+
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
3777
|
+
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
3778
|
+
var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
|
|
3779
|
+
var REGEX_TEST_TRAILING_SLASH = /\/$/;
|
|
3780
|
+
var SLASH2 = "/";
|
|
3781
|
+
var TMP_KEY_IGNORE = "node-ignore";
|
|
3782
|
+
if (typeof Symbol !== "undefined") {
|
|
3783
|
+
TMP_KEY_IGNORE = Symbol.for("node-ignore");
|
|
3784
|
+
}
|
|
3785
|
+
var KEY_IGNORE = TMP_KEY_IGNORE;
|
|
3786
|
+
var define2 = (object, key, value) => {
|
|
3787
|
+
Object.defineProperty(object, key, { value });
|
|
3788
|
+
return value;
|
|
3789
|
+
};
|
|
3790
|
+
var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
|
|
3791
|
+
var RETURN_FALSE = () => false;
|
|
3792
|
+
var sanitizeRange = (range) => range.replace(REGEX_REGEXP_RANGE, (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY);
|
|
3793
|
+
var cleanRangeBackSlash = (slashes) => {
|
|
3794
|
+
const { length } = slashes;
|
|
3795
|
+
return slashes.slice(0, length - length % 2);
|
|
3796
|
+
};
|
|
3797
|
+
var REPLACERS = [
|
|
3798
|
+
[
|
|
3799
|
+
/^\uFEFF/,
|
|
3800
|
+
() => EMPTY
|
|
3801
|
+
],
|
|
3802
|
+
[
|
|
3803
|
+
/((?:\\\\)*?)(\\?\s+)$/,
|
|
3804
|
+
(_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
|
|
3805
|
+
],
|
|
3806
|
+
[
|
|
3807
|
+
/(\\+?)\s/g,
|
|
3808
|
+
(_, m1) => {
|
|
3809
|
+
const { length } = m1;
|
|
3810
|
+
return m1.slice(0, length - length % 2) + SPACE;
|
|
3811
|
+
}
|
|
3812
|
+
],
|
|
3813
|
+
[
|
|
3814
|
+
/[\\$.|*+(){^]/g,
|
|
3815
|
+
(match) => `\\${match}`
|
|
3816
|
+
],
|
|
3817
|
+
[
|
|
3818
|
+
/(?!\\)\?/g,
|
|
3819
|
+
() => "[^/]"
|
|
3820
|
+
],
|
|
3821
|
+
[
|
|
3822
|
+
/^\//,
|
|
3823
|
+
() => "^"
|
|
3824
|
+
],
|
|
3825
|
+
[
|
|
3826
|
+
/\//g,
|
|
3827
|
+
() => "\\/"
|
|
3828
|
+
],
|
|
3829
|
+
[
|
|
3830
|
+
/^\^*\\\*\\\*\\\//,
|
|
3831
|
+
() => "^(?:.*\\/)?"
|
|
3832
|
+
],
|
|
3833
|
+
[
|
|
3834
|
+
/^(?=[^^])/,
|
|
3835
|
+
function startingReplacer() {
|
|
3836
|
+
return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
|
|
3837
|
+
}
|
|
3838
|
+
],
|
|
3839
|
+
[
|
|
3840
|
+
/\\\/\\\*\\\*(?=\\\/|$)/g,
|
|
3841
|
+
(_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
|
|
3842
|
+
],
|
|
3843
|
+
[
|
|
3844
|
+
/(^|[^\\]+)(\\\*)+(?=.+)/g,
|
|
3845
|
+
(_, p1, p2) => {
|
|
3846
|
+
const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
|
|
3847
|
+
return p1 + unescaped;
|
|
3848
|
+
}
|
|
3849
|
+
],
|
|
3850
|
+
[
|
|
3851
|
+
/\\\\\\(?=[$.|*+(){^])/g,
|
|
3852
|
+
() => ESCAPE
|
|
3853
|
+
],
|
|
3854
|
+
[
|
|
3855
|
+
/\\\\/g,
|
|
3856
|
+
() => ESCAPE
|
|
3857
|
+
],
|
|
3858
|
+
[
|
|
3859
|
+
/(\\)?\[([^\]/]*?)(\\*)($|\])/g,
|
|
3860
|
+
(match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` : close === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
|
|
3861
|
+
],
|
|
3862
|
+
[
|
|
3863
|
+
/(?:[^*])$/,
|
|
3864
|
+
(match) => /\/$/.test(match) ? `${match}$` : `${match}(?=$|\\/$)`
|
|
3865
|
+
]
|
|
3866
|
+
];
|
|
3867
|
+
var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
|
|
3868
|
+
var MODE_IGNORE = "regex";
|
|
3869
|
+
var MODE_CHECK_IGNORE = "checkRegex";
|
|
3870
|
+
var UNDERSCORE = "_";
|
|
3871
|
+
var TRAILING_WILD_CARD_REPLACERS = {
|
|
3872
|
+
[MODE_IGNORE](_, p1) {
|
|
3873
|
+
const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
|
|
3874
|
+
return `${prefix}(?=$|\\/$)`;
|
|
3875
|
+
},
|
|
3876
|
+
[MODE_CHECK_IGNORE](_, p1) {
|
|
3877
|
+
const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
|
|
3878
|
+
return `${prefix}(?=$|\\/$)`;
|
|
3879
|
+
}
|
|
3880
|
+
};
|
|
3881
|
+
var makeRegexPrefix = (pattern) => REPLACERS.reduce((prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)), pattern);
|
|
3882
|
+
var isString = (subject) => typeof subject === "string";
|
|
3883
|
+
var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
|
|
3884
|
+
var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
|
|
3885
|
+
|
|
3886
|
+
class IgnoreRule {
|
|
3887
|
+
constructor(pattern, mark, body, ignoreCase, negative, prefix) {
|
|
3888
|
+
this.pattern = pattern;
|
|
3889
|
+
this.mark = mark;
|
|
3890
|
+
this.negative = negative;
|
|
3891
|
+
define2(this, "body", body);
|
|
3892
|
+
define2(this, "ignoreCase", ignoreCase);
|
|
3893
|
+
define2(this, "regexPrefix", prefix);
|
|
3894
|
+
}
|
|
3895
|
+
get regex() {
|
|
3896
|
+
const key = UNDERSCORE + MODE_IGNORE;
|
|
3897
|
+
if (this[key]) {
|
|
3898
|
+
return this[key];
|
|
3899
|
+
}
|
|
3900
|
+
return this._make(MODE_IGNORE, key);
|
|
3901
|
+
}
|
|
3902
|
+
get checkRegex() {
|
|
3903
|
+
const key = UNDERSCORE + MODE_CHECK_IGNORE;
|
|
3904
|
+
if (this[key]) {
|
|
3905
|
+
return this[key];
|
|
3906
|
+
}
|
|
3907
|
+
return this._make(MODE_CHECK_IGNORE, key);
|
|
3908
|
+
}
|
|
3909
|
+
_make(mode, key) {
|
|
3910
|
+
const str = this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, TRAILING_WILD_CARD_REPLACERS[mode]);
|
|
3911
|
+
const regex2 = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
|
|
3912
|
+
return define2(this, key, regex2);
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
var createRule = ({
|
|
3916
|
+
pattern,
|
|
3917
|
+
mark
|
|
3918
|
+
}, ignoreCase) => {
|
|
3919
|
+
let negative = false;
|
|
3920
|
+
let body = pattern;
|
|
3921
|
+
if (body.indexOf("!") === 0) {
|
|
3922
|
+
negative = true;
|
|
3923
|
+
body = body.substr(1);
|
|
3924
|
+
}
|
|
3925
|
+
body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
|
|
3926
|
+
const regexPrefix = makeRegexPrefix(body);
|
|
3927
|
+
return new IgnoreRule(pattern, mark, body, ignoreCase, negative, regexPrefix);
|
|
3928
|
+
};
|
|
3929
|
+
|
|
3930
|
+
class RuleManager {
|
|
3931
|
+
constructor(ignoreCase) {
|
|
3932
|
+
this._ignoreCase = ignoreCase;
|
|
3933
|
+
this._rules = [];
|
|
3934
|
+
}
|
|
3935
|
+
_add(pattern) {
|
|
3936
|
+
if (pattern && pattern[KEY_IGNORE]) {
|
|
3937
|
+
this._rules = this._rules.concat(pattern._rules._rules);
|
|
3938
|
+
this._added = true;
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
if (isString(pattern)) {
|
|
3942
|
+
pattern = {
|
|
3943
|
+
pattern
|
|
3944
|
+
};
|
|
3945
|
+
}
|
|
3946
|
+
if (checkPattern(pattern.pattern)) {
|
|
3947
|
+
const rule = createRule(pattern, this._ignoreCase);
|
|
3948
|
+
this._added = true;
|
|
3949
|
+
this._rules.push(rule);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
add(pattern) {
|
|
3953
|
+
this._added = false;
|
|
3954
|
+
makeArray(isString(pattern) ? splitPattern(pattern) : pattern).forEach(this._add, this);
|
|
3955
|
+
return this._added;
|
|
3956
|
+
}
|
|
3957
|
+
test(path5, checkUnignored, mode) {
|
|
3958
|
+
let ignored = false;
|
|
3959
|
+
let unignored = false;
|
|
3960
|
+
let matchedRule;
|
|
3961
|
+
this._rules.forEach((rule) => {
|
|
3962
|
+
const { negative } = rule;
|
|
3963
|
+
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
3964
|
+
return;
|
|
3965
|
+
}
|
|
3966
|
+
const matched = rule[mode].test(path5);
|
|
3967
|
+
if (!matched) {
|
|
3968
|
+
return;
|
|
3969
|
+
}
|
|
3970
|
+
ignored = !negative;
|
|
3971
|
+
unignored = negative;
|
|
3972
|
+
matchedRule = negative ? UNDEFINED : rule;
|
|
3973
|
+
});
|
|
3974
|
+
const ret = {
|
|
3975
|
+
ignored,
|
|
3976
|
+
unignored
|
|
3977
|
+
};
|
|
3978
|
+
if (matchedRule) {
|
|
3979
|
+
ret.rule = matchedRule;
|
|
3980
|
+
}
|
|
3981
|
+
return ret;
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
var throwError = (message, Ctor) => {
|
|
3985
|
+
throw new Ctor(message);
|
|
3986
|
+
};
|
|
3987
|
+
var checkPath = (path5, originalPath, doThrow) => {
|
|
3988
|
+
if (!isString(path5)) {
|
|
3989
|
+
return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
|
|
3990
|
+
}
|
|
3991
|
+
if (!path5) {
|
|
3992
|
+
return doThrow(`path must not be empty`, TypeError);
|
|
3993
|
+
}
|
|
3994
|
+
if (checkPath.isNotRelative(path5)) {
|
|
3995
|
+
const r2 = "`path.relative()`d";
|
|
3996
|
+
return doThrow(`path should be a ${r2} string, but got "${originalPath}"`, RangeError);
|
|
3997
|
+
}
|
|
3998
|
+
return true;
|
|
3999
|
+
};
|
|
4000
|
+
var isNotRelative = (path5) => REGEX_TEST_INVALID_PATH.test(path5);
|
|
4001
|
+
checkPath.isNotRelative = isNotRelative;
|
|
4002
|
+
checkPath.convert = (p) => p;
|
|
4003
|
+
|
|
4004
|
+
class Ignore {
|
|
4005
|
+
constructor({
|
|
4006
|
+
ignorecase = true,
|
|
4007
|
+
ignoreCase = ignorecase,
|
|
4008
|
+
allowRelativePaths = false
|
|
4009
|
+
} = {}) {
|
|
4010
|
+
define2(this, KEY_IGNORE, true);
|
|
4011
|
+
this._rules = new RuleManager(ignoreCase);
|
|
4012
|
+
this._strictPathCheck = !allowRelativePaths;
|
|
4013
|
+
this._initCache();
|
|
4014
|
+
}
|
|
4015
|
+
_initCache() {
|
|
4016
|
+
this._ignoreCache = Object.create(null);
|
|
4017
|
+
this._testCache = Object.create(null);
|
|
4018
|
+
}
|
|
4019
|
+
add(pattern) {
|
|
4020
|
+
if (this._rules.add(pattern)) {
|
|
4021
|
+
this._initCache();
|
|
4022
|
+
}
|
|
4023
|
+
return this;
|
|
4024
|
+
}
|
|
4025
|
+
addPattern(pattern) {
|
|
4026
|
+
return this.add(pattern);
|
|
4027
|
+
}
|
|
4028
|
+
_test(originalPath, cache2, checkUnignored, slices) {
|
|
4029
|
+
const path5 = originalPath && checkPath.convert(originalPath);
|
|
4030
|
+
checkPath(path5, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
|
|
4031
|
+
return this._t(path5, cache2, checkUnignored, slices);
|
|
4032
|
+
}
|
|
4033
|
+
checkIgnore(path5) {
|
|
4034
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path5)) {
|
|
4035
|
+
return this.test(path5);
|
|
4036
|
+
}
|
|
4037
|
+
const slices = path5.split(SLASH2).filter(Boolean);
|
|
4038
|
+
slices.pop();
|
|
4039
|
+
if (slices.length) {
|
|
4040
|
+
const parent = this._t(slices.join(SLASH2) + SLASH2, this._testCache, true, slices);
|
|
4041
|
+
if (parent.ignored) {
|
|
4042
|
+
return parent;
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
return this._rules.test(path5, false, MODE_CHECK_IGNORE);
|
|
4046
|
+
}
|
|
4047
|
+
_t(path5, cache2, checkUnignored, slices) {
|
|
4048
|
+
if (path5 in cache2) {
|
|
4049
|
+
return cache2[path5];
|
|
4050
|
+
}
|
|
4051
|
+
if (!slices) {
|
|
4052
|
+
slices = path5.split(SLASH2).filter(Boolean);
|
|
4053
|
+
}
|
|
4054
|
+
slices.pop();
|
|
4055
|
+
if (!slices.length) {
|
|
4056
|
+
return cache2[path5] = this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
4057
|
+
}
|
|
4058
|
+
const parent = this._t(slices.join(SLASH2) + SLASH2, cache2, checkUnignored, slices);
|
|
4059
|
+
return cache2[path5] = parent.ignored ? parent : this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
4060
|
+
}
|
|
4061
|
+
ignores(path5) {
|
|
4062
|
+
return this._test(path5, this._ignoreCache, false).ignored;
|
|
4063
|
+
}
|
|
4064
|
+
createFilter() {
|
|
4065
|
+
return (path5) => !this.ignores(path5);
|
|
4066
|
+
}
|
|
4067
|
+
filter(paths) {
|
|
4068
|
+
return makeArray(paths).filter(this.createFilter());
|
|
4069
|
+
}
|
|
4070
|
+
test(path5) {
|
|
4071
|
+
return this._test(path5, this._testCache, true);
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
var factory = (options2) => new Ignore(options2);
|
|
4075
|
+
var isPathValid = (path5) => checkPath(path5 && checkPath.convert(path5), path5, RETURN_FALSE);
|
|
4076
|
+
var setupWindows = () => {
|
|
4077
|
+
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
4078
|
+
checkPath.convert = makePosix;
|
|
4079
|
+
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
4080
|
+
checkPath.isNotRelative = (path5) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path5) || isNotRelative(path5);
|
|
4081
|
+
};
|
|
4082
|
+
if (typeof process !== "undefined" && process.platform === "win32") {
|
|
4083
|
+
setupWindows();
|
|
4084
|
+
}
|
|
4085
|
+
module.exports = factory;
|
|
4086
|
+
factory.default = factory;
|
|
4087
|
+
module.exports.isPathValid = isPathValid;
|
|
4088
|
+
define2(module.exports, Symbol.for("setupWindows"), setupWindows);
|
|
4089
|
+
});
|
|
4090
|
+
|
|
3764
4091
|
// ../../node_modules/.bun/fuzzysort@3.1.0/node_modules/fuzzysort/fuzzysort.js
|
|
3765
4092
|
var require_fuzzysort = __commonJS((exports, module) => {
|
|
3766
4093
|
((root, UMD) => {
|
|
@@ -3949,8 +4276,8 @@ var require_fuzzysort = __commonJS((exports, module) => {
|
|
|
3949
4276
|
results.total = resultsLen + limitedCount;
|
|
3950
4277
|
return results;
|
|
3951
4278
|
};
|
|
3952
|
-
var highlight = (result,
|
|
3953
|
-
var callback = typeof
|
|
4279
|
+
var highlight = (result, open2 = "<b>", close = "</b>") => {
|
|
4280
|
+
var callback = typeof open2 === "function" ? open2 : undefined;
|
|
3954
4281
|
var target = result.target;
|
|
3955
4282
|
var targetLen = target.length;
|
|
3956
4283
|
var indexes = result.indexes;
|
|
@@ -3969,7 +4296,7 @@ var require_fuzzysort = __commonJS((exports, module) => {
|
|
|
3969
4296
|
parts.push(highlighted);
|
|
3970
4297
|
highlighted = "";
|
|
3971
4298
|
} else {
|
|
3972
|
-
highlighted +=
|
|
4299
|
+
highlighted += open2;
|
|
3973
4300
|
}
|
|
3974
4301
|
}
|
|
3975
4302
|
if (indexesI === indexes.length) {
|
|
@@ -4018,8 +4345,8 @@ var require_fuzzysort = __commonJS((exports, module) => {
|
|
|
4018
4345
|
set ["indexes"](indexes) {
|
|
4019
4346
|
return this._indexes = indexes;
|
|
4020
4347
|
}
|
|
4021
|
-
["highlight"](
|
|
4022
|
-
return highlight(this,
|
|
4348
|
+
["highlight"](open2, close) {
|
|
4349
|
+
return highlight(this, open2, close);
|
|
4023
4350
|
}
|
|
4024
4351
|
get ["score"]() {
|
|
4025
4352
|
return normalizeScore(this._score);
|
|
@@ -10165,8 +10492,16 @@ var ghostConfigSchema = exports_external.object({
|
|
|
10165
10492
|
$schema: exports_external.string().optional(),
|
|
10166
10493
|
registries: exports_external.record(registryConfigSchema).default({}),
|
|
10167
10494
|
componentPath: safeRelativePathSchema.optional(),
|
|
10168
|
-
|
|
10169
|
-
|
|
10495
|
+
exclude: exports_external.array(globPatternSchema).default([
|
|
10496
|
+
"**/AGENTS.md",
|
|
10497
|
+
"**/CLAUDE.md",
|
|
10498
|
+
"**/CONTEXT.md",
|
|
10499
|
+
".opencode",
|
|
10500
|
+
"opencode.jsonc",
|
|
10501
|
+
"opencode.json"
|
|
10502
|
+
]).describe("Glob patterns to exclude from the symlink farm"),
|
|
10503
|
+
include: exports_external.array(globPatternSchema).default([]).describe("Glob patterns to re-include from excluded set (for power users)"),
|
|
10504
|
+
renameWindow: exports_external.boolean().default(true).describe("Set terminal/tmux window name when launching OpenCode")
|
|
10170
10505
|
});
|
|
10171
10506
|
|
|
10172
10507
|
// src/utils/errors.ts
|
|
@@ -10237,6 +10572,13 @@ class IntegrityError extends OCXError {
|
|
|
10237
10572
|
this.name = "IntegrityError";
|
|
10238
10573
|
}
|
|
10239
10574
|
}
|
|
10575
|
+
|
|
10576
|
+
class SelfUpdateError extends OCXError {
|
|
10577
|
+
constructor(message) {
|
|
10578
|
+
super(message, "UPDATE_ERROR", EXIT_CODES.GENERAL);
|
|
10579
|
+
this.name = "SelfUpdateError";
|
|
10580
|
+
}
|
|
10581
|
+
}
|
|
10240
10582
|
class GhostConfigError extends OCXError {
|
|
10241
10583
|
constructor(message) {
|
|
10242
10584
|
super(message, "CONFIG_ERROR", EXIT_CODES.CONFIG);
|
|
@@ -10334,7 +10676,17 @@ var profileSchema = exports_external.object({
|
|
|
10334
10676
|
// src/profile/manager.ts
|
|
10335
10677
|
var DEFAULT_GHOST_CONFIG = {
|
|
10336
10678
|
$schema: "https://ocx.kdco.dev/schemas/ghost.json",
|
|
10337
|
-
registries: {}
|
|
10679
|
+
registries: {},
|
|
10680
|
+
exclude: [
|
|
10681
|
+
"**/AGENTS.md",
|
|
10682
|
+
"**/CLAUDE.md",
|
|
10683
|
+
"**/CONTEXT.md",
|
|
10684
|
+
".opencode",
|
|
10685
|
+
"opencode.jsonc",
|
|
10686
|
+
"opencode.json"
|
|
10687
|
+
],
|
|
10688
|
+
include: [],
|
|
10689
|
+
renameWindow: true
|
|
10338
10690
|
};
|
|
10339
10691
|
|
|
10340
10692
|
class ProfileManager {
|
|
@@ -10528,7 +10880,7 @@ class GhostConfigProvider {
|
|
|
10528
10880
|
// package.json
|
|
10529
10881
|
var package_default = {
|
|
10530
10882
|
name: "ocx",
|
|
10531
|
-
version: "1.
|
|
10883
|
+
version: "1.3.0",
|
|
10532
10884
|
description: "OCX CLI - ShadCN-style registry for OpenCode extensions. Install agents, plugins, skills, and MCP servers.",
|
|
10533
10885
|
author: "kdcokenny",
|
|
10534
10886
|
license: "MIT",
|
|
@@ -10576,9 +10928,11 @@ var package_default = {
|
|
|
10576
10928
|
test: "bun test"
|
|
10577
10929
|
},
|
|
10578
10930
|
dependencies: {
|
|
10931
|
+
chokidar: "^5.0.0",
|
|
10579
10932
|
commander: "^14.0.0",
|
|
10580
10933
|
diff: "^8.0.0",
|
|
10581
10934
|
fuzzysort: "^3.1.0",
|
|
10935
|
+
ignore: "^7.0.5",
|
|
10582
10936
|
"jsonc-parser": "3.3.1",
|
|
10583
10937
|
kleur: "^4.1.5",
|
|
10584
10938
|
ora: "^8.2.0",
|
|
@@ -10920,6 +11274,19 @@ function isContentIdentical(existing, incoming) {
|
|
|
10920
11274
|
var isCI = Boolean(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.JENKINS_URL || process.env.BUILDKITE);
|
|
10921
11275
|
var isTTY = Boolean(process.stdout.isTTY && !isCI);
|
|
10922
11276
|
var supportsColor = Boolean(isTTY && process.env.FORCE_COLOR !== "0" && process.env.NO_COLOR === undefined);
|
|
11277
|
+
function parseEnvBool(value, defaultValue) {
|
|
11278
|
+
if (value == null || value === "") {
|
|
11279
|
+
return defaultValue;
|
|
11280
|
+
}
|
|
11281
|
+
const normalized = value.trim().toLowerCase();
|
|
11282
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
|
|
11283
|
+
return true;
|
|
11284
|
+
}
|
|
11285
|
+
if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
|
|
11286
|
+
return false;
|
|
11287
|
+
}
|
|
11288
|
+
return defaultValue;
|
|
11289
|
+
}
|
|
10923
11290
|
// src/utils/git-context.ts
|
|
10924
11291
|
import { basename, resolve } from "path";
|
|
10925
11292
|
function getGitEnv() {
|
|
@@ -11194,6 +11561,15 @@ function handleError(error, options2 = {}) {
|
|
|
11194
11561
|
}
|
|
11195
11562
|
process.exit(EXIT_CODES.GENERAL);
|
|
11196
11563
|
}
|
|
11564
|
+
function wrapAction(action) {
|
|
11565
|
+
return async (...args) => {
|
|
11566
|
+
try {
|
|
11567
|
+
await action(...args);
|
|
11568
|
+
} catch (error) {
|
|
11569
|
+
handleError(error);
|
|
11570
|
+
}
|
|
11571
|
+
};
|
|
11572
|
+
}
|
|
11197
11573
|
function formatErrorAsJson(error) {
|
|
11198
11574
|
if (error instanceof OCXError) {
|
|
11199
11575
|
return {
|
|
@@ -12714,20 +13090,18 @@ function parseNpmSpecifier(specifier) {
|
|
|
12714
13090
|
function isNpmSpecifier(input) {
|
|
12715
13091
|
return input.trim().startsWith("npm:");
|
|
12716
13092
|
}
|
|
12717
|
-
async function validateNpmPackage(packageName) {
|
|
13093
|
+
async function validateNpmPackage(packageName, signal) {
|
|
12718
13094
|
validateNpmPackageName(packageName);
|
|
12719
13095
|
const encodedName = packageName.startsWith("@") ? `@${encodeURIComponent(packageName.slice(1))}` : encodeURIComponent(packageName);
|
|
12720
13096
|
const url = `${NPM_REGISTRY_BASE}/${encodedName}`;
|
|
12721
13097
|
try {
|
|
12722
|
-
const
|
|
12723
|
-
const timeoutId = setTimeout(() => controller.abort(), NPM_FETCH_TIMEOUT_MS);
|
|
13098
|
+
const fetchSignal = signal ?? AbortSignal.timeout(NPM_FETCH_TIMEOUT_MS);
|
|
12724
13099
|
const response = await fetch(url, {
|
|
12725
|
-
signal:
|
|
13100
|
+
signal: fetchSignal,
|
|
12726
13101
|
headers: {
|
|
12727
13102
|
Accept: "application/json"
|
|
12728
13103
|
}
|
|
12729
13104
|
});
|
|
12730
|
-
clearTimeout(timeoutId);
|
|
12731
13105
|
if (response.status === 404) {
|
|
12732
13106
|
throw new NotFoundError(`npm package \`${packageName}\` not found on registry`);
|
|
12733
13107
|
}
|
|
@@ -12740,8 +13114,8 @@ async function validateNpmPackage(packageName) {
|
|
|
12740
13114
|
if (error instanceof NotFoundError || error instanceof NetworkError) {
|
|
12741
13115
|
throw error;
|
|
12742
13116
|
}
|
|
12743
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
12744
|
-
throw new NetworkError(`Request to npm registry timed out
|
|
13117
|
+
if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
|
|
13118
|
+
throw new NetworkError(`Request to npm registry timed out for package \`${packageName}\``);
|
|
12745
13119
|
}
|
|
12746
13120
|
const message = error instanceof Error ? error.message : String(error);
|
|
12747
13121
|
throw new NetworkError(`Failed to fetch npm package \`${packageName}\`: ${message}`);
|
|
@@ -12765,8 +13139,8 @@ function validateOpenCodePlugin(packageJson) {
|
|
|
12765
13139
|
}
|
|
12766
13140
|
return { valid: true, warnings };
|
|
12767
13141
|
}
|
|
12768
|
-
async function fetchPackageVersion(packageName, version) {
|
|
12769
|
-
const metadata = await validateNpmPackage(packageName);
|
|
13142
|
+
async function fetchPackageVersion(packageName, version, signal) {
|
|
13143
|
+
const metadata = await validateNpmPackage(packageName, signal);
|
|
12770
13144
|
const resolvedVersion = version ?? metadata["dist-tags"].latest;
|
|
12771
13145
|
const versionData = metadata.versions[resolvedVersion];
|
|
12772
13146
|
if (!versionData) {
|
|
@@ -14387,289 +14761,1905 @@ async function runGhostInit(options2) {
|
|
|
14387
14761
|
}
|
|
14388
14762
|
}
|
|
14389
14763
|
|
|
14390
|
-
// src/
|
|
14391
|
-
import {
|
|
14392
|
-
import {
|
|
14393
|
-
import
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
}
|
|
14398
|
-
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
}
|
|
14764
|
+
// src/commands/ghost/opencode.ts
|
|
14765
|
+
import { renameSync, rmSync } from "fs";
|
|
14766
|
+
import { copyFile, mkdir as mkdir5, readdir as readdir5 } from "fs/promises";
|
|
14767
|
+
import path7 from "path";
|
|
14768
|
+
var {Glob: Glob3 } = globalThis.Bun;
|
|
14769
|
+
|
|
14770
|
+
// src/utils/file-sync.ts
|
|
14771
|
+
import { existsSync as existsSync2, lstatSync, mkdirSync, readFileSync, rmdirSync, unlinkSync } from "fs";
|
|
14772
|
+
import { dirname as dirname5, join as join6, relative as relative4 } from "path";
|
|
14773
|
+
|
|
14774
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
14775
|
+
import { EventEmitter } from "events";
|
|
14776
|
+
import { stat as statcb, Stats } from "fs";
|
|
14777
|
+
import { readdir as readdir3, stat as stat4 } from "fs/promises";
|
|
14778
|
+
import * as sp2 from "path";
|
|
14779
|
+
|
|
14780
|
+
// ../../node_modules/.bun/readdirp@5.0.0/node_modules/readdirp/index.js
|
|
14781
|
+
import { lstat, readdir as readdir2, realpath, stat as stat2 } from "fs/promises";
|
|
14782
|
+
import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "path";
|
|
14783
|
+
import { Readable } from "stream";
|
|
14784
|
+
var EntryTypes = {
|
|
14785
|
+
FILE_TYPE: "files",
|
|
14786
|
+
DIR_TYPE: "directories",
|
|
14787
|
+
FILE_DIR_TYPE: "files_directories",
|
|
14788
|
+
EVERYTHING_TYPE: "all"
|
|
14789
|
+
};
|
|
14790
|
+
var defaultOptions = {
|
|
14791
|
+
root: ".",
|
|
14792
|
+
fileFilter: (_entryInfo) => true,
|
|
14793
|
+
directoryFilter: (_entryInfo) => true,
|
|
14794
|
+
type: EntryTypes.FILE_TYPE,
|
|
14795
|
+
lstat: false,
|
|
14796
|
+
depth: 2147483648,
|
|
14797
|
+
alwaysStat: false,
|
|
14798
|
+
highWaterMark: 4096
|
|
14799
|
+
};
|
|
14800
|
+
Object.freeze(defaultOptions);
|
|
14801
|
+
var RECURSIVE_ERROR_CODE = "READDIRP_RECURSIVE_ERROR";
|
|
14802
|
+
var NORMAL_FLOW_ERRORS = new Set(["ENOENT", "EPERM", "EACCES", "ELOOP", RECURSIVE_ERROR_CODE]);
|
|
14803
|
+
var ALL_TYPES = [
|
|
14804
|
+
EntryTypes.DIR_TYPE,
|
|
14805
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
14806
|
+
EntryTypes.FILE_DIR_TYPE,
|
|
14807
|
+
EntryTypes.FILE_TYPE
|
|
14808
|
+
];
|
|
14809
|
+
var DIR_TYPES = new Set([
|
|
14810
|
+
EntryTypes.DIR_TYPE,
|
|
14811
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
14812
|
+
EntryTypes.FILE_DIR_TYPE
|
|
14813
|
+
]);
|
|
14814
|
+
var FILE_TYPES = new Set([
|
|
14815
|
+
EntryTypes.EVERYTHING_TYPE,
|
|
14816
|
+
EntryTypes.FILE_DIR_TYPE,
|
|
14817
|
+
EntryTypes.FILE_TYPE
|
|
14818
|
+
]);
|
|
14819
|
+
var isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);
|
|
14820
|
+
var wantBigintFsStats = process.platform === "win32";
|
|
14821
|
+
var emptyFn = (_entryInfo) => true;
|
|
14822
|
+
var normalizeFilter = (filter) => {
|
|
14823
|
+
if (filter === undefined)
|
|
14824
|
+
return emptyFn;
|
|
14825
|
+
if (typeof filter === "function")
|
|
14826
|
+
return filter;
|
|
14827
|
+
if (typeof filter === "string") {
|
|
14828
|
+
const fl = filter.trim();
|
|
14829
|
+
return (entry) => entry.basename === fl;
|
|
14830
|
+
}
|
|
14831
|
+
if (Array.isArray(filter)) {
|
|
14832
|
+
const trItems = filter.map((item) => item.trim());
|
|
14833
|
+
return (entry) => trItems.some((f) => entry.basename === f);
|
|
14834
|
+
}
|
|
14835
|
+
return emptyFn;
|
|
14836
|
+
};
|
|
14461
14837
|
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14838
|
+
class ReaddirpStream extends Readable {
|
|
14839
|
+
parents;
|
|
14840
|
+
reading;
|
|
14841
|
+
parent;
|
|
14842
|
+
_stat;
|
|
14843
|
+
_maxDepth;
|
|
14844
|
+
_wantsDir;
|
|
14845
|
+
_wantsFile;
|
|
14846
|
+
_wantsEverything;
|
|
14847
|
+
_root;
|
|
14848
|
+
_isDirent;
|
|
14849
|
+
_statsProp;
|
|
14850
|
+
_rdOptions;
|
|
14851
|
+
_fileFilter;
|
|
14852
|
+
_directoryFilter;
|
|
14853
|
+
constructor(options2 = {}) {
|
|
14854
|
+
super({
|
|
14855
|
+
objectMode: true,
|
|
14856
|
+
autoDestroy: true,
|
|
14857
|
+
highWaterMark: options2.highWaterMark
|
|
14858
|
+
});
|
|
14859
|
+
const opts = { ...defaultOptions, ...options2 };
|
|
14860
|
+
const { root, type } = opts;
|
|
14861
|
+
this._fileFilter = normalizeFilter(opts.fileFilter);
|
|
14862
|
+
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
14863
|
+
const statMethod = opts.lstat ? lstat : stat2;
|
|
14864
|
+
if (wantBigintFsStats) {
|
|
14865
|
+
this._stat = (path5) => statMethod(path5, { bigint: true });
|
|
14866
|
+
} else {
|
|
14867
|
+
this._stat = statMethod;
|
|
14868
|
+
}
|
|
14869
|
+
this._maxDepth = opts.depth != null && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
|
|
14870
|
+
this._wantsDir = type ? DIR_TYPES.has(type) : false;
|
|
14871
|
+
this._wantsFile = type ? FILE_TYPES.has(type) : false;
|
|
14872
|
+
this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
|
|
14873
|
+
this._root = presolve(root);
|
|
14874
|
+
this._isDirent = !opts.alwaysStat;
|
|
14875
|
+
this._statsProp = this._isDirent ? "dirent" : "stats";
|
|
14876
|
+
this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
|
|
14877
|
+
this.parents = [this._exploreDir(root, 1)];
|
|
14878
|
+
this.reading = false;
|
|
14879
|
+
this.parent = undefined;
|
|
14880
|
+
}
|
|
14881
|
+
async _read(batch) {
|
|
14882
|
+
if (this.reading)
|
|
14883
|
+
return;
|
|
14884
|
+
this.reading = true;
|
|
14465
14885
|
try {
|
|
14466
|
-
|
|
14886
|
+
while (!this.destroyed && batch > 0) {
|
|
14887
|
+
const par = this.parent;
|
|
14888
|
+
const fil = par && par.files;
|
|
14889
|
+
if (fil && fil.length > 0) {
|
|
14890
|
+
const { path: path5, depth } = par;
|
|
14891
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path5));
|
|
14892
|
+
const awaited = await Promise.all(slice);
|
|
14893
|
+
for (const entry of awaited) {
|
|
14894
|
+
if (!entry)
|
|
14895
|
+
continue;
|
|
14896
|
+
if (this.destroyed)
|
|
14897
|
+
return;
|
|
14898
|
+
const entryType = await this._getEntryType(entry);
|
|
14899
|
+
if (entryType === "directory" && this._directoryFilter(entry)) {
|
|
14900
|
+
if (depth <= this._maxDepth) {
|
|
14901
|
+
this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
|
|
14902
|
+
}
|
|
14903
|
+
if (this._wantsDir) {
|
|
14904
|
+
this.push(entry);
|
|
14905
|
+
batch--;
|
|
14906
|
+
}
|
|
14907
|
+
} else if ((entryType === "file" || this._includeAsFile(entry)) && this._fileFilter(entry)) {
|
|
14908
|
+
if (this._wantsFile) {
|
|
14909
|
+
this.push(entry);
|
|
14910
|
+
batch--;
|
|
14911
|
+
}
|
|
14912
|
+
}
|
|
14913
|
+
}
|
|
14914
|
+
} else {
|
|
14915
|
+
const parent = this.parents.pop();
|
|
14916
|
+
if (!parent) {
|
|
14917
|
+
this.push(null);
|
|
14918
|
+
break;
|
|
14919
|
+
}
|
|
14920
|
+
this.parent = await parent;
|
|
14921
|
+
if (this.destroyed)
|
|
14922
|
+
return;
|
|
14923
|
+
}
|
|
14924
|
+
}
|
|
14467
14925
|
} catch (error) {
|
|
14468
|
-
|
|
14926
|
+
this.destroy(error);
|
|
14927
|
+
} finally {
|
|
14928
|
+
this.reading = false;
|
|
14469
14929
|
}
|
|
14470
|
-
});
|
|
14471
|
-
}
|
|
14472
|
-
async function runMigrate(options2) {
|
|
14473
|
-
const needsMigrationResult = await needsMigration();
|
|
14474
|
-
if (!needsMigrationResult) {
|
|
14475
|
-
const legacyDir = getLegacyConfigDir();
|
|
14476
|
-
const profilesDir = getProfilesDir();
|
|
14477
|
-
console.log("No migration needed.");
|
|
14478
|
-
console.log(` Legacy config: ${legacyDir} (not found)`);
|
|
14479
|
-
console.log(` Profiles: ${profilesDir}`);
|
|
14480
|
-
return;
|
|
14481
14930
|
}
|
|
14482
|
-
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
console.error("Migration failed:");
|
|
14489
|
-
for (const error of result.errors) {
|
|
14490
|
-
console.error(` - ${error}`);
|
|
14491
|
-
}
|
|
14492
|
-
process.exit(1);
|
|
14493
|
-
}
|
|
14494
|
-
if (options2.dryRun) {
|
|
14495
|
-
console.log("Migration preview:");
|
|
14496
|
-
console.log(`
|
|
14497
|
-
Files to migrate to default profile:`);
|
|
14498
|
-
for (const file of result.migratedFiles) {
|
|
14499
|
-
console.log(` ${file}`);
|
|
14500
|
-
}
|
|
14501
|
-
console.log(`
|
|
14502
|
-
Legacy config will be renamed to:`);
|
|
14503
|
-
console.log(` ${result.backupPath}`);
|
|
14504
|
-
console.log(`
|
|
14505
|
-
Run without --dry-run to perform migration.`);
|
|
14506
|
-
} else {
|
|
14507
|
-
console.log("Migration complete!");
|
|
14508
|
-
console.log(`
|
|
14509
|
-
Migrated to default profile:`);
|
|
14510
|
-
for (const file of result.migratedFiles) {
|
|
14511
|
-
console.log(` ${file}`);
|
|
14931
|
+
async _exploreDir(path5, depth) {
|
|
14932
|
+
let files;
|
|
14933
|
+
try {
|
|
14934
|
+
files = await readdir2(path5, this._rdOptions);
|
|
14935
|
+
} catch (error) {
|
|
14936
|
+
this._onError(error);
|
|
14512
14937
|
}
|
|
14513
|
-
|
|
14514
|
-
Legacy config backed up to:`);
|
|
14515
|
-
console.log(` ${result.backupPath}`);
|
|
14516
|
-
console.log(`
|
|
14517
|
-
Profile location:`);
|
|
14518
|
-
console.log(` ${getProfileDir("default")}`);
|
|
14938
|
+
return { files, depth, path: path5 };
|
|
14519
14939
|
}
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
var CONFIG_FILES = ["opencode.jsonc", "opencode.json"];
|
|
14531
|
-
var RULE_FILES = ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"];
|
|
14532
|
-
var CONFIG_DIRS = [".opencode"];
|
|
14533
|
-
async function findUp(target, start, stop) {
|
|
14534
|
-
let current = start;
|
|
14535
|
-
const result = [];
|
|
14536
|
-
while (true) {
|
|
14537
|
-
const search = join4(current, target);
|
|
14538
|
-
if (await exists(search).catch(() => false)) {
|
|
14539
|
-
result.push(search);
|
|
14940
|
+
async _formatEntry(dirent, path5) {
|
|
14941
|
+
let entry;
|
|
14942
|
+
const basename2 = this._isDirent ? dirent.name : dirent;
|
|
14943
|
+
try {
|
|
14944
|
+
const fullPath = presolve(pjoin(path5, basename2));
|
|
14945
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename2 };
|
|
14946
|
+
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
14947
|
+
} catch (err) {
|
|
14948
|
+
this._onError(err);
|
|
14949
|
+
return;
|
|
14540
14950
|
}
|
|
14541
|
-
|
|
14542
|
-
break;
|
|
14543
|
-
const parent = dirname3(current);
|
|
14544
|
-
if (parent === current)
|
|
14545
|
-
break;
|
|
14546
|
-
current = parent;
|
|
14951
|
+
return entry;
|
|
14547
14952
|
}
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
while (true) {
|
|
14554
|
-
for (const target of targets) {
|
|
14555
|
-
const search = join4(current, target);
|
|
14556
|
-
if (await exists(search).catch(() => false)) {
|
|
14557
|
-
yield search;
|
|
14558
|
-
}
|
|
14953
|
+
_onError(err) {
|
|
14954
|
+
if (isNormalFlowError(err) && !this.destroyed) {
|
|
14955
|
+
this.emit("warn", err);
|
|
14956
|
+
} else {
|
|
14957
|
+
this.destroy(err);
|
|
14559
14958
|
}
|
|
14560
|
-
if (stop === current)
|
|
14561
|
-
break;
|
|
14562
|
-
const parent = dirname3(current);
|
|
14563
|
-
if (parent === current)
|
|
14564
|
-
break;
|
|
14565
|
-
current = parent;
|
|
14566
14959
|
}
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
for (const file of CONFIG_FILES) {
|
|
14571
|
-
const found = await findUp(file, start, stop);
|
|
14572
|
-
for (const path6 of found) {
|
|
14573
|
-
excluded.add(path6);
|
|
14960
|
+
async _getEntryType(entry) {
|
|
14961
|
+
if (!entry && this._statsProp in entry) {
|
|
14962
|
+
return "";
|
|
14574
14963
|
}
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14964
|
+
const stats = entry[this._statsProp];
|
|
14965
|
+
if (stats.isFile())
|
|
14966
|
+
return "file";
|
|
14967
|
+
if (stats.isDirectory())
|
|
14968
|
+
return "directory";
|
|
14969
|
+
if (stats && stats.isSymbolicLink()) {
|
|
14970
|
+
const full = entry.fullPath;
|
|
14971
|
+
try {
|
|
14972
|
+
const entryRealPath = await realpath(full);
|
|
14973
|
+
const entryRealPathStats = await lstat(entryRealPath);
|
|
14974
|
+
if (entryRealPathStats.isFile()) {
|
|
14975
|
+
return "file";
|
|
14976
|
+
}
|
|
14977
|
+
if (entryRealPathStats.isDirectory()) {
|
|
14978
|
+
const len = entryRealPath.length;
|
|
14979
|
+
if (full.startsWith(entryRealPath) && full.substr(len, 1) === psep) {
|
|
14980
|
+
const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
|
|
14981
|
+
recursiveError.code = RECURSIVE_ERROR_CODE;
|
|
14982
|
+
return this._onError(recursiveError);
|
|
14983
|
+
}
|
|
14984
|
+
return "directory";
|
|
14985
|
+
}
|
|
14986
|
+
} catch (error) {
|
|
14987
|
+
this._onError(error);
|
|
14988
|
+
return "";
|
|
14989
|
+
}
|
|
14580
14990
|
}
|
|
14581
14991
|
}
|
|
14582
|
-
|
|
14583
|
-
|
|
14992
|
+
_includeAsFile(entry) {
|
|
14993
|
+
const stats = entry && entry[this._statsProp];
|
|
14994
|
+
return stats && this._wantsEverything && !stats.isDirectory();
|
|
14584
14995
|
}
|
|
14585
|
-
return excluded;
|
|
14586
14996
|
}
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14598
|
-
|
|
14599
|
-
const filteredExclusions = new Set;
|
|
14600
|
-
for (const path6 of excludedPaths) {
|
|
14601
|
-
const matchesInclude = matchesAnyGlob(path6, includeGlobs);
|
|
14602
|
-
const matchesExclude = matchesAnyGlob(path6, excludeGlobs);
|
|
14603
|
-
if (matchesInclude && !matchesExclude) {
|
|
14604
|
-
continue;
|
|
14605
|
-
}
|
|
14606
|
-
filteredExclusions.add(path6);
|
|
14997
|
+
function readdirp(root, options2 = {}) {
|
|
14998
|
+
let type = options2.entryType || options2.type;
|
|
14999
|
+
if (type === "both")
|
|
15000
|
+
type = EntryTypes.FILE_DIR_TYPE;
|
|
15001
|
+
if (type)
|
|
15002
|
+
options2.type = type;
|
|
15003
|
+
if (!root) {
|
|
15004
|
+
throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");
|
|
15005
|
+
} else if (typeof root !== "string") {
|
|
15006
|
+
throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");
|
|
15007
|
+
} else if (type && !ALL_TYPES.includes(type)) {
|
|
15008
|
+
throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(", ")}`);
|
|
14607
15009
|
}
|
|
14608
|
-
|
|
15010
|
+
options2.root = root;
|
|
15011
|
+
return new ReaddirpStream(options2);
|
|
14609
15012
|
}
|
|
14610
15013
|
|
|
14611
|
-
//
|
|
14612
|
-
import {
|
|
14613
|
-
import {
|
|
14614
|
-
import {
|
|
14615
|
-
import
|
|
14616
|
-
var
|
|
14617
|
-
var
|
|
14618
|
-
var
|
|
14619
|
-
var
|
|
14620
|
-
var
|
|
14621
|
-
|
|
14622
|
-
|
|
14623
|
-
|
|
15014
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
15015
|
+
import { watch as fs_watch, unwatchFile, watchFile } from "fs";
|
|
15016
|
+
import { realpath as fsrealpath, lstat as lstat2, open, stat as stat3 } from "fs/promises";
|
|
15017
|
+
import { type as osType } from "os";
|
|
15018
|
+
import * as sp from "path";
|
|
15019
|
+
var STR_DATA = "data";
|
|
15020
|
+
var STR_END = "end";
|
|
15021
|
+
var STR_CLOSE = "close";
|
|
15022
|
+
var EMPTY_FN = () => {};
|
|
15023
|
+
var pl = process.platform;
|
|
15024
|
+
var isWindows = pl === "win32";
|
|
15025
|
+
var isMacos = pl === "darwin";
|
|
15026
|
+
var isLinux = pl === "linux";
|
|
15027
|
+
var isFreeBSD = pl === "freebsd";
|
|
15028
|
+
var isIBMi = osType() === "OS400";
|
|
15029
|
+
var EVENTS = {
|
|
15030
|
+
ALL: "all",
|
|
15031
|
+
READY: "ready",
|
|
15032
|
+
ADD: "add",
|
|
15033
|
+
CHANGE: "change",
|
|
15034
|
+
ADD_DIR: "addDir",
|
|
15035
|
+
UNLINK: "unlink",
|
|
15036
|
+
UNLINK_DIR: "unlinkDir",
|
|
15037
|
+
RAW: "raw",
|
|
15038
|
+
ERROR: "error"
|
|
15039
|
+
};
|
|
15040
|
+
var EV = EVENTS;
|
|
15041
|
+
var THROTTLE_MODE_WATCH = "watch";
|
|
15042
|
+
var statMethods = { lstat: lstat2, stat: stat3 };
|
|
15043
|
+
var KEY_LISTENERS = "listeners";
|
|
15044
|
+
var KEY_ERR = "errHandlers";
|
|
15045
|
+
var KEY_RAW = "rawEmitters";
|
|
15046
|
+
var HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
|
|
15047
|
+
var binaryExtensions = new Set([
|
|
15048
|
+
"3dm",
|
|
15049
|
+
"3ds",
|
|
15050
|
+
"3g2",
|
|
15051
|
+
"3gp",
|
|
15052
|
+
"7z",
|
|
15053
|
+
"a",
|
|
15054
|
+
"aac",
|
|
15055
|
+
"adp",
|
|
15056
|
+
"afdesign",
|
|
15057
|
+
"afphoto",
|
|
15058
|
+
"afpub",
|
|
15059
|
+
"ai",
|
|
15060
|
+
"aif",
|
|
15061
|
+
"aiff",
|
|
15062
|
+
"alz",
|
|
15063
|
+
"ape",
|
|
15064
|
+
"apk",
|
|
15065
|
+
"appimage",
|
|
15066
|
+
"ar",
|
|
15067
|
+
"arj",
|
|
15068
|
+
"asf",
|
|
15069
|
+
"au",
|
|
15070
|
+
"avi",
|
|
15071
|
+
"bak",
|
|
15072
|
+
"baml",
|
|
15073
|
+
"bh",
|
|
15074
|
+
"bin",
|
|
15075
|
+
"bk",
|
|
15076
|
+
"bmp",
|
|
15077
|
+
"btif",
|
|
15078
|
+
"bz2",
|
|
15079
|
+
"bzip2",
|
|
15080
|
+
"cab",
|
|
15081
|
+
"caf",
|
|
15082
|
+
"cgm",
|
|
15083
|
+
"class",
|
|
15084
|
+
"cmx",
|
|
15085
|
+
"cpio",
|
|
15086
|
+
"cr2",
|
|
15087
|
+
"cur",
|
|
15088
|
+
"dat",
|
|
15089
|
+
"dcm",
|
|
15090
|
+
"deb",
|
|
15091
|
+
"dex",
|
|
15092
|
+
"djvu",
|
|
15093
|
+
"dll",
|
|
15094
|
+
"dmg",
|
|
15095
|
+
"dng",
|
|
15096
|
+
"doc",
|
|
15097
|
+
"docm",
|
|
15098
|
+
"docx",
|
|
15099
|
+
"dot",
|
|
15100
|
+
"dotm",
|
|
15101
|
+
"dra",
|
|
15102
|
+
"DS_Store",
|
|
15103
|
+
"dsk",
|
|
15104
|
+
"dts",
|
|
15105
|
+
"dtshd",
|
|
15106
|
+
"dvb",
|
|
15107
|
+
"dwg",
|
|
15108
|
+
"dxf",
|
|
15109
|
+
"ecelp4800",
|
|
15110
|
+
"ecelp7470",
|
|
15111
|
+
"ecelp9600",
|
|
15112
|
+
"egg",
|
|
15113
|
+
"eol",
|
|
15114
|
+
"eot",
|
|
15115
|
+
"epub",
|
|
15116
|
+
"exe",
|
|
15117
|
+
"f4v",
|
|
15118
|
+
"fbs",
|
|
15119
|
+
"fh",
|
|
15120
|
+
"fla",
|
|
15121
|
+
"flac",
|
|
15122
|
+
"flatpak",
|
|
15123
|
+
"fli",
|
|
15124
|
+
"flv",
|
|
15125
|
+
"fpx",
|
|
15126
|
+
"fst",
|
|
15127
|
+
"fvt",
|
|
15128
|
+
"g3",
|
|
15129
|
+
"gh",
|
|
15130
|
+
"gif",
|
|
15131
|
+
"graffle",
|
|
15132
|
+
"gz",
|
|
15133
|
+
"gzip",
|
|
15134
|
+
"h261",
|
|
15135
|
+
"h263",
|
|
15136
|
+
"h264",
|
|
15137
|
+
"icns",
|
|
15138
|
+
"ico",
|
|
15139
|
+
"ief",
|
|
15140
|
+
"img",
|
|
15141
|
+
"ipa",
|
|
15142
|
+
"iso",
|
|
15143
|
+
"jar",
|
|
15144
|
+
"jpeg",
|
|
15145
|
+
"jpg",
|
|
15146
|
+
"jpgv",
|
|
15147
|
+
"jpm",
|
|
15148
|
+
"jxr",
|
|
15149
|
+
"key",
|
|
15150
|
+
"ktx",
|
|
15151
|
+
"lha",
|
|
15152
|
+
"lib",
|
|
15153
|
+
"lvp",
|
|
15154
|
+
"lz",
|
|
15155
|
+
"lzh",
|
|
15156
|
+
"lzma",
|
|
15157
|
+
"lzo",
|
|
15158
|
+
"m3u",
|
|
15159
|
+
"m4a",
|
|
15160
|
+
"m4v",
|
|
15161
|
+
"mar",
|
|
15162
|
+
"mdi",
|
|
15163
|
+
"mht",
|
|
15164
|
+
"mid",
|
|
15165
|
+
"midi",
|
|
15166
|
+
"mj2",
|
|
15167
|
+
"mka",
|
|
15168
|
+
"mkv",
|
|
15169
|
+
"mmr",
|
|
15170
|
+
"mng",
|
|
15171
|
+
"mobi",
|
|
15172
|
+
"mov",
|
|
15173
|
+
"movie",
|
|
15174
|
+
"mp3",
|
|
15175
|
+
"mp4",
|
|
15176
|
+
"mp4a",
|
|
15177
|
+
"mpeg",
|
|
15178
|
+
"mpg",
|
|
15179
|
+
"mpga",
|
|
15180
|
+
"mxu",
|
|
15181
|
+
"nef",
|
|
15182
|
+
"npx",
|
|
15183
|
+
"numbers",
|
|
15184
|
+
"nupkg",
|
|
15185
|
+
"o",
|
|
15186
|
+
"odp",
|
|
15187
|
+
"ods",
|
|
15188
|
+
"odt",
|
|
15189
|
+
"oga",
|
|
15190
|
+
"ogg",
|
|
15191
|
+
"ogv",
|
|
15192
|
+
"otf",
|
|
15193
|
+
"ott",
|
|
15194
|
+
"pages",
|
|
15195
|
+
"pbm",
|
|
15196
|
+
"pcx",
|
|
15197
|
+
"pdb",
|
|
15198
|
+
"pdf",
|
|
15199
|
+
"pea",
|
|
15200
|
+
"pgm",
|
|
15201
|
+
"pic",
|
|
15202
|
+
"png",
|
|
15203
|
+
"pnm",
|
|
15204
|
+
"pot",
|
|
15205
|
+
"potm",
|
|
15206
|
+
"potx",
|
|
15207
|
+
"ppa",
|
|
15208
|
+
"ppam",
|
|
15209
|
+
"ppm",
|
|
15210
|
+
"pps",
|
|
15211
|
+
"ppsm",
|
|
15212
|
+
"ppsx",
|
|
15213
|
+
"ppt",
|
|
15214
|
+
"pptm",
|
|
15215
|
+
"pptx",
|
|
15216
|
+
"psd",
|
|
15217
|
+
"pya",
|
|
15218
|
+
"pyc",
|
|
15219
|
+
"pyo",
|
|
15220
|
+
"pyv",
|
|
15221
|
+
"qt",
|
|
15222
|
+
"rar",
|
|
15223
|
+
"ras",
|
|
15224
|
+
"raw",
|
|
15225
|
+
"resources",
|
|
15226
|
+
"rgb",
|
|
15227
|
+
"rip",
|
|
15228
|
+
"rlc",
|
|
15229
|
+
"rmf",
|
|
15230
|
+
"rmvb",
|
|
15231
|
+
"rpm",
|
|
15232
|
+
"rtf",
|
|
15233
|
+
"rz",
|
|
15234
|
+
"s3m",
|
|
15235
|
+
"s7z",
|
|
15236
|
+
"scpt",
|
|
15237
|
+
"sgi",
|
|
15238
|
+
"shar",
|
|
15239
|
+
"snap",
|
|
15240
|
+
"sil",
|
|
15241
|
+
"sketch",
|
|
15242
|
+
"slk",
|
|
15243
|
+
"smv",
|
|
15244
|
+
"snk",
|
|
15245
|
+
"so",
|
|
15246
|
+
"stl",
|
|
15247
|
+
"suo",
|
|
15248
|
+
"sub",
|
|
15249
|
+
"swf",
|
|
15250
|
+
"tar",
|
|
15251
|
+
"tbz",
|
|
15252
|
+
"tbz2",
|
|
15253
|
+
"tga",
|
|
15254
|
+
"tgz",
|
|
15255
|
+
"thmx",
|
|
15256
|
+
"tif",
|
|
15257
|
+
"tiff",
|
|
15258
|
+
"tlz",
|
|
15259
|
+
"ttc",
|
|
15260
|
+
"ttf",
|
|
15261
|
+
"txz",
|
|
15262
|
+
"udf",
|
|
15263
|
+
"uvh",
|
|
15264
|
+
"uvi",
|
|
15265
|
+
"uvm",
|
|
15266
|
+
"uvp",
|
|
15267
|
+
"uvs",
|
|
15268
|
+
"uvu",
|
|
15269
|
+
"viv",
|
|
15270
|
+
"vob",
|
|
15271
|
+
"war",
|
|
15272
|
+
"wav",
|
|
15273
|
+
"wax",
|
|
15274
|
+
"wbmp",
|
|
15275
|
+
"wdp",
|
|
15276
|
+
"weba",
|
|
15277
|
+
"webm",
|
|
15278
|
+
"webp",
|
|
15279
|
+
"whl",
|
|
15280
|
+
"wim",
|
|
15281
|
+
"wm",
|
|
15282
|
+
"wma",
|
|
15283
|
+
"wmv",
|
|
15284
|
+
"wmx",
|
|
15285
|
+
"woff",
|
|
15286
|
+
"woff2",
|
|
15287
|
+
"wrm",
|
|
15288
|
+
"wvx",
|
|
15289
|
+
"xbm",
|
|
15290
|
+
"xif",
|
|
15291
|
+
"xla",
|
|
15292
|
+
"xlam",
|
|
15293
|
+
"xls",
|
|
15294
|
+
"xlsb",
|
|
15295
|
+
"xlsm",
|
|
15296
|
+
"xlsx",
|
|
15297
|
+
"xlt",
|
|
15298
|
+
"xltm",
|
|
15299
|
+
"xltx",
|
|
15300
|
+
"xm",
|
|
15301
|
+
"xmind",
|
|
15302
|
+
"xpi",
|
|
15303
|
+
"xpm",
|
|
15304
|
+
"xwd",
|
|
15305
|
+
"xz",
|
|
15306
|
+
"z",
|
|
15307
|
+
"zip",
|
|
15308
|
+
"zipx"
|
|
15309
|
+
]);
|
|
15310
|
+
var isBinaryPath = (filePath) => binaryExtensions.has(sp.extname(filePath).slice(1).toLowerCase());
|
|
15311
|
+
var foreach = (val, fn) => {
|
|
15312
|
+
if (val instanceof Set) {
|
|
15313
|
+
val.forEach(fn);
|
|
15314
|
+
} else {
|
|
15315
|
+
fn(val);
|
|
14624
15316
|
}
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
15317
|
+
};
|
|
15318
|
+
var addAndConvert = (main2, prop, item) => {
|
|
15319
|
+
let container = main2[prop];
|
|
15320
|
+
if (!(container instanceof Set)) {
|
|
15321
|
+
main2[prop] = container = new Set([container]);
|
|
15322
|
+
}
|
|
15323
|
+
container.add(item);
|
|
15324
|
+
};
|
|
15325
|
+
var clearItem = (cont) => (key) => {
|
|
15326
|
+
const set = cont[key];
|
|
15327
|
+
if (set instanceof Set) {
|
|
15328
|
+
set.clear();
|
|
15329
|
+
} else {
|
|
15330
|
+
delete cont[key];
|
|
15331
|
+
}
|
|
15332
|
+
};
|
|
15333
|
+
var delFromSet = (main2, prop, item) => {
|
|
15334
|
+
const container = main2[prop];
|
|
15335
|
+
if (container instanceof Set) {
|
|
15336
|
+
container.delete(item);
|
|
15337
|
+
} else if (container === item) {
|
|
15338
|
+
delete main2[prop];
|
|
15339
|
+
}
|
|
15340
|
+
};
|
|
15341
|
+
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15342
|
+
var FsWatchInstances = new Map;
|
|
15343
|
+
function createFsWatchInstance(path5, options2, listener, errHandler, emitRaw) {
|
|
15344
|
+
const handleEvent = (rawEvent, evPath) => {
|
|
15345
|
+
listener(path5);
|
|
15346
|
+
emitRaw(rawEvent, evPath, { watchedPath: path5 });
|
|
15347
|
+
if (evPath && path5 !== evPath) {
|
|
15348
|
+
fsWatchBroadcast(sp.resolve(path5, evPath), KEY_LISTENERS, sp.join(path5, evPath));
|
|
14636
15349
|
}
|
|
14637
|
-
|
|
15350
|
+
};
|
|
15351
|
+
try {
|
|
15352
|
+
return fs_watch(path5, {
|
|
15353
|
+
persistent: options2.persistent
|
|
15354
|
+
}, handleEvent);
|
|
14638
15355
|
} catch (error) {
|
|
14639
|
-
|
|
14640
|
-
|
|
15356
|
+
errHandler(error);
|
|
15357
|
+
return;
|
|
14641
15358
|
}
|
|
14642
15359
|
}
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
15360
|
+
var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
15361
|
+
const cont = FsWatchInstances.get(fullPath);
|
|
15362
|
+
if (!cont)
|
|
15363
|
+
return;
|
|
15364
|
+
foreach(cont[listenerType], (listener) => {
|
|
15365
|
+
listener(val1, val2, val3);
|
|
15366
|
+
});
|
|
15367
|
+
};
|
|
15368
|
+
var setFsWatchListener = (path5, fullPath, options2, handlers) => {
|
|
15369
|
+
const { listener, errHandler, rawEmitter } = handlers;
|
|
15370
|
+
let cont = FsWatchInstances.get(fullPath);
|
|
15371
|
+
let watcher;
|
|
15372
|
+
if (!options2.persistent) {
|
|
15373
|
+
watcher = createFsWatchInstance(path5, options2, listener, errHandler, rawEmitter);
|
|
15374
|
+
if (!watcher)
|
|
15375
|
+
return;
|
|
15376
|
+
return watcher.close.bind(watcher);
|
|
14646
15377
|
}
|
|
14647
|
-
if (
|
|
14648
|
-
|
|
15378
|
+
if (cont) {
|
|
15379
|
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
|
15380
|
+
addAndConvert(cont, KEY_ERR, errHandler);
|
|
15381
|
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15382
|
+
} else {
|
|
15383
|
+
watcher = createFsWatchInstance(path5, options2, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
|
|
15384
|
+
if (!watcher)
|
|
15385
|
+
return;
|
|
15386
|
+
watcher.on(EV.ERROR, async (error) => {
|
|
15387
|
+
const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
|
|
15388
|
+
if (cont)
|
|
15389
|
+
cont.watcherUnusable = true;
|
|
15390
|
+
if (isWindows && error.code === "EPERM") {
|
|
15391
|
+
try {
|
|
15392
|
+
const fd = await open(path5, "r");
|
|
15393
|
+
await fd.close();
|
|
15394
|
+
broadcastErr(error);
|
|
15395
|
+
} catch (err) {}
|
|
15396
|
+
} else {
|
|
15397
|
+
broadcastErr(error);
|
|
15398
|
+
}
|
|
15399
|
+
});
|
|
15400
|
+
cont = {
|
|
15401
|
+
listeners: listener,
|
|
15402
|
+
errHandlers: errHandler,
|
|
15403
|
+
rawEmitters: rawEmitter,
|
|
15404
|
+
watcher
|
|
15405
|
+
};
|
|
15406
|
+
FsWatchInstances.set(fullPath, cont);
|
|
15407
|
+
}
|
|
15408
|
+
return () => {
|
|
15409
|
+
delFromSet(cont, KEY_LISTENERS, listener);
|
|
15410
|
+
delFromSet(cont, KEY_ERR, errHandler);
|
|
15411
|
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
15412
|
+
if (isEmptySet(cont.listeners)) {
|
|
15413
|
+
cont.watcher.close();
|
|
15414
|
+
FsWatchInstances.delete(fullPath);
|
|
15415
|
+
HANDLER_KEYS.forEach(clearItem(cont));
|
|
15416
|
+
cont.watcher = undefined;
|
|
15417
|
+
Object.freeze(cont);
|
|
15418
|
+
}
|
|
15419
|
+
};
|
|
15420
|
+
};
|
|
15421
|
+
var FsWatchFileInstances = new Map;
|
|
15422
|
+
var setFsWatchFileListener = (path5, fullPath, options2, handlers) => {
|
|
15423
|
+
const { listener, rawEmitter } = handlers;
|
|
15424
|
+
let cont = FsWatchFileInstances.get(fullPath);
|
|
15425
|
+
const copts = cont && cont.options;
|
|
15426
|
+
if (copts && (copts.persistent < options2.persistent || copts.interval > options2.interval)) {
|
|
15427
|
+
unwatchFile(fullPath);
|
|
15428
|
+
cont = undefined;
|
|
15429
|
+
}
|
|
15430
|
+
if (cont) {
|
|
15431
|
+
addAndConvert(cont, KEY_LISTENERS, listener);
|
|
15432
|
+
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15433
|
+
} else {
|
|
15434
|
+
cont = {
|
|
15435
|
+
listeners: listener,
|
|
15436
|
+
rawEmitters: rawEmitter,
|
|
15437
|
+
options: options2,
|
|
15438
|
+
watcher: watchFile(fullPath, options2, (curr, prev) => {
|
|
15439
|
+
foreach(cont.rawEmitters, (rawEmitter2) => {
|
|
15440
|
+
rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
|
|
15441
|
+
});
|
|
15442
|
+
const currmtime = curr.mtimeMs;
|
|
15443
|
+
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
15444
|
+
foreach(cont.listeners, (listener2) => listener2(path5, curr));
|
|
15445
|
+
}
|
|
15446
|
+
})
|
|
15447
|
+
};
|
|
15448
|
+
FsWatchFileInstances.set(fullPath, cont);
|
|
14649
15449
|
}
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
15450
|
+
return () => {
|
|
15451
|
+
delFromSet(cont, KEY_LISTENERS, listener);
|
|
15452
|
+
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
15453
|
+
if (isEmptySet(cont.listeners)) {
|
|
15454
|
+
FsWatchFileInstances.delete(fullPath);
|
|
15455
|
+
unwatchFile(fullPath);
|
|
15456
|
+
cont.options = cont.watcher = undefined;
|
|
15457
|
+
Object.freeze(cont);
|
|
14654
15458
|
}
|
|
14655
|
-
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
15459
|
+
};
|
|
15460
|
+
};
|
|
15461
|
+
|
|
15462
|
+
class NodeFsHandler {
|
|
15463
|
+
fsw;
|
|
15464
|
+
_boundHandleError;
|
|
15465
|
+
constructor(fsW) {
|
|
15466
|
+
this.fsw = fsW;
|
|
15467
|
+
this._boundHandleError = (error) => fsW._handleError(error);
|
|
15468
|
+
}
|
|
15469
|
+
_watchWithNodeFs(path5, listener) {
|
|
15470
|
+
const opts = this.fsw.options;
|
|
15471
|
+
const directory = sp.dirname(path5);
|
|
15472
|
+
const basename3 = sp.basename(path5);
|
|
15473
|
+
const parent = this.fsw._getWatchedDir(directory);
|
|
15474
|
+
parent.add(basename3);
|
|
15475
|
+
const absolutePath = sp.resolve(path5);
|
|
15476
|
+
const options2 = {
|
|
15477
|
+
persistent: opts.persistent
|
|
15478
|
+
};
|
|
15479
|
+
if (!listener)
|
|
15480
|
+
listener = EMPTY_FN;
|
|
15481
|
+
let closer;
|
|
15482
|
+
if (opts.usePolling) {
|
|
15483
|
+
const enableBin = opts.interval !== opts.binaryInterval;
|
|
15484
|
+
options2.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
|
|
15485
|
+
closer = setFsWatchFileListener(path5, absolutePath, options2, {
|
|
15486
|
+
listener,
|
|
15487
|
+
rawEmitter: this.fsw._emitRaw
|
|
15488
|
+
});
|
|
15489
|
+
} else {
|
|
15490
|
+
closer = setFsWatchListener(path5, absolutePath, options2, {
|
|
15491
|
+
listener,
|
|
15492
|
+
errHandler: this._boundHandleError,
|
|
15493
|
+
rawEmitter: this.fsw._emitRaw
|
|
15494
|
+
});
|
|
14659
15495
|
}
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
15496
|
+
return closer;
|
|
15497
|
+
}
|
|
15498
|
+
_handleFile(file, stats, initialAdd) {
|
|
15499
|
+
if (this.fsw.closed) {
|
|
15500
|
+
return;
|
|
15501
|
+
}
|
|
15502
|
+
const dirname4 = sp.dirname(file);
|
|
15503
|
+
const basename3 = sp.basename(file);
|
|
15504
|
+
const parent = this.fsw._getWatchedDir(dirname4);
|
|
15505
|
+
let prevStats = stats;
|
|
15506
|
+
if (parent.has(basename3))
|
|
15507
|
+
return;
|
|
15508
|
+
const listener = async (path5, newStats) => {
|
|
15509
|
+
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
15510
|
+
return;
|
|
15511
|
+
if (!newStats || newStats.mtimeMs === 0) {
|
|
15512
|
+
try {
|
|
15513
|
+
const newStats2 = await stat3(file);
|
|
15514
|
+
if (this.fsw.closed)
|
|
15515
|
+
return;
|
|
15516
|
+
const at = newStats2.atimeMs;
|
|
15517
|
+
const mt = newStats2.mtimeMs;
|
|
15518
|
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
15519
|
+
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
15520
|
+
}
|
|
15521
|
+
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
15522
|
+
this.fsw._closeFile(path5);
|
|
15523
|
+
prevStats = newStats2;
|
|
15524
|
+
const closer2 = this._watchWithNodeFs(file, listener);
|
|
15525
|
+
if (closer2)
|
|
15526
|
+
this.fsw._addPathCloser(path5, closer2);
|
|
15527
|
+
} else {
|
|
15528
|
+
prevStats = newStats2;
|
|
15529
|
+
}
|
|
15530
|
+
} catch (error) {
|
|
15531
|
+
this.fsw._remove(dirname4, basename3);
|
|
15532
|
+
}
|
|
15533
|
+
} else if (parent.has(basename3)) {
|
|
15534
|
+
const at = newStats.atimeMs;
|
|
15535
|
+
const mt = newStats.mtimeMs;
|
|
15536
|
+
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
15537
|
+
this.fsw._emit(EV.CHANGE, file, newStats);
|
|
15538
|
+
}
|
|
15539
|
+
prevStats = newStats;
|
|
14665
15540
|
}
|
|
15541
|
+
};
|
|
15542
|
+
const closer = this._watchWithNodeFs(file, listener);
|
|
15543
|
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
|
|
15544
|
+
if (!this.fsw._throttle(EV.ADD, file, 0))
|
|
15545
|
+
return;
|
|
15546
|
+
this.fsw._emit(EV.ADD, file, stats);
|
|
14666
15547
|
}
|
|
15548
|
+
return closer;
|
|
15549
|
+
}
|
|
15550
|
+
async _handleSymlink(entry, directory, path5, item) {
|
|
15551
|
+
if (this.fsw.closed) {
|
|
15552
|
+
return;
|
|
15553
|
+
}
|
|
15554
|
+
const full = entry.fullPath;
|
|
15555
|
+
const dir = this.fsw._getWatchedDir(directory);
|
|
15556
|
+
if (!this.fsw.options.followSymlinks) {
|
|
15557
|
+
this.fsw._incrReadyCount();
|
|
15558
|
+
let linkPath;
|
|
15559
|
+
try {
|
|
15560
|
+
linkPath = await fsrealpath(path5);
|
|
15561
|
+
} catch (e3) {
|
|
15562
|
+
this.fsw._emitReady();
|
|
15563
|
+
return true;
|
|
15564
|
+
}
|
|
15565
|
+
if (this.fsw.closed)
|
|
15566
|
+
return;
|
|
15567
|
+
if (dir.has(item)) {
|
|
15568
|
+
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
15569
|
+
this.fsw._symlinkPaths.set(full, linkPath);
|
|
15570
|
+
this.fsw._emit(EV.CHANGE, path5, entry.stats);
|
|
15571
|
+
}
|
|
15572
|
+
} else {
|
|
15573
|
+
dir.add(item);
|
|
15574
|
+
this.fsw._symlinkPaths.set(full, linkPath);
|
|
15575
|
+
this.fsw._emit(EV.ADD, path5, entry.stats);
|
|
15576
|
+
}
|
|
15577
|
+
this.fsw._emitReady();
|
|
15578
|
+
return true;
|
|
15579
|
+
}
|
|
15580
|
+
if (this.fsw._symlinkPaths.has(full)) {
|
|
15581
|
+
return true;
|
|
15582
|
+
}
|
|
15583
|
+
this.fsw._symlinkPaths.set(full, true);
|
|
15584
|
+
}
|
|
15585
|
+
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
|
|
15586
|
+
directory = sp.join(directory, "");
|
|
15587
|
+
const throttleKey = target ? `${directory}:${target}` : directory;
|
|
15588
|
+
throttler = this.fsw._throttle("readdir", throttleKey, 1000);
|
|
15589
|
+
if (!throttler)
|
|
15590
|
+
return;
|
|
15591
|
+
const previous = this.fsw._getWatchedDir(wh.path);
|
|
15592
|
+
const current = new Set;
|
|
15593
|
+
let stream = this.fsw._readdirp(directory, {
|
|
15594
|
+
fileFilter: (entry) => wh.filterPath(entry),
|
|
15595
|
+
directoryFilter: (entry) => wh.filterDir(entry)
|
|
15596
|
+
});
|
|
15597
|
+
if (!stream)
|
|
15598
|
+
return;
|
|
15599
|
+
stream.on(STR_DATA, async (entry) => {
|
|
15600
|
+
if (this.fsw.closed) {
|
|
15601
|
+
stream = undefined;
|
|
15602
|
+
return;
|
|
15603
|
+
}
|
|
15604
|
+
const item = entry.path;
|
|
15605
|
+
let path5 = sp.join(directory, item);
|
|
15606
|
+
current.add(item);
|
|
15607
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path5, item)) {
|
|
15608
|
+
return;
|
|
15609
|
+
}
|
|
15610
|
+
if (this.fsw.closed) {
|
|
15611
|
+
stream = undefined;
|
|
15612
|
+
return;
|
|
15613
|
+
}
|
|
15614
|
+
if (item === target || !target && !previous.has(item)) {
|
|
15615
|
+
this.fsw._incrReadyCount();
|
|
15616
|
+
path5 = sp.join(dir, sp.relative(dir, path5));
|
|
15617
|
+
this._addToNodeFs(path5, initialAdd, wh, depth + 1);
|
|
15618
|
+
}
|
|
15619
|
+
}).on(EV.ERROR, this._boundHandleError);
|
|
15620
|
+
return new Promise((resolve3, reject) => {
|
|
15621
|
+
if (!stream)
|
|
15622
|
+
return reject();
|
|
15623
|
+
stream.once(STR_END, () => {
|
|
15624
|
+
if (this.fsw.closed) {
|
|
15625
|
+
stream = undefined;
|
|
15626
|
+
return;
|
|
15627
|
+
}
|
|
15628
|
+
const wasThrottled = throttler ? throttler.clear() : false;
|
|
15629
|
+
resolve3(undefined);
|
|
15630
|
+
previous.getChildren().filter((item) => {
|
|
15631
|
+
return item !== directory && !current.has(item);
|
|
15632
|
+
}).forEach((item) => {
|
|
15633
|
+
this.fsw._remove(directory, item);
|
|
15634
|
+
});
|
|
15635
|
+
stream = undefined;
|
|
15636
|
+
if (wasThrottled)
|
|
15637
|
+
this._handleRead(directory, false, wh, target, dir, depth, throttler);
|
|
15638
|
+
});
|
|
15639
|
+
});
|
|
15640
|
+
}
|
|
15641
|
+
async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath2) {
|
|
15642
|
+
const parentDir = this.fsw._getWatchedDir(sp.dirname(dir));
|
|
15643
|
+
const tracked = parentDir.has(sp.basename(dir));
|
|
15644
|
+
if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
|
|
15645
|
+
this.fsw._emit(EV.ADD_DIR, dir, stats);
|
|
15646
|
+
}
|
|
15647
|
+
parentDir.add(sp.basename(dir));
|
|
15648
|
+
this.fsw._getWatchedDir(dir);
|
|
15649
|
+
let throttler;
|
|
15650
|
+
let closer;
|
|
15651
|
+
const oDepth = this.fsw.options.depth;
|
|
15652
|
+
if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath2)) {
|
|
15653
|
+
if (!target) {
|
|
15654
|
+
await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
|
|
15655
|
+
if (this.fsw.closed)
|
|
15656
|
+
return;
|
|
15657
|
+
}
|
|
15658
|
+
closer = this._watchWithNodeFs(dir, (dirPath, stats2) => {
|
|
15659
|
+
if (stats2 && stats2.mtimeMs === 0)
|
|
15660
|
+
return;
|
|
15661
|
+
this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
|
|
15662
|
+
});
|
|
15663
|
+
}
|
|
15664
|
+
return closer;
|
|
15665
|
+
}
|
|
15666
|
+
async _addToNodeFs(path5, initialAdd, priorWh, depth, target) {
|
|
15667
|
+
const ready = this.fsw._emitReady;
|
|
15668
|
+
if (this.fsw._isIgnored(path5) || this.fsw.closed) {
|
|
15669
|
+
ready();
|
|
15670
|
+
return false;
|
|
15671
|
+
}
|
|
15672
|
+
const wh = this.fsw._getWatchHelpers(path5);
|
|
15673
|
+
if (priorWh) {
|
|
15674
|
+
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
15675
|
+
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
15676
|
+
}
|
|
15677
|
+
try {
|
|
15678
|
+
const stats = await statMethods[wh.statMethod](wh.watchPath);
|
|
15679
|
+
if (this.fsw.closed)
|
|
15680
|
+
return;
|
|
15681
|
+
if (this.fsw._isIgnored(wh.watchPath, stats)) {
|
|
15682
|
+
ready();
|
|
15683
|
+
return false;
|
|
15684
|
+
}
|
|
15685
|
+
const follow = this.fsw.options.followSymlinks;
|
|
15686
|
+
let closer;
|
|
15687
|
+
if (stats.isDirectory()) {
|
|
15688
|
+
const absPath = sp.resolve(path5);
|
|
15689
|
+
const targetPath = follow ? await fsrealpath(path5) : path5;
|
|
15690
|
+
if (this.fsw.closed)
|
|
15691
|
+
return;
|
|
15692
|
+
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
15693
|
+
if (this.fsw.closed)
|
|
15694
|
+
return;
|
|
15695
|
+
if (absPath !== targetPath && targetPath !== undefined) {
|
|
15696
|
+
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
15697
|
+
}
|
|
15698
|
+
} else if (stats.isSymbolicLink()) {
|
|
15699
|
+
const targetPath = follow ? await fsrealpath(path5) : path5;
|
|
15700
|
+
if (this.fsw.closed)
|
|
15701
|
+
return;
|
|
15702
|
+
const parent = sp.dirname(wh.watchPath);
|
|
15703
|
+
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
15704
|
+
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
15705
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path5, wh, targetPath);
|
|
15706
|
+
if (this.fsw.closed)
|
|
15707
|
+
return;
|
|
15708
|
+
if (targetPath !== undefined) {
|
|
15709
|
+
this.fsw._symlinkPaths.set(sp.resolve(path5), targetPath);
|
|
15710
|
+
}
|
|
15711
|
+
} else {
|
|
15712
|
+
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
15713
|
+
}
|
|
15714
|
+
ready();
|
|
15715
|
+
if (closer)
|
|
15716
|
+
this.fsw._addPathCloser(path5, closer);
|
|
15717
|
+
return false;
|
|
15718
|
+
} catch (error) {
|
|
15719
|
+
if (this.fsw._handleError(error)) {
|
|
15720
|
+
ready();
|
|
15721
|
+
return path5;
|
|
15722
|
+
}
|
|
15723
|
+
}
|
|
15724
|
+
}
|
|
15725
|
+
}
|
|
15726
|
+
|
|
15727
|
+
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
15728
|
+
/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
|
|
15729
|
+
var SLASH = "/";
|
|
15730
|
+
var SLASH_SLASH = "//";
|
|
15731
|
+
var ONE_DOT = ".";
|
|
15732
|
+
var TWO_DOTS = "..";
|
|
15733
|
+
var STRING_TYPE = "string";
|
|
15734
|
+
var BACK_SLASH_RE = /\\/g;
|
|
15735
|
+
var DOUBLE_SLASH_RE = /\/\//g;
|
|
15736
|
+
var DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
|
|
15737
|
+
var REPLACER_RE = /^\.[/\\]/;
|
|
15738
|
+
function arrify(item) {
|
|
15739
|
+
return Array.isArray(item) ? item : [item];
|
|
15740
|
+
}
|
|
15741
|
+
var isMatcherObject = (matcher) => typeof matcher === "object" && matcher !== null && !(matcher instanceof RegExp);
|
|
15742
|
+
function createPattern(matcher) {
|
|
15743
|
+
if (typeof matcher === "function")
|
|
15744
|
+
return matcher;
|
|
15745
|
+
if (typeof matcher === "string")
|
|
15746
|
+
return (string) => matcher === string;
|
|
15747
|
+
if (matcher instanceof RegExp)
|
|
15748
|
+
return (string) => matcher.test(string);
|
|
15749
|
+
if (typeof matcher === "object" && matcher !== null) {
|
|
15750
|
+
return (string) => {
|
|
15751
|
+
if (matcher.path === string)
|
|
15752
|
+
return true;
|
|
15753
|
+
if (matcher.recursive) {
|
|
15754
|
+
const relative4 = sp2.relative(matcher.path, string);
|
|
15755
|
+
if (!relative4) {
|
|
15756
|
+
return false;
|
|
15757
|
+
}
|
|
15758
|
+
return !relative4.startsWith("..") && !sp2.isAbsolute(relative4);
|
|
15759
|
+
}
|
|
15760
|
+
return false;
|
|
15761
|
+
};
|
|
15762
|
+
}
|
|
15763
|
+
return () => false;
|
|
15764
|
+
}
|
|
15765
|
+
function normalizePath(path5) {
|
|
15766
|
+
if (typeof path5 !== "string")
|
|
15767
|
+
throw new Error("string expected");
|
|
15768
|
+
path5 = sp2.normalize(path5);
|
|
15769
|
+
path5 = path5.replace(/\\/g, "/");
|
|
15770
|
+
let prepend = false;
|
|
15771
|
+
if (path5.startsWith("//"))
|
|
15772
|
+
prepend = true;
|
|
15773
|
+
path5 = path5.replace(DOUBLE_SLASH_RE, "/");
|
|
15774
|
+
if (prepend)
|
|
15775
|
+
path5 = "/" + path5;
|
|
15776
|
+
return path5;
|
|
15777
|
+
}
|
|
15778
|
+
function matchPatterns(patterns, testString, stats) {
|
|
15779
|
+
const path5 = normalizePath(testString);
|
|
15780
|
+
for (let index = 0;index < patterns.length; index++) {
|
|
15781
|
+
const pattern = patterns[index];
|
|
15782
|
+
if (pattern(path5, stats)) {
|
|
15783
|
+
return true;
|
|
15784
|
+
}
|
|
15785
|
+
}
|
|
15786
|
+
return false;
|
|
15787
|
+
}
|
|
15788
|
+
function anymatch(matchers, testString) {
|
|
15789
|
+
if (matchers == null) {
|
|
15790
|
+
throw new TypeError("anymatch: specify first argument");
|
|
15791
|
+
}
|
|
15792
|
+
const matchersArray = arrify(matchers);
|
|
15793
|
+
const patterns = matchersArray.map((matcher) => createPattern(matcher));
|
|
15794
|
+
if (testString == null) {
|
|
15795
|
+
return (testString2, stats) => {
|
|
15796
|
+
return matchPatterns(patterns, testString2, stats);
|
|
15797
|
+
};
|
|
15798
|
+
}
|
|
15799
|
+
return matchPatterns(patterns, testString);
|
|
15800
|
+
}
|
|
15801
|
+
var unifyPaths = (paths_) => {
|
|
15802
|
+
const paths = arrify(paths_).flat();
|
|
15803
|
+
if (!paths.every((p) => typeof p === STRING_TYPE)) {
|
|
15804
|
+
throw new TypeError(`Non-string provided as watch path: ${paths}`);
|
|
15805
|
+
}
|
|
15806
|
+
return paths.map(normalizePathToUnix);
|
|
15807
|
+
};
|
|
15808
|
+
var toUnix = (string) => {
|
|
15809
|
+
let str = string.replace(BACK_SLASH_RE, SLASH);
|
|
15810
|
+
let prepend = false;
|
|
15811
|
+
if (str.startsWith(SLASH_SLASH)) {
|
|
15812
|
+
prepend = true;
|
|
15813
|
+
}
|
|
15814
|
+
str = str.replace(DOUBLE_SLASH_RE, SLASH);
|
|
15815
|
+
if (prepend) {
|
|
15816
|
+
str = SLASH + str;
|
|
15817
|
+
}
|
|
15818
|
+
return str;
|
|
15819
|
+
};
|
|
15820
|
+
var normalizePathToUnix = (path5) => toUnix(sp2.normalize(toUnix(path5)));
|
|
15821
|
+
var normalizeIgnored = (cwd = "") => (path5) => {
|
|
15822
|
+
if (typeof path5 === "string") {
|
|
15823
|
+
return normalizePathToUnix(sp2.isAbsolute(path5) ? path5 : sp2.join(cwd, path5));
|
|
15824
|
+
} else {
|
|
15825
|
+
return path5;
|
|
15826
|
+
}
|
|
15827
|
+
};
|
|
15828
|
+
var getAbsolutePath = (path5, cwd) => {
|
|
15829
|
+
if (sp2.isAbsolute(path5)) {
|
|
15830
|
+
return path5;
|
|
15831
|
+
}
|
|
15832
|
+
return sp2.join(cwd, path5);
|
|
15833
|
+
};
|
|
15834
|
+
var EMPTY_SET = Object.freeze(new Set);
|
|
15835
|
+
|
|
15836
|
+
class DirEntry {
|
|
15837
|
+
path;
|
|
15838
|
+
_removeWatcher;
|
|
15839
|
+
items;
|
|
15840
|
+
constructor(dir, removeWatcher) {
|
|
15841
|
+
this.path = dir;
|
|
15842
|
+
this._removeWatcher = removeWatcher;
|
|
15843
|
+
this.items = new Set;
|
|
15844
|
+
}
|
|
15845
|
+
add(item) {
|
|
15846
|
+
const { items } = this;
|
|
15847
|
+
if (!items)
|
|
15848
|
+
return;
|
|
15849
|
+
if (item !== ONE_DOT && item !== TWO_DOTS)
|
|
15850
|
+
items.add(item);
|
|
15851
|
+
}
|
|
15852
|
+
async remove(item) {
|
|
15853
|
+
const { items } = this;
|
|
15854
|
+
if (!items)
|
|
15855
|
+
return;
|
|
15856
|
+
items.delete(item);
|
|
15857
|
+
if (items.size > 0)
|
|
15858
|
+
return;
|
|
15859
|
+
const dir = this.path;
|
|
15860
|
+
try {
|
|
15861
|
+
await readdir3(dir);
|
|
15862
|
+
} catch (err) {
|
|
15863
|
+
if (this._removeWatcher) {
|
|
15864
|
+
this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
|
|
15865
|
+
}
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15868
|
+
has(item) {
|
|
15869
|
+
const { items } = this;
|
|
15870
|
+
if (!items)
|
|
15871
|
+
return;
|
|
15872
|
+
return items.has(item);
|
|
15873
|
+
}
|
|
15874
|
+
getChildren() {
|
|
15875
|
+
const { items } = this;
|
|
15876
|
+
if (!items)
|
|
15877
|
+
return [];
|
|
15878
|
+
return [...items.values()];
|
|
15879
|
+
}
|
|
15880
|
+
dispose() {
|
|
15881
|
+
this.items.clear();
|
|
15882
|
+
this.path = "";
|
|
15883
|
+
this._removeWatcher = EMPTY_FN;
|
|
15884
|
+
this.items = EMPTY_SET;
|
|
15885
|
+
Object.freeze(this);
|
|
15886
|
+
}
|
|
15887
|
+
}
|
|
15888
|
+
var STAT_METHOD_F = "stat";
|
|
15889
|
+
var STAT_METHOD_L = "lstat";
|
|
15890
|
+
|
|
15891
|
+
class WatchHelper {
|
|
15892
|
+
fsw;
|
|
15893
|
+
path;
|
|
15894
|
+
watchPath;
|
|
15895
|
+
fullWatchPath;
|
|
15896
|
+
dirParts;
|
|
15897
|
+
followSymlinks;
|
|
15898
|
+
statMethod;
|
|
15899
|
+
constructor(path5, follow, fsw) {
|
|
15900
|
+
this.fsw = fsw;
|
|
15901
|
+
const watchPath = path5;
|
|
15902
|
+
this.path = path5 = path5.replace(REPLACER_RE, "");
|
|
15903
|
+
this.watchPath = watchPath;
|
|
15904
|
+
this.fullWatchPath = sp2.resolve(watchPath);
|
|
15905
|
+
this.dirParts = [];
|
|
15906
|
+
this.dirParts.forEach((parts) => {
|
|
15907
|
+
if (parts.length > 1)
|
|
15908
|
+
parts.pop();
|
|
15909
|
+
});
|
|
15910
|
+
this.followSymlinks = follow;
|
|
15911
|
+
this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
|
|
15912
|
+
}
|
|
15913
|
+
entryPath(entry) {
|
|
15914
|
+
return sp2.join(this.watchPath, sp2.relative(this.watchPath, entry.fullPath));
|
|
15915
|
+
}
|
|
15916
|
+
filterPath(entry) {
|
|
15917
|
+
const { stats } = entry;
|
|
15918
|
+
if (stats && stats.isSymbolicLink())
|
|
15919
|
+
return this.filterDir(entry);
|
|
15920
|
+
const resolvedPath = this.entryPath(entry);
|
|
15921
|
+
return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
|
|
15922
|
+
}
|
|
15923
|
+
filterDir(entry) {
|
|
15924
|
+
return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
|
|
15925
|
+
}
|
|
15926
|
+
}
|
|
15927
|
+
|
|
15928
|
+
class FSWatcher extends EventEmitter {
|
|
15929
|
+
closed;
|
|
15930
|
+
options;
|
|
15931
|
+
_closers;
|
|
15932
|
+
_ignoredPaths;
|
|
15933
|
+
_throttled;
|
|
15934
|
+
_streams;
|
|
15935
|
+
_symlinkPaths;
|
|
15936
|
+
_watched;
|
|
15937
|
+
_pendingWrites;
|
|
15938
|
+
_pendingUnlinks;
|
|
15939
|
+
_readyCount;
|
|
15940
|
+
_emitReady;
|
|
15941
|
+
_closePromise;
|
|
15942
|
+
_userIgnored;
|
|
15943
|
+
_readyEmitted;
|
|
15944
|
+
_emitRaw;
|
|
15945
|
+
_boundRemove;
|
|
15946
|
+
_nodeFsHandler;
|
|
15947
|
+
constructor(_opts = {}) {
|
|
15948
|
+
super();
|
|
15949
|
+
this.closed = false;
|
|
15950
|
+
this._closers = new Map;
|
|
15951
|
+
this._ignoredPaths = new Set;
|
|
15952
|
+
this._throttled = new Map;
|
|
15953
|
+
this._streams = new Set;
|
|
15954
|
+
this._symlinkPaths = new Map;
|
|
15955
|
+
this._watched = new Map;
|
|
15956
|
+
this._pendingWrites = new Map;
|
|
15957
|
+
this._pendingUnlinks = new Map;
|
|
15958
|
+
this._readyCount = 0;
|
|
15959
|
+
this._readyEmitted = false;
|
|
15960
|
+
const awf = _opts.awaitWriteFinish;
|
|
15961
|
+
const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
|
|
15962
|
+
const opts = {
|
|
15963
|
+
persistent: true,
|
|
15964
|
+
ignoreInitial: false,
|
|
15965
|
+
ignorePermissionErrors: false,
|
|
15966
|
+
interval: 100,
|
|
15967
|
+
binaryInterval: 300,
|
|
15968
|
+
followSymlinks: true,
|
|
15969
|
+
usePolling: false,
|
|
15970
|
+
atomic: true,
|
|
15971
|
+
..._opts,
|
|
15972
|
+
ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
|
|
15973
|
+
awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === "object" ? { ...DEF_AWF, ...awf } : false
|
|
15974
|
+
};
|
|
15975
|
+
if (isIBMi)
|
|
15976
|
+
opts.usePolling = true;
|
|
15977
|
+
if (opts.atomic === undefined)
|
|
15978
|
+
opts.atomic = !opts.usePolling;
|
|
15979
|
+
const envPoll = process.env.CHOKIDAR_USEPOLLING;
|
|
15980
|
+
if (envPoll !== undefined) {
|
|
15981
|
+
const envLower = envPoll.toLowerCase();
|
|
15982
|
+
if (envLower === "false" || envLower === "0")
|
|
15983
|
+
opts.usePolling = false;
|
|
15984
|
+
else if (envLower === "true" || envLower === "1")
|
|
15985
|
+
opts.usePolling = true;
|
|
15986
|
+
else
|
|
15987
|
+
opts.usePolling = !!envLower;
|
|
15988
|
+
}
|
|
15989
|
+
const envInterval = process.env.CHOKIDAR_INTERVAL;
|
|
15990
|
+
if (envInterval)
|
|
15991
|
+
opts.interval = Number.parseInt(envInterval, 10);
|
|
15992
|
+
let readyCalls = 0;
|
|
15993
|
+
this._emitReady = () => {
|
|
15994
|
+
readyCalls++;
|
|
15995
|
+
if (readyCalls >= this._readyCount) {
|
|
15996
|
+
this._emitReady = EMPTY_FN;
|
|
15997
|
+
this._readyEmitted = true;
|
|
15998
|
+
process.nextTick(() => this.emit(EVENTS.READY));
|
|
15999
|
+
}
|
|
16000
|
+
};
|
|
16001
|
+
this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args);
|
|
16002
|
+
this._boundRemove = this._remove.bind(this);
|
|
16003
|
+
this.options = opts;
|
|
16004
|
+
this._nodeFsHandler = new NodeFsHandler(this);
|
|
16005
|
+
Object.freeze(opts);
|
|
16006
|
+
}
|
|
16007
|
+
_addIgnoredPath(matcher) {
|
|
16008
|
+
if (isMatcherObject(matcher)) {
|
|
16009
|
+
for (const ignored of this._ignoredPaths) {
|
|
16010
|
+
if (isMatcherObject(ignored) && ignored.path === matcher.path && ignored.recursive === matcher.recursive) {
|
|
16011
|
+
return;
|
|
16012
|
+
}
|
|
16013
|
+
}
|
|
16014
|
+
}
|
|
16015
|
+
this._ignoredPaths.add(matcher);
|
|
16016
|
+
}
|
|
16017
|
+
_removeIgnoredPath(matcher) {
|
|
16018
|
+
this._ignoredPaths.delete(matcher);
|
|
16019
|
+
if (typeof matcher === "string") {
|
|
16020
|
+
for (const ignored of this._ignoredPaths) {
|
|
16021
|
+
if (isMatcherObject(ignored) && ignored.path === matcher) {
|
|
16022
|
+
this._ignoredPaths.delete(ignored);
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
16025
|
+
}
|
|
16026
|
+
}
|
|
16027
|
+
add(paths_, _origAdd, _internal) {
|
|
16028
|
+
const { cwd } = this.options;
|
|
16029
|
+
this.closed = false;
|
|
16030
|
+
this._closePromise = undefined;
|
|
16031
|
+
let paths = unifyPaths(paths_);
|
|
16032
|
+
if (cwd) {
|
|
16033
|
+
paths = paths.map((path5) => {
|
|
16034
|
+
const absPath = getAbsolutePath(path5, cwd);
|
|
16035
|
+
return absPath;
|
|
16036
|
+
});
|
|
16037
|
+
}
|
|
16038
|
+
paths.forEach((path5) => {
|
|
16039
|
+
this._removeIgnoredPath(path5);
|
|
16040
|
+
});
|
|
16041
|
+
this._userIgnored = undefined;
|
|
16042
|
+
if (!this._readyCount)
|
|
16043
|
+
this._readyCount = 0;
|
|
16044
|
+
this._readyCount += paths.length;
|
|
16045
|
+
Promise.all(paths.map(async (path5) => {
|
|
16046
|
+
const res = await this._nodeFsHandler._addToNodeFs(path5, !_internal, undefined, 0, _origAdd);
|
|
16047
|
+
if (res)
|
|
16048
|
+
this._emitReady();
|
|
16049
|
+
return res;
|
|
16050
|
+
})).then((results) => {
|
|
16051
|
+
if (this.closed)
|
|
16052
|
+
return;
|
|
16053
|
+
results.forEach((item) => {
|
|
16054
|
+
if (item)
|
|
16055
|
+
this.add(sp2.dirname(item), sp2.basename(_origAdd || item));
|
|
16056
|
+
});
|
|
16057
|
+
});
|
|
16058
|
+
return this;
|
|
16059
|
+
}
|
|
16060
|
+
unwatch(paths_) {
|
|
16061
|
+
if (this.closed)
|
|
16062
|
+
return this;
|
|
16063
|
+
const paths = unifyPaths(paths_);
|
|
16064
|
+
const { cwd } = this.options;
|
|
16065
|
+
paths.forEach((path5) => {
|
|
16066
|
+
if (!sp2.isAbsolute(path5) && !this._closers.has(path5)) {
|
|
16067
|
+
if (cwd)
|
|
16068
|
+
path5 = sp2.join(cwd, path5);
|
|
16069
|
+
path5 = sp2.resolve(path5);
|
|
16070
|
+
}
|
|
16071
|
+
this._closePath(path5);
|
|
16072
|
+
this._addIgnoredPath(path5);
|
|
16073
|
+
if (this._watched.has(path5)) {
|
|
16074
|
+
this._addIgnoredPath({
|
|
16075
|
+
path: path5,
|
|
16076
|
+
recursive: true
|
|
16077
|
+
});
|
|
16078
|
+
}
|
|
16079
|
+
this._userIgnored = undefined;
|
|
16080
|
+
});
|
|
16081
|
+
return this;
|
|
16082
|
+
}
|
|
16083
|
+
close() {
|
|
16084
|
+
if (this._closePromise) {
|
|
16085
|
+
return this._closePromise;
|
|
16086
|
+
}
|
|
16087
|
+
this.closed = true;
|
|
16088
|
+
this.removeAllListeners();
|
|
16089
|
+
const closers = [];
|
|
16090
|
+
this._closers.forEach((closerList) => closerList.forEach((closer) => {
|
|
16091
|
+
const promise = closer();
|
|
16092
|
+
if (promise instanceof Promise)
|
|
16093
|
+
closers.push(promise);
|
|
16094
|
+
}));
|
|
16095
|
+
this._streams.forEach((stream) => stream.destroy());
|
|
16096
|
+
this._userIgnored = undefined;
|
|
16097
|
+
this._readyCount = 0;
|
|
16098
|
+
this._readyEmitted = false;
|
|
16099
|
+
this._watched.forEach((dirent) => dirent.dispose());
|
|
16100
|
+
this._closers.clear();
|
|
16101
|
+
this._watched.clear();
|
|
16102
|
+
this._streams.clear();
|
|
16103
|
+
this._symlinkPaths.clear();
|
|
16104
|
+
this._throttled.clear();
|
|
16105
|
+
this._closePromise = closers.length ? Promise.all(closers).then(() => {
|
|
16106
|
+
return;
|
|
16107
|
+
}) : Promise.resolve();
|
|
16108
|
+
return this._closePromise;
|
|
16109
|
+
}
|
|
16110
|
+
getWatched() {
|
|
16111
|
+
const watchList = {};
|
|
16112
|
+
this._watched.forEach((entry, dir) => {
|
|
16113
|
+
const key = this.options.cwd ? sp2.relative(this.options.cwd, dir) : dir;
|
|
16114
|
+
const index = key || ONE_DOT;
|
|
16115
|
+
watchList[index] = entry.getChildren().sort();
|
|
16116
|
+
});
|
|
16117
|
+
return watchList;
|
|
16118
|
+
}
|
|
16119
|
+
emitWithAll(event, args) {
|
|
16120
|
+
this.emit(event, ...args);
|
|
16121
|
+
if (event !== EVENTS.ERROR)
|
|
16122
|
+
this.emit(EVENTS.ALL, event, ...args);
|
|
16123
|
+
}
|
|
16124
|
+
async _emit(event, path5, stats) {
|
|
16125
|
+
if (this.closed)
|
|
16126
|
+
return;
|
|
16127
|
+
const opts = this.options;
|
|
16128
|
+
if (isWindows)
|
|
16129
|
+
path5 = sp2.normalize(path5);
|
|
16130
|
+
if (opts.cwd)
|
|
16131
|
+
path5 = sp2.relative(opts.cwd, path5);
|
|
16132
|
+
const args = [path5];
|
|
16133
|
+
if (stats != null)
|
|
16134
|
+
args.push(stats);
|
|
16135
|
+
const awf = opts.awaitWriteFinish;
|
|
16136
|
+
let pw;
|
|
16137
|
+
if (awf && (pw = this._pendingWrites.get(path5))) {
|
|
16138
|
+
pw.lastChange = new Date;
|
|
16139
|
+
return this;
|
|
16140
|
+
}
|
|
16141
|
+
if (opts.atomic) {
|
|
16142
|
+
if (event === EVENTS.UNLINK) {
|
|
16143
|
+
this._pendingUnlinks.set(path5, [event, ...args]);
|
|
16144
|
+
setTimeout(() => {
|
|
16145
|
+
this._pendingUnlinks.forEach((entry, path6) => {
|
|
16146
|
+
this.emit(...entry);
|
|
16147
|
+
this.emit(EVENTS.ALL, ...entry);
|
|
16148
|
+
this._pendingUnlinks.delete(path6);
|
|
16149
|
+
});
|
|
16150
|
+
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16151
|
+
return this;
|
|
16152
|
+
}
|
|
16153
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path5)) {
|
|
16154
|
+
event = EVENTS.CHANGE;
|
|
16155
|
+
this._pendingUnlinks.delete(path5);
|
|
16156
|
+
}
|
|
16157
|
+
}
|
|
16158
|
+
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
16159
|
+
const awfEmit = (err, stats2) => {
|
|
16160
|
+
if (err) {
|
|
16161
|
+
event = EVENTS.ERROR;
|
|
16162
|
+
args[0] = err;
|
|
16163
|
+
this.emitWithAll(event, args);
|
|
16164
|
+
} else if (stats2) {
|
|
16165
|
+
if (args.length > 1) {
|
|
16166
|
+
args[1] = stats2;
|
|
16167
|
+
} else {
|
|
16168
|
+
args.push(stats2);
|
|
16169
|
+
}
|
|
16170
|
+
this.emitWithAll(event, args);
|
|
16171
|
+
}
|
|
16172
|
+
};
|
|
16173
|
+
this._awaitWriteFinish(path5, awf.stabilityThreshold, event, awfEmit);
|
|
16174
|
+
return this;
|
|
16175
|
+
}
|
|
16176
|
+
if (event === EVENTS.CHANGE) {
|
|
16177
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path5, 50);
|
|
16178
|
+
if (isThrottled)
|
|
16179
|
+
return this;
|
|
16180
|
+
}
|
|
16181
|
+
if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16182
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path5) : path5;
|
|
16183
|
+
let stats2;
|
|
16184
|
+
try {
|
|
16185
|
+
stats2 = await stat4(fullPath);
|
|
16186
|
+
} catch (err) {}
|
|
16187
|
+
if (!stats2 || this.closed)
|
|
16188
|
+
return;
|
|
16189
|
+
args.push(stats2);
|
|
16190
|
+
}
|
|
16191
|
+
this.emitWithAll(event, args);
|
|
16192
|
+
return this;
|
|
16193
|
+
}
|
|
16194
|
+
_handleError(error) {
|
|
16195
|
+
const code = error && error.code;
|
|
16196
|
+
if (error && code !== "ENOENT" && code !== "ENOTDIR" && (!this.options.ignorePermissionErrors || code !== "EPERM" && code !== "EACCES")) {
|
|
16197
|
+
this.emit(EVENTS.ERROR, error);
|
|
16198
|
+
}
|
|
16199
|
+
return error || this.closed;
|
|
16200
|
+
}
|
|
16201
|
+
_throttle(actionType, path5, timeout) {
|
|
16202
|
+
if (!this._throttled.has(actionType)) {
|
|
16203
|
+
this._throttled.set(actionType, new Map);
|
|
16204
|
+
}
|
|
16205
|
+
const action = this._throttled.get(actionType);
|
|
16206
|
+
if (!action)
|
|
16207
|
+
throw new Error("invalid throttle");
|
|
16208
|
+
const actionPath = action.get(path5);
|
|
16209
|
+
if (actionPath) {
|
|
16210
|
+
actionPath.count++;
|
|
16211
|
+
return false;
|
|
16212
|
+
}
|
|
16213
|
+
let timeoutObject;
|
|
16214
|
+
const clear = () => {
|
|
16215
|
+
const item = action.get(path5);
|
|
16216
|
+
const count = item ? item.count : 0;
|
|
16217
|
+
action.delete(path5);
|
|
16218
|
+
clearTimeout(timeoutObject);
|
|
16219
|
+
if (item)
|
|
16220
|
+
clearTimeout(item.timeoutObject);
|
|
16221
|
+
return count;
|
|
16222
|
+
};
|
|
16223
|
+
timeoutObject = setTimeout(clear, timeout);
|
|
16224
|
+
const thr = { timeoutObject, clear, count: 0 };
|
|
16225
|
+
action.set(path5, thr);
|
|
16226
|
+
return thr;
|
|
16227
|
+
}
|
|
16228
|
+
_incrReadyCount() {
|
|
16229
|
+
return this._readyCount++;
|
|
16230
|
+
}
|
|
16231
|
+
_awaitWriteFinish(path5, threshold, event, awfEmit) {
|
|
16232
|
+
const awf = this.options.awaitWriteFinish;
|
|
16233
|
+
if (typeof awf !== "object")
|
|
16234
|
+
return;
|
|
16235
|
+
const pollInterval = awf.pollInterval;
|
|
16236
|
+
let timeoutHandler;
|
|
16237
|
+
let fullPath = path5;
|
|
16238
|
+
if (this.options.cwd && !sp2.isAbsolute(path5)) {
|
|
16239
|
+
fullPath = sp2.join(this.options.cwd, path5);
|
|
16240
|
+
}
|
|
16241
|
+
const now = new Date;
|
|
16242
|
+
const writes = this._pendingWrites;
|
|
16243
|
+
function awaitWriteFinishFn(prevStat) {
|
|
16244
|
+
statcb(fullPath, (err, curStat) => {
|
|
16245
|
+
if (err || !writes.has(path5)) {
|
|
16246
|
+
if (err && err.code !== "ENOENT")
|
|
16247
|
+
awfEmit(err);
|
|
16248
|
+
return;
|
|
16249
|
+
}
|
|
16250
|
+
const now2 = Number(new Date);
|
|
16251
|
+
if (prevStat && curStat.size !== prevStat.size) {
|
|
16252
|
+
writes.get(path5).lastChange = now2;
|
|
16253
|
+
}
|
|
16254
|
+
const pw = writes.get(path5);
|
|
16255
|
+
const df = now2 - pw.lastChange;
|
|
16256
|
+
if (df >= threshold) {
|
|
16257
|
+
writes.delete(path5);
|
|
16258
|
+
awfEmit(undefined, curStat);
|
|
16259
|
+
} else {
|
|
16260
|
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16261
|
+
}
|
|
16262
|
+
});
|
|
16263
|
+
}
|
|
16264
|
+
if (!writes.has(path5)) {
|
|
16265
|
+
writes.set(path5, {
|
|
16266
|
+
lastChange: now,
|
|
16267
|
+
cancelWait: () => {
|
|
16268
|
+
writes.delete(path5);
|
|
16269
|
+
clearTimeout(timeoutHandler);
|
|
16270
|
+
return event;
|
|
16271
|
+
}
|
|
16272
|
+
});
|
|
16273
|
+
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16276
|
+
_isIgnored(path5, stats) {
|
|
16277
|
+
if (this.options.atomic && DOT_RE.test(path5))
|
|
16278
|
+
return true;
|
|
16279
|
+
if (!this._userIgnored) {
|
|
16280
|
+
const { cwd } = this.options;
|
|
16281
|
+
const ign = this.options.ignored;
|
|
16282
|
+
const ignored = (ign || []).map(normalizeIgnored(cwd));
|
|
16283
|
+
const ignoredPaths = [...this._ignoredPaths];
|
|
16284
|
+
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16285
|
+
this._userIgnored = anymatch(list, undefined);
|
|
16286
|
+
}
|
|
16287
|
+
return this._userIgnored(path5, stats);
|
|
16288
|
+
}
|
|
16289
|
+
_isntIgnored(path5, stat5) {
|
|
16290
|
+
return !this._isIgnored(path5, stat5);
|
|
16291
|
+
}
|
|
16292
|
+
_getWatchHelpers(path5) {
|
|
16293
|
+
return new WatchHelper(path5, this.options.followSymlinks, this);
|
|
16294
|
+
}
|
|
16295
|
+
_getWatchedDir(directory) {
|
|
16296
|
+
const dir = sp2.resolve(directory);
|
|
16297
|
+
if (!this._watched.has(dir))
|
|
16298
|
+
this._watched.set(dir, new DirEntry(dir, this._boundRemove));
|
|
16299
|
+
return this._watched.get(dir);
|
|
16300
|
+
}
|
|
16301
|
+
_hasReadPermissions(stats) {
|
|
16302
|
+
if (this.options.ignorePermissionErrors)
|
|
16303
|
+
return true;
|
|
16304
|
+
return Boolean(Number(stats.mode) & 256);
|
|
16305
|
+
}
|
|
16306
|
+
_remove(directory, item, isDirectory) {
|
|
16307
|
+
const path5 = sp2.join(directory, item);
|
|
16308
|
+
const fullPath = sp2.resolve(path5);
|
|
16309
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path5) || this._watched.has(fullPath);
|
|
16310
|
+
if (!this._throttle("remove", path5, 100))
|
|
16311
|
+
return;
|
|
16312
|
+
if (!isDirectory && this._watched.size === 1) {
|
|
16313
|
+
this.add(directory, item, true);
|
|
16314
|
+
}
|
|
16315
|
+
const wp = this._getWatchedDir(path5);
|
|
16316
|
+
const nestedDirectoryChildren = wp.getChildren();
|
|
16317
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path5, nested));
|
|
16318
|
+
const parent = this._getWatchedDir(directory);
|
|
16319
|
+
const wasTracked = parent.has(item);
|
|
16320
|
+
parent.remove(item);
|
|
16321
|
+
if (this._symlinkPaths.has(fullPath)) {
|
|
16322
|
+
this._symlinkPaths.delete(fullPath);
|
|
16323
|
+
}
|
|
16324
|
+
let relPath = path5;
|
|
16325
|
+
if (this.options.cwd)
|
|
16326
|
+
relPath = sp2.relative(this.options.cwd, path5);
|
|
16327
|
+
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
16328
|
+
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
16329
|
+
if (event === EVENTS.ADD)
|
|
16330
|
+
return;
|
|
16331
|
+
}
|
|
16332
|
+
this._watched.delete(path5);
|
|
16333
|
+
this._watched.delete(fullPath);
|
|
16334
|
+
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
16335
|
+
if (wasTracked && !this._isIgnored(path5))
|
|
16336
|
+
this._emit(eventName, path5);
|
|
16337
|
+
this._closePath(path5);
|
|
16338
|
+
}
|
|
16339
|
+
_closePath(path5) {
|
|
16340
|
+
this._closeFile(path5);
|
|
16341
|
+
const dir = sp2.dirname(path5);
|
|
16342
|
+
this._getWatchedDir(dir).remove(sp2.basename(path5));
|
|
16343
|
+
}
|
|
16344
|
+
_closeFile(path5) {
|
|
16345
|
+
const closers = this._closers.get(path5);
|
|
16346
|
+
if (!closers)
|
|
16347
|
+
return;
|
|
16348
|
+
closers.forEach((closer) => closer());
|
|
16349
|
+
this._closers.delete(path5);
|
|
16350
|
+
}
|
|
16351
|
+
_addPathCloser(path5, closer) {
|
|
16352
|
+
if (!closer)
|
|
16353
|
+
return;
|
|
16354
|
+
let list = this._closers.get(path5);
|
|
16355
|
+
if (!list) {
|
|
16356
|
+
list = [];
|
|
16357
|
+
this._closers.set(path5, list);
|
|
16358
|
+
}
|
|
16359
|
+
list.push(closer);
|
|
16360
|
+
}
|
|
16361
|
+
_readdirp(root, opts) {
|
|
16362
|
+
if (this.closed)
|
|
16363
|
+
return;
|
|
16364
|
+
const options2 = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
|
|
16365
|
+
let stream = readdirp(root, options2);
|
|
16366
|
+
this._streams.add(stream);
|
|
16367
|
+
stream.once(STR_CLOSE, () => {
|
|
16368
|
+
stream = undefined;
|
|
16369
|
+
});
|
|
16370
|
+
stream.once(STR_END, () => {
|
|
16371
|
+
if (stream) {
|
|
16372
|
+
this._streams.delete(stream);
|
|
16373
|
+
stream = undefined;
|
|
16374
|
+
}
|
|
16375
|
+
});
|
|
16376
|
+
return stream;
|
|
16377
|
+
}
|
|
16378
|
+
}
|
|
16379
|
+
function watch(paths, options2 = {}) {
|
|
16380
|
+
const watcher = new FSWatcher(options2);
|
|
16381
|
+
watcher.add(paths);
|
|
16382
|
+
return watcher;
|
|
16383
|
+
}
|
|
16384
|
+
var chokidar_default = { watch, FSWatcher };
|
|
16385
|
+
|
|
16386
|
+
// src/utils/file-sync.ts
|
|
16387
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
16388
|
+
var OS_JUNK = [/\.DS_Store$/, /Thumbs\.db$/];
|
|
16389
|
+
function loadGitignore(projectDir) {
|
|
16390
|
+
const ig = import_ignore.default();
|
|
16391
|
+
const gitignorePath = join6(projectDir, ".gitignore");
|
|
16392
|
+
try {
|
|
16393
|
+
if (existsSync2(gitignorePath)) {
|
|
16394
|
+
ig.add(readFileSync(gitignorePath, "utf8"));
|
|
16395
|
+
}
|
|
16396
|
+
} catch (err) {
|
|
16397
|
+
const code = err.code;
|
|
16398
|
+
if (code !== "ENOENT") {
|
|
16399
|
+
console.warn(`Warning: Could not read .gitignore: ${err.message}`);
|
|
16400
|
+
}
|
|
16401
|
+
}
|
|
16402
|
+
return ig;
|
|
16403
|
+
}
|
|
16404
|
+
function normalizePath2(p) {
|
|
16405
|
+
return p.replace(/\\/g, "/").replace(/\/$/, "");
|
|
16406
|
+
}
|
|
16407
|
+
function isSymlink(filePath) {
|
|
16408
|
+
try {
|
|
16409
|
+
return lstatSync(filePath).isSymbolicLink();
|
|
16410
|
+
} catch (err) {
|
|
16411
|
+
if (err.code === "ENOENT")
|
|
16412
|
+
return false;
|
|
16413
|
+
throw err;
|
|
16414
|
+
}
|
|
16415
|
+
}
|
|
16416
|
+
function isExcluded(relativePath, gitignore) {
|
|
16417
|
+
if (!relativePath)
|
|
16418
|
+
return false;
|
|
16419
|
+
if (OS_JUNK.some((p) => p.test(relativePath)))
|
|
16420
|
+
return true;
|
|
16421
|
+
if (gitignore.ignores(relativePath))
|
|
16422
|
+
return true;
|
|
16423
|
+
return false;
|
|
16424
|
+
}
|
|
16425
|
+
async function syncFile(src, dest) {
|
|
16426
|
+
mkdirSync(dirname5(dest), { recursive: true });
|
|
16427
|
+
await Bun.write(dest, Bun.file(src));
|
|
16428
|
+
}
|
|
16429
|
+
function syncDelete(dest) {
|
|
16430
|
+
try {
|
|
16431
|
+
unlinkSync(dest);
|
|
16432
|
+
} catch (err) {
|
|
16433
|
+
if (err.code !== "ENOENT")
|
|
16434
|
+
throw err;
|
|
16435
|
+
}
|
|
16436
|
+
}
|
|
16437
|
+
function createFileSync(tempDir, projectDir, options2) {
|
|
16438
|
+
const failures = [];
|
|
16439
|
+
const syncedFiles = new Set;
|
|
16440
|
+
const gitignore = loadGitignore(projectDir);
|
|
16441
|
+
const isCI2 = process.env.CI === "true";
|
|
16442
|
+
const watcher = chokidar_default.watch(tempDir, {
|
|
16443
|
+
followSymlinks: false,
|
|
16444
|
+
ignoreInitial: true,
|
|
16445
|
+
usePolling: isCI2,
|
|
16446
|
+
interval: 100,
|
|
16447
|
+
awaitWriteFinish: {
|
|
16448
|
+
stabilityThreshold: 200,
|
|
16449
|
+
pollInterval: 50
|
|
16450
|
+
},
|
|
16451
|
+
ignored: (filePath) => isExcluded(relative4(tempDir, filePath), gitignore)
|
|
16452
|
+
});
|
|
16453
|
+
watcher.on("error", (err) => {
|
|
16454
|
+
failures.push({ path: "<watcher>", error: err });
|
|
16455
|
+
});
|
|
16456
|
+
const handleAdd = async (filePath) => {
|
|
16457
|
+
if (isSymlink(filePath))
|
|
16458
|
+
return;
|
|
16459
|
+
const relativePath = relative4(tempDir, filePath);
|
|
16460
|
+
const normalizedPath = normalizePath2(relativePath);
|
|
16461
|
+
if (options2?.overlayFiles?.has(normalizedPath))
|
|
16462
|
+
return;
|
|
16463
|
+
const destPath = join6(projectDir, relativePath);
|
|
16464
|
+
try {
|
|
16465
|
+
await syncFile(filePath, destPath);
|
|
16466
|
+
syncedFiles.add(normalizedPath);
|
|
16467
|
+
} catch (err) {
|
|
16468
|
+
failures.push({ path: relativePath, error: err });
|
|
16469
|
+
}
|
|
16470
|
+
};
|
|
16471
|
+
const handleChange = async (filePath) => {
|
|
16472
|
+
if (isSymlink(filePath))
|
|
16473
|
+
return;
|
|
16474
|
+
const relativePath = relative4(tempDir, filePath);
|
|
16475
|
+
const normalizedPath = normalizePath2(relativePath);
|
|
16476
|
+
if (options2?.overlayFiles?.has(normalizedPath))
|
|
16477
|
+
return;
|
|
16478
|
+
const destPath = join6(projectDir, relativePath);
|
|
16479
|
+
try {
|
|
16480
|
+
await syncFile(filePath, destPath);
|
|
16481
|
+
} catch (err) {
|
|
16482
|
+
failures.push({ path: relativePath, error: err });
|
|
16483
|
+
}
|
|
16484
|
+
};
|
|
16485
|
+
const handleUnlink = async (filePath) => {
|
|
16486
|
+
const relativePath = relative4(tempDir, filePath);
|
|
16487
|
+
const normalizedPath = normalizePath2(relativePath);
|
|
16488
|
+
if (!syncedFiles.has(normalizedPath))
|
|
16489
|
+
return;
|
|
16490
|
+
const destPath = join6(projectDir, relativePath);
|
|
16491
|
+
try {
|
|
16492
|
+
syncDelete(destPath);
|
|
16493
|
+
syncedFiles.delete(normalizedPath);
|
|
16494
|
+
} catch (err) {
|
|
16495
|
+
failures.push({ path: relativePath, error: err });
|
|
16496
|
+
}
|
|
16497
|
+
};
|
|
16498
|
+
const handleAddDir = (dirPath) => {
|
|
16499
|
+
if (isSymlink(dirPath))
|
|
16500
|
+
return;
|
|
16501
|
+
const relativePath = relative4(tempDir, dirPath);
|
|
16502
|
+
try {
|
|
16503
|
+
mkdirSync(join6(projectDir, relativePath), { recursive: true });
|
|
16504
|
+
} catch (err) {
|
|
16505
|
+
if (err.code !== "EEXIST") {
|
|
16506
|
+
failures.push({ path: relativePath, error: err });
|
|
16507
|
+
}
|
|
16508
|
+
}
|
|
16509
|
+
};
|
|
16510
|
+
const handleUnlinkDir = (dirPath) => {
|
|
16511
|
+
const relativePath = relative4(tempDir, dirPath);
|
|
16512
|
+
const destPath = join6(projectDir, relativePath);
|
|
16513
|
+
try {
|
|
16514
|
+
rmdirSync(destPath);
|
|
16515
|
+
} catch (err) {
|
|
16516
|
+
const code = err.code;
|
|
16517
|
+
if (code !== "ENOENT" && code !== "ENOTEMPTY") {
|
|
16518
|
+
failures.push({ path: relativePath, error: err });
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
};
|
|
16522
|
+
watcher.on("add", handleAdd);
|
|
16523
|
+
watcher.on("change", handleChange);
|
|
16524
|
+
watcher.on("unlink", handleUnlink);
|
|
16525
|
+
watcher.on("addDir", handleAddDir);
|
|
16526
|
+
watcher.on("unlinkDir", handleUnlinkDir);
|
|
16527
|
+
return {
|
|
16528
|
+
close: async () => {
|
|
16529
|
+
await watcher.close();
|
|
16530
|
+
},
|
|
16531
|
+
getFailures: () => [...failures],
|
|
16532
|
+
getSyncCount: () => syncedFiles.size
|
|
16533
|
+
};
|
|
16534
|
+
}
|
|
16535
|
+
|
|
16536
|
+
// src/utils/symlink-farm.ts
|
|
16537
|
+
import { randomBytes } from "crypto";
|
|
16538
|
+
import { mkdir as mkdir4, readdir as readdir4, rename as rename2, rm as rm2, stat as stat5, symlink as symlink2 } from "fs/promises";
|
|
16539
|
+
import { tmpdir } from "os";
|
|
16540
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join7, relative as relative5 } from "path";
|
|
16541
|
+
|
|
16542
|
+
// src/utils/pattern-filter.ts
|
|
16543
|
+
import path5 from "path";
|
|
16544
|
+
var {Glob: Glob2 } = globalThis.Bun;
|
|
16545
|
+
function normalizeForMatching(absolutePath, projectRoot) {
|
|
16546
|
+
const relativePath = path5.relative(projectRoot, absolutePath);
|
|
16547
|
+
return relativePath.split(path5.sep).join("/").replace(/^\.\//, "");
|
|
16548
|
+
}
|
|
16549
|
+
class PathMatcher {
|
|
16550
|
+
includeGlobs;
|
|
16551
|
+
excludeGlobs;
|
|
16552
|
+
includePatterns;
|
|
16553
|
+
excludePatterns;
|
|
16554
|
+
constructor(includePatterns = [], excludePatterns = []) {
|
|
16555
|
+
this.includePatterns = includePatterns;
|
|
16556
|
+
this.excludePatterns = excludePatterns;
|
|
16557
|
+
this.includeGlobs = includePatterns.map((p) => ({ pattern: p, glob: new Glob2(p) }));
|
|
16558
|
+
this.excludeGlobs = excludePatterns.map((p) => ({ pattern: p, glob: new Glob2(p) }));
|
|
16559
|
+
}
|
|
16560
|
+
getDisposition(relativePath) {
|
|
16561
|
+
const matchesExclude = this.excludeGlobs.some((g) => g.glob.match(relativePath));
|
|
16562
|
+
const matchesInclude = this.includeGlobs.some((g) => g.glob.match(relativePath));
|
|
16563
|
+
if (this.includePatterns.length > 0 && this.excludePatterns.length > 0) {
|
|
16564
|
+
if (matchesInclude) {
|
|
16565
|
+
return { type: "included" };
|
|
16566
|
+
}
|
|
16567
|
+
if (matchesExclude) {
|
|
16568
|
+
return { type: "excluded" };
|
|
16569
|
+
}
|
|
16570
|
+
const hasIncludesInside = this.includePatterns.some((pattern) => {
|
|
16571
|
+
if (pattern.startsWith(`${relativePath}/`))
|
|
16572
|
+
return true;
|
|
16573
|
+
if (pattern.startsWith("**/"))
|
|
16574
|
+
return true;
|
|
16575
|
+
return false;
|
|
16576
|
+
});
|
|
16577
|
+
const hasExcludesInside2 = this.excludePatterns.some((pattern) => {
|
|
16578
|
+
if (pattern.startsWith(`${relativePath}/`))
|
|
16579
|
+
return true;
|
|
16580
|
+
if (pattern.startsWith("**/"))
|
|
16581
|
+
return true;
|
|
16582
|
+
return false;
|
|
16583
|
+
});
|
|
16584
|
+
if (hasIncludesInside || hasExcludesInside2) {
|
|
16585
|
+
return { type: "partial", patterns: this.includePatterns };
|
|
16586
|
+
}
|
|
16587
|
+
return { type: "included" };
|
|
16588
|
+
}
|
|
16589
|
+
if (this.includePatterns.length > 0) {
|
|
16590
|
+
if (matchesInclude) {
|
|
16591
|
+
return { type: "included" };
|
|
16592
|
+
}
|
|
16593
|
+
const hasIncludesInside = this.includePatterns.some((pattern) => {
|
|
16594
|
+
if (pattern.startsWith(`${relativePath}/`))
|
|
16595
|
+
return true;
|
|
16596
|
+
if (pattern.startsWith("**/"))
|
|
16597
|
+
return true;
|
|
16598
|
+
return false;
|
|
16599
|
+
});
|
|
16600
|
+
if (hasIncludesInside) {
|
|
16601
|
+
return { type: "partial", patterns: this.includePatterns };
|
|
16602
|
+
}
|
|
16603
|
+
return { type: "excluded" };
|
|
16604
|
+
}
|
|
16605
|
+
if (matchesExclude) {
|
|
16606
|
+
return { type: "excluded" };
|
|
16607
|
+
}
|
|
16608
|
+
const hasExcludesInside = this.excludePatterns.some((pattern) => {
|
|
16609
|
+
if (pattern.startsWith(`${relativePath}/`))
|
|
16610
|
+
return true;
|
|
16611
|
+
if (pattern.startsWith("**/"))
|
|
16612
|
+
return true;
|
|
16613
|
+
return false;
|
|
16614
|
+
});
|
|
16615
|
+
if (hasExcludesInside) {
|
|
16616
|
+
return { type: "partial", patterns: [] };
|
|
16617
|
+
}
|
|
16618
|
+
return { type: "included" };
|
|
16619
|
+
}
|
|
16620
|
+
targetsInside(dirPath) {
|
|
16621
|
+
const normalizedDir = dirPath.endsWith("/") ? dirPath : `${dirPath}/`;
|
|
16622
|
+
return this.includePatterns.some((p) => p.startsWith(normalizedDir));
|
|
16623
|
+
}
|
|
16624
|
+
getInnerPatterns(dirPath) {
|
|
16625
|
+
const normalizedDir = dirPath.endsWith("/") ? dirPath : `${dirPath}/`;
|
|
16626
|
+
return this.includePatterns.filter((p) => p.startsWith(normalizedDir));
|
|
16627
|
+
}
|
|
16628
|
+
hasIncludePatterns() {
|
|
16629
|
+
return this.includePatterns.length > 0;
|
|
16630
|
+
}
|
|
16631
|
+
}
|
|
16632
|
+
function createPathMatcher(includePatterns = [], excludePatterns = []) {
|
|
16633
|
+
return new PathMatcher(includePatterns, excludePatterns);
|
|
16634
|
+
}
|
|
16635
|
+
|
|
16636
|
+
// src/utils/symlink-farm.ts
|
|
16637
|
+
var STALE_SESSION_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
16638
|
+
var REMOVING_THRESHOLD_MS = 60 * 60 * 1000;
|
|
16639
|
+
var GHOST_DIR_PREFIX = "ocx-ghost-";
|
|
16640
|
+
var REMOVING_SUFFIX = "-removing";
|
|
16641
|
+
var GHOST_MARKER_FILE = ".ocx-ghost-marker";
|
|
16642
|
+
async function createSymlinkFarm(sourceDir, options2) {
|
|
16643
|
+
if (!isAbsolute2(sourceDir)) {
|
|
16644
|
+
throw new Error(`sourceDir must be an absolute path, got: ${sourceDir}`);
|
|
16645
|
+
}
|
|
16646
|
+
const suffix = randomBytes(4).toString("hex");
|
|
16647
|
+
const tempDir = join7(tmpdir(), `${GHOST_DIR_PREFIX}${suffix}`);
|
|
16648
|
+
await Bun.write(join7(tempDir, GHOST_MARKER_FILE), "");
|
|
16649
|
+
try {
|
|
16650
|
+
const matcher = createPathMatcher(options2?.includePatterns ?? [], options2?.excludePatterns ?? []);
|
|
16651
|
+
const plan = await computeSymlinkPlan(sourceDir, sourceDir, matcher);
|
|
16652
|
+
await executeSymlinkPlan(plan, sourceDir, tempDir);
|
|
16653
|
+
return tempDir;
|
|
16654
|
+
} catch (error) {
|
|
16655
|
+
await rm2(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
16656
|
+
throw error;
|
|
14667
16657
|
}
|
|
14668
16658
|
}
|
|
14669
16659
|
async function cleanupSymlinkFarm(tempDir) {
|
|
14670
16660
|
const removingPath = `${tempDir}${REMOVING_SUFFIX}`;
|
|
14671
16661
|
try {
|
|
14672
|
-
await
|
|
16662
|
+
await rename2(tempDir, removingPath);
|
|
14673
16663
|
} catch {
|
|
14674
16664
|
return;
|
|
14675
16665
|
}
|
|
@@ -14677,24 +16667,24 @@ async function cleanupSymlinkFarm(tempDir) {
|
|
|
14677
16667
|
}
|
|
14678
16668
|
async function cleanupOrphanedGhostDirs(tempBase = tmpdir()) {
|
|
14679
16669
|
let cleanedCount = 0;
|
|
14680
|
-
if (!
|
|
16670
|
+
if (!isAbsolute2(tempBase)) {
|
|
14681
16671
|
throw new Error(`tempBase must be an absolute path, got: ${tempBase}`);
|
|
14682
16672
|
}
|
|
14683
16673
|
let dirNames;
|
|
14684
16674
|
try {
|
|
14685
|
-
dirNames = await
|
|
16675
|
+
dirNames = await readdir4(tempBase);
|
|
14686
16676
|
} catch {
|
|
14687
16677
|
return 0;
|
|
14688
16678
|
}
|
|
14689
16679
|
for (const dirName of dirNames) {
|
|
14690
|
-
const dirPath =
|
|
16680
|
+
const dirPath = join7(tempBase, dirName);
|
|
14691
16681
|
const isRemovingDir = dirName.endsWith(REMOVING_SUFFIX);
|
|
14692
16682
|
const isGhostDir = dirName.startsWith(GHOST_DIR_PREFIX) && !isRemovingDir;
|
|
14693
16683
|
if (!isRemovingDir && !isGhostDir)
|
|
14694
16684
|
continue;
|
|
14695
16685
|
let stats;
|
|
14696
16686
|
try {
|
|
14697
|
-
stats = await
|
|
16687
|
+
stats = await stat5(dirPath);
|
|
14698
16688
|
} catch {
|
|
14699
16689
|
continue;
|
|
14700
16690
|
}
|
|
@@ -14707,7 +16697,7 @@ async function cleanupOrphanedGhostDirs(tempBase = tmpdir()) {
|
|
|
14707
16697
|
try {
|
|
14708
16698
|
if (isGhostDir) {
|
|
14709
16699
|
const removingPath = `${dirPath}${REMOVING_SUFFIX}`;
|
|
14710
|
-
await
|
|
16700
|
+
await rename2(dirPath, removingPath);
|
|
14711
16701
|
await rm2(removingPath, { recursive: true, force: true });
|
|
14712
16702
|
} else {
|
|
14713
16703
|
await rm2(dirPath, { recursive: true, force: true });
|
|
@@ -14717,10 +16707,69 @@ async function cleanupOrphanedGhostDirs(tempBase = tmpdir()) {
|
|
|
14717
16707
|
}
|
|
14718
16708
|
return cleanedCount;
|
|
14719
16709
|
}
|
|
16710
|
+
async function computeSymlinkPlan(sourceDir, projectRoot, matcher) {
|
|
16711
|
+
if (!isAbsolute2(sourceDir)) {
|
|
16712
|
+
throw new Error(`sourceDir must be an absolute path, got: ${sourceDir}`);
|
|
16713
|
+
}
|
|
16714
|
+
const plan = {
|
|
16715
|
+
wholeDirs: [],
|
|
16716
|
+
files: [],
|
|
16717
|
+
partialDirs: new Map
|
|
16718
|
+
};
|
|
16719
|
+
const entries = await readdir4(sourceDir, { withFileTypes: true });
|
|
16720
|
+
for (const entry of entries) {
|
|
16721
|
+
const sourcePath = join7(sourceDir, entry.name);
|
|
16722
|
+
const relativePath = normalizeForMatching(sourcePath, projectRoot);
|
|
16723
|
+
const disposition = matcher.getDisposition(relativePath);
|
|
16724
|
+
if (disposition.type === "excluded") {
|
|
16725
|
+
continue;
|
|
16726
|
+
}
|
|
16727
|
+
if (disposition.type === "included") {
|
|
16728
|
+
if (entry.isDirectory()) {
|
|
16729
|
+
plan.wholeDirs.push(entry.name);
|
|
16730
|
+
} else {
|
|
16731
|
+
plan.files.push(entry.name);
|
|
16732
|
+
}
|
|
16733
|
+
continue;
|
|
16734
|
+
}
|
|
16735
|
+
if (entry.isDirectory()) {
|
|
16736
|
+
const nestedPlan = await computeSymlinkPlan(sourcePath, projectRoot, matcher);
|
|
16737
|
+
plan.partialDirs.set(entry.name, nestedPlan);
|
|
16738
|
+
} else {
|
|
16739
|
+
plan.files.push(entry.name);
|
|
16740
|
+
}
|
|
16741
|
+
}
|
|
16742
|
+
return plan;
|
|
16743
|
+
}
|
|
16744
|
+
async function executeSymlinkPlan(plan, sourceRoot, targetRoot) {
|
|
16745
|
+
if (!isAbsolute2(sourceRoot)) {
|
|
16746
|
+
throw new Error(`sourceRoot must be an absolute path, got: ${sourceRoot}`);
|
|
16747
|
+
}
|
|
16748
|
+
if (!isAbsolute2(targetRoot)) {
|
|
16749
|
+
throw new Error(`targetRoot must be an absolute path, got: ${targetRoot}`);
|
|
16750
|
+
}
|
|
16751
|
+
for (const dirName of plan.wholeDirs) {
|
|
16752
|
+
const sourcePath = join7(sourceRoot, dirName);
|
|
16753
|
+
const targetPath = join7(targetRoot, dirName);
|
|
16754
|
+
await symlink2(sourcePath, targetPath);
|
|
16755
|
+
}
|
|
16756
|
+
for (const fileName of plan.files) {
|
|
16757
|
+
const sourcePath = join7(sourceRoot, fileName);
|
|
16758
|
+
const targetPath = join7(targetRoot, fileName);
|
|
16759
|
+
await symlink2(sourcePath, targetPath);
|
|
16760
|
+
}
|
|
16761
|
+
for (const [dirName, nestedPlan] of plan.partialDirs) {
|
|
16762
|
+
const sourcePath = join7(sourceRoot, dirName);
|
|
16763
|
+
const targetPath = join7(targetRoot, dirName);
|
|
16764
|
+
await mkdir4(targetPath, { recursive: true });
|
|
16765
|
+
await executeSymlinkPlan(nestedPlan, sourcePath, targetPath);
|
|
16766
|
+
}
|
|
16767
|
+
}
|
|
14720
16768
|
|
|
14721
16769
|
// src/utils/terminal-title.ts
|
|
14722
16770
|
import path6 from "path";
|
|
14723
16771
|
var MAX_BRANCH_LENGTH = 20;
|
|
16772
|
+
var titleSaved = false;
|
|
14724
16773
|
function isInsideTmux() {
|
|
14725
16774
|
return Boolean(process.env.TMUX);
|
|
14726
16775
|
}
|
|
@@ -14741,6 +16790,25 @@ function setTerminalName(name) {
|
|
|
14741
16790
|
setTmuxWindowName(name);
|
|
14742
16791
|
setTerminalTitle(name);
|
|
14743
16792
|
}
|
|
16793
|
+
function saveTerminalTitle() {
|
|
16794
|
+
if (titleSaved || !isTTY) {
|
|
16795
|
+
return;
|
|
16796
|
+
}
|
|
16797
|
+
process.stdout.write("\x1B[22;2t");
|
|
16798
|
+
titleSaved = true;
|
|
16799
|
+
}
|
|
16800
|
+
function restoreTerminalTitle() {
|
|
16801
|
+
if (!titleSaved) {
|
|
16802
|
+
return;
|
|
16803
|
+
}
|
|
16804
|
+
if (isInsideTmux()) {
|
|
16805
|
+
Bun.spawnSync(["tmux", "set-window-option", "automatic-rename", "on"]);
|
|
16806
|
+
}
|
|
16807
|
+
if (isTTY) {
|
|
16808
|
+
process.stdout.write("\x1B[23;2t");
|
|
16809
|
+
}
|
|
16810
|
+
titleSaved = false;
|
|
16811
|
+
}
|
|
14744
16812
|
function formatTerminalName(cwd, profileName, gitInfo) {
|
|
14745
16813
|
const repoName = gitInfo.repoName ?? path6.basename(cwd);
|
|
14746
16814
|
if (!gitInfo.branch) {
|
|
@@ -14752,7 +16820,7 @@ function formatTerminalName(cwd, profileName, gitInfo) {
|
|
|
14752
16820
|
|
|
14753
16821
|
// src/commands/ghost/opencode.ts
|
|
14754
16822
|
function registerGhostOpenCodeCommand(parent) {
|
|
14755
|
-
parent.command("opencode").description("Launch OpenCode with ghost mode configuration").option("-p, --profile <name>", "Use specific profile").addOption(sharedOptions.json()).addOption(sharedOptions.quiet()).allowUnknownOption().allowExcessArguments(true).action(async (options2, command) => {
|
|
16823
|
+
parent.command("opencode").description("Launch OpenCode with ghost mode configuration").option("-p, --profile <name>", "Use specific profile").option("--no-rename", "Disable terminal/tmux window renaming").addOption(sharedOptions.json()).addOption(sharedOptions.quiet()).allowUnknownOption().allowExcessArguments(true).action(async (options2, command) => {
|
|
14756
16824
|
try {
|
|
14757
16825
|
const args = command.args;
|
|
14758
16826
|
await runGhostOpenCode(args, options2);
|
|
@@ -14766,11 +16834,6 @@ async function runGhostOpenCode(args, options2) {
|
|
|
14766
16834
|
if (!await manager.isInitialized()) {
|
|
14767
16835
|
throw new ProfilesNotInitializedError;
|
|
14768
16836
|
}
|
|
14769
|
-
if (!options2.quiet && await needsMigration()) {
|
|
14770
|
-
console.log("Notice: Found legacy config at ~/.config/ocx/");
|
|
14771
|
-
console.log(`Run 'ocx ghost migrate' to upgrade to the new profiles system.
|
|
14772
|
-
`);
|
|
14773
|
-
}
|
|
14774
16837
|
await cleanupOrphanedGhostDirs();
|
|
14775
16838
|
const profileName = await manager.getCurrent(options2.profile);
|
|
14776
16839
|
const profile = await manager.get(profileName);
|
|
@@ -14783,26 +16846,29 @@ async function runGhostOpenCode(args, options2) {
|
|
|
14783
16846
|
}
|
|
14784
16847
|
const cwd = process.cwd();
|
|
14785
16848
|
const gitContext = await detectGitRepo(cwd);
|
|
14786
|
-
const gitRoot = gitContext?.workTree ?? cwd;
|
|
14787
|
-
const discoveredPaths = await discoverProjectFiles(cwd, gitRoot);
|
|
14788
16849
|
const ghostConfig = profile.ghost;
|
|
14789
|
-
const
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14794
|
-
const agentsPath = getProfileAgents(profileName);
|
|
14795
|
-
const destAgentsPath = path7.join(tempDir, "AGENTS.md");
|
|
14796
|
-
await copyFilePromise(agentsPath, destAgentsPath);
|
|
14797
|
-
}
|
|
16850
|
+
const tempDir = await createSymlinkFarm(cwd, {
|
|
16851
|
+
includePatterns: ghostConfig.include,
|
|
16852
|
+
excludePatterns: ghostConfig.exclude
|
|
16853
|
+
});
|
|
16854
|
+
const overlayFiles = await injectProfileOverlay(tempDir, profileDir, ghostConfig.include);
|
|
14798
16855
|
let cleanupDone = false;
|
|
16856
|
+
let fileSync;
|
|
16857
|
+
fileSync = createFileSync(tempDir, cwd, { overlayFiles });
|
|
14799
16858
|
const performCleanup = async () => {
|
|
14800
16859
|
if (cleanupDone)
|
|
14801
16860
|
return;
|
|
14802
16861
|
cleanupDone = true;
|
|
14803
16862
|
await cleanupSymlinkFarm(tempDir);
|
|
14804
16863
|
};
|
|
16864
|
+
const shouldRename = options2.rename !== false && ghostConfig.renameWindow !== false;
|
|
14805
16865
|
const exitHandler = () => {
|
|
16866
|
+
if (shouldRename) {
|
|
16867
|
+
restoreTerminalTitle();
|
|
16868
|
+
}
|
|
16869
|
+
if (fileSync) {
|
|
16870
|
+
fileSync.close().catch(() => {});
|
|
16871
|
+
}
|
|
14806
16872
|
if (!cleanupDone && tempDir) {
|
|
14807
16873
|
try {
|
|
14808
16874
|
const removingPath = `${tempDir}${REMOVING_SUFFIX}`;
|
|
@@ -14817,8 +16883,11 @@ async function runGhostOpenCode(args, options2) {
|
|
|
14817
16883
|
const sigtermHandler = () => proc?.kill("SIGTERM");
|
|
14818
16884
|
process.on("SIGINT", sigintHandler);
|
|
14819
16885
|
process.on("SIGTERM", sigtermHandler);
|
|
14820
|
-
|
|
14821
|
-
|
|
16886
|
+
if (shouldRename) {
|
|
16887
|
+
saveTerminalTitle();
|
|
16888
|
+
const gitInfo = await getGitInfo(cwd);
|
|
16889
|
+
setTerminalName(formatTerminalName(cwd, profileName, gitInfo));
|
|
16890
|
+
}
|
|
14822
16891
|
proc = Bun.spawn({
|
|
14823
16892
|
cmd: ["opencode", ...args],
|
|
14824
16893
|
cwd: tempDir,
|
|
@@ -14838,14 +16907,62 @@ async function runGhostOpenCode(args, options2) {
|
|
|
14838
16907
|
});
|
|
14839
16908
|
try {
|
|
14840
16909
|
const exitCode = await proc.exited;
|
|
16910
|
+
process.off("SIGINT", sigintHandler);
|
|
16911
|
+
process.off("SIGTERM", sigtermHandler);
|
|
16912
|
+
process.off("exit", exitHandler);
|
|
16913
|
+
if (fileSync) {
|
|
16914
|
+
await fileSync.close();
|
|
16915
|
+
const syncCount = fileSync.getSyncCount();
|
|
16916
|
+
const failures = fileSync.getFailures();
|
|
16917
|
+
if (syncCount > 0 && !options2.quiet) {
|
|
16918
|
+
logger.info(`Synced ${syncCount} new files to project`);
|
|
16919
|
+
}
|
|
16920
|
+
if (failures.length > 0) {
|
|
16921
|
+
logger.warn(`${failures.length} files failed to sync`);
|
|
16922
|
+
for (const f of failures) {
|
|
16923
|
+
logger.debug(` ${f.path}: ${f.error.message}`);
|
|
16924
|
+
}
|
|
16925
|
+
}
|
|
16926
|
+
}
|
|
16927
|
+
await performCleanup();
|
|
14841
16928
|
process.exit(exitCode);
|
|
14842
|
-
}
|
|
16929
|
+
} catch (error) {
|
|
14843
16930
|
process.off("SIGINT", sigintHandler);
|
|
14844
16931
|
process.off("SIGTERM", sigtermHandler);
|
|
14845
16932
|
process.off("exit", exitHandler);
|
|
16933
|
+
if (fileSync) {
|
|
16934
|
+
await fileSync.close();
|
|
16935
|
+
}
|
|
14846
16936
|
await performCleanup();
|
|
16937
|
+
throw error;
|
|
14847
16938
|
}
|
|
14848
16939
|
}
|
|
16940
|
+
function userExplicitlyIncluded(relativePath, compiledPatterns) {
|
|
16941
|
+
if (compiledPatterns.length === 0)
|
|
16942
|
+
return false;
|
|
16943
|
+
return compiledPatterns.some((glob) => glob.match(relativePath));
|
|
16944
|
+
}
|
|
16945
|
+
async function injectProfileOverlay(tempDir, profileDir, includePatterns) {
|
|
16946
|
+
const entries = await readdir5(profileDir, { withFileTypes: true, recursive: true });
|
|
16947
|
+
const injectedFiles = new Set;
|
|
16948
|
+
const compiledIncludePatterns = includePatterns.map((p) => new Glob3(p));
|
|
16949
|
+
for (const entry of entries) {
|
|
16950
|
+
const relativePath = path7.relative(profileDir, path7.join(entry.parentPath, entry.name));
|
|
16951
|
+
if (relativePath === "ghost.jsonc")
|
|
16952
|
+
continue;
|
|
16953
|
+
if (relativePath === ".gitignore")
|
|
16954
|
+
continue;
|
|
16955
|
+
if (userExplicitlyIncluded(relativePath, compiledIncludePatterns))
|
|
16956
|
+
continue;
|
|
16957
|
+
if (entry.isDirectory())
|
|
16958
|
+
continue;
|
|
16959
|
+
const destPath = path7.join(tempDir, relativePath);
|
|
16960
|
+
await mkdir5(path7.dirname(destPath), { recursive: true });
|
|
16961
|
+
await copyFile(path7.join(entry.parentPath, entry.name), destPath);
|
|
16962
|
+
injectedFiles.add(normalizePath2(relativePath));
|
|
16963
|
+
}
|
|
16964
|
+
return new Set(injectedFiles);
|
|
16965
|
+
}
|
|
14849
16966
|
|
|
14850
16967
|
// src/commands/ghost/profile/add.ts
|
|
14851
16968
|
function registerProfileAddCommand(parent) {
|
|
@@ -15381,13 +17498,12 @@ function registerGhostCommand(program2) {
|
|
|
15381
17498
|
registerGhostSearchCommand(ghost);
|
|
15382
17499
|
registerGhostOpenCodeCommand(ghost);
|
|
15383
17500
|
registerGhostProfileCommand(ghost);
|
|
15384
|
-
registerGhostMigrateCommand(ghost);
|
|
15385
17501
|
}
|
|
15386
17502
|
|
|
15387
17503
|
// src/commands/init.ts
|
|
15388
|
-
import { existsSync as
|
|
15389
|
-
import { cp, mkdir as
|
|
15390
|
-
import { join as
|
|
17504
|
+
import { existsSync as existsSync3 } from "fs";
|
|
17505
|
+
import { cp, mkdir as mkdir6, readdir as readdir6, readFile, rm as rm3, writeFile as writeFile2 } from "fs/promises";
|
|
17506
|
+
import { join as join8 } from "path";
|
|
15391
17507
|
var TEMPLATE_REPO = "kdcokenny/ocx";
|
|
15392
17508
|
var TEMPLATE_PATH = "examples/registry-starter";
|
|
15393
17509
|
function registerInitCommand(program2) {
|
|
@@ -15405,8 +17521,8 @@ function registerInitCommand(program2) {
|
|
|
15405
17521
|
}
|
|
15406
17522
|
async function runInit(options2) {
|
|
15407
17523
|
const cwd = options2.cwd ?? process.cwd();
|
|
15408
|
-
const configPath =
|
|
15409
|
-
if (
|
|
17524
|
+
const configPath = join8(cwd, "ocx.jsonc");
|
|
17525
|
+
if (existsSync3(configPath)) {
|
|
15410
17526
|
throw new ConflictError(`ocx.jsonc already exists at ${configPath}
|
|
15411
17527
|
|
|
15412
17528
|
` + `To reset, delete the config and run init again:
|
|
@@ -15453,7 +17569,7 @@ async function runInitRegistry(directory, options2) {
|
|
|
15453
17569
|
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(namespace)) {
|
|
15454
17570
|
throw new ValidationError("Invalid namespace format: must start with letter/number, use hyphens only between segments (e.g., 'my-registry')");
|
|
15455
17571
|
}
|
|
15456
|
-
const existingFiles = await
|
|
17572
|
+
const existingFiles = await readdir6(cwd).catch(() => []);
|
|
15457
17573
|
const hasVisibleFiles = existingFiles.some((f) => !f.startsWith("."));
|
|
15458
17574
|
if (hasVisibleFiles && !options2.force) {
|
|
15459
17575
|
throw new ConflictError("Directory is not empty. Use --force to overwrite existing files.");
|
|
@@ -15464,7 +17580,7 @@ async function runInitRegistry(directory, options2) {
|
|
|
15464
17580
|
if (spin)
|
|
15465
17581
|
spin.text = options2.local ? "Copying template..." : "Fetching template...";
|
|
15466
17582
|
if (options2.local) {
|
|
15467
|
-
await
|
|
17583
|
+
await mkdir6(cwd, { recursive: true });
|
|
15468
17584
|
await copyDir(options2.local, cwd);
|
|
15469
17585
|
} else {
|
|
15470
17586
|
const version = options2.canary ? "main" : await getLatestVersion();
|
|
@@ -15480,7 +17596,7 @@ async function runInitRegistry(directory, options2) {
|
|
|
15480
17596
|
logger.info("");
|
|
15481
17597
|
logger.info("Next steps:");
|
|
15482
17598
|
logger.info(" 1. bun install");
|
|
15483
|
-
logger.info(" 2. Edit registry.
|
|
17599
|
+
logger.info(" 2. Edit registry.jsonc with your components");
|
|
15484
17600
|
logger.info(" 3. bun run build");
|
|
15485
17601
|
logger.info("");
|
|
15486
17602
|
logger.info("Deploy to:");
|
|
@@ -15512,10 +17628,10 @@ async function fetchAndExtractTemplate(destDir, version, verbose) {
|
|
|
15512
17628
|
if (!response.ok || !response.body) {
|
|
15513
17629
|
throw new NetworkError(`Failed to fetch template from ${tarballUrl}: ${response.statusText}`);
|
|
15514
17630
|
}
|
|
15515
|
-
const tempDir =
|
|
15516
|
-
await
|
|
17631
|
+
const tempDir = join8(destDir, ".ocx-temp");
|
|
17632
|
+
await mkdir6(tempDir, { recursive: true });
|
|
15517
17633
|
try {
|
|
15518
|
-
const tarPath =
|
|
17634
|
+
const tarPath = join8(tempDir, "template.tar.gz");
|
|
15519
17635
|
const arrayBuffer = await response.arrayBuffer();
|
|
15520
17636
|
await writeFile2(tarPath, Buffer.from(arrayBuffer));
|
|
15521
17637
|
const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", tempDir], {
|
|
@@ -15527,12 +17643,12 @@ async function fetchAndExtractTemplate(destDir, version, verbose) {
|
|
|
15527
17643
|
const stderr = await new Response(proc.stderr).text();
|
|
15528
17644
|
throw new Error(`Failed to extract template: ${stderr}`);
|
|
15529
17645
|
}
|
|
15530
|
-
const extractedDirs = await
|
|
17646
|
+
const extractedDirs = await readdir6(tempDir);
|
|
15531
17647
|
const extractedDir = extractedDirs.find((d) => d.startsWith("ocx-"));
|
|
15532
17648
|
if (!extractedDir) {
|
|
15533
17649
|
throw new Error("Failed to find extracted template directory");
|
|
15534
17650
|
}
|
|
15535
|
-
const templateDir =
|
|
17651
|
+
const templateDir = join8(tempDir, extractedDir, TEMPLATE_PATH);
|
|
15536
17652
|
await copyDir(templateDir, destDir);
|
|
15537
17653
|
} finally {
|
|
15538
17654
|
await rm3(tempDir, { recursive: true, force: true });
|
|
@@ -15540,15 +17656,15 @@ async function fetchAndExtractTemplate(destDir, version, verbose) {
|
|
|
15540
17656
|
}
|
|
15541
17657
|
async function replacePlaceholders(dir, values) {
|
|
15542
17658
|
const filesToProcess = [
|
|
15543
|
-
"registry.
|
|
17659
|
+
"registry.jsonc",
|
|
15544
17660
|
"package.json",
|
|
15545
17661
|
"wrangler.jsonc",
|
|
15546
17662
|
"README.md",
|
|
15547
17663
|
"AGENTS.md"
|
|
15548
17664
|
];
|
|
15549
17665
|
for (const file of filesToProcess) {
|
|
15550
|
-
const filePath =
|
|
15551
|
-
if (!
|
|
17666
|
+
const filePath = join8(dir, file);
|
|
17667
|
+
if (!existsSync3(filePath))
|
|
15552
17668
|
continue;
|
|
15553
17669
|
let content2 = await readFile(filePath).then((b) => b.toString());
|
|
15554
17670
|
content2 = content2.replace(/my-registry/g, values.namespace);
|
|
@@ -15557,11 +17673,393 @@ async function replacePlaceholders(dir, values) {
|
|
|
15557
17673
|
}
|
|
15558
17674
|
}
|
|
15559
17675
|
|
|
15560
|
-
// src/
|
|
17676
|
+
// src/self-update/version-provider.ts
|
|
17677
|
+
class BuildTimeVersionProvider {
|
|
17678
|
+
version = "1.3.0";
|
|
17679
|
+
}
|
|
17680
|
+
var defaultVersionProvider = new BuildTimeVersionProvider;
|
|
17681
|
+
|
|
17682
|
+
// src/self-update/check.ts
|
|
17683
|
+
var VERSION_CHECK_TIMEOUT_MS = 200;
|
|
17684
|
+
var PACKAGE_NAME = "ocx";
|
|
17685
|
+
function parseVersion2(v) {
|
|
17686
|
+
const [main2 = ""] = v.split("-");
|
|
17687
|
+
const parts = main2.split(".");
|
|
17688
|
+
const major = parseInt(parts[0] ?? "", 10);
|
|
17689
|
+
const minor = parseInt(parts[1] ?? "", 10);
|
|
17690
|
+
const patch = parseInt(parts[2] ?? "", 10);
|
|
17691
|
+
if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch)) {
|
|
17692
|
+
return null;
|
|
17693
|
+
}
|
|
17694
|
+
return { major, minor, patch };
|
|
17695
|
+
}
|
|
17696
|
+
function compareSemver2(a, b) {
|
|
17697
|
+
const vA = parseVersion2(a);
|
|
17698
|
+
const vB = parseVersion2(b);
|
|
17699
|
+
if (!vA || !vB) {
|
|
17700
|
+
return null;
|
|
17701
|
+
}
|
|
17702
|
+
if (vA.major !== vB.major)
|
|
17703
|
+
return vA.major - vB.major;
|
|
17704
|
+
if (vA.minor !== vB.minor)
|
|
17705
|
+
return vA.minor - vB.minor;
|
|
17706
|
+
return vA.patch - vB.patch;
|
|
17707
|
+
}
|
|
17708
|
+
async function checkForUpdate(versionProvider) {
|
|
17709
|
+
const provider = versionProvider ?? defaultVersionProvider;
|
|
17710
|
+
const current = provider.version || "0.0.0-dev";
|
|
17711
|
+
if (current === "0.0.0-dev") {
|
|
17712
|
+
return null;
|
|
17713
|
+
}
|
|
17714
|
+
try {
|
|
17715
|
+
const result = await fetchPackageVersion(PACKAGE_NAME, undefined, AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS));
|
|
17716
|
+
const latest = result.version;
|
|
17717
|
+
const comparison = compareSemver2(latest, current);
|
|
17718
|
+
if (comparison === null) {
|
|
17719
|
+
return null;
|
|
17720
|
+
}
|
|
17721
|
+
return {
|
|
17722
|
+
current,
|
|
17723
|
+
latest,
|
|
17724
|
+
updateAvailable: comparison > 0
|
|
17725
|
+
};
|
|
17726
|
+
} catch {
|
|
17727
|
+
return null;
|
|
17728
|
+
}
|
|
17729
|
+
}
|
|
17730
|
+
|
|
17731
|
+
// src/self-update/detect-method.ts
|
|
17732
|
+
function parseInstallMethod(input) {
|
|
17733
|
+
const VALID_METHODS = ["curl", "npm", "yarn", "pnpm", "bun"];
|
|
17734
|
+
const method = VALID_METHODS.find((m) => m === input);
|
|
17735
|
+
if (!method) {
|
|
17736
|
+
throw new SelfUpdateError(`Invalid install method: "${input}"
|
|
17737
|
+
Valid methods: ${VALID_METHODS.join(", ")}`);
|
|
17738
|
+
}
|
|
17739
|
+
return method;
|
|
17740
|
+
}
|
|
17741
|
+
var isCompiledBinary = () => Bun.main.startsWith("/$bunfs/");
|
|
17742
|
+
var isTempExecution = (path8) => path8.includes("/_npx/") || path8.includes("/.cache/bunx/") || path8.includes("/.pnpm/_temp/");
|
|
17743
|
+
var isYarnGlobalInstall = (path8) => path8.includes("/.yarn/global") || path8.includes("/.config/yarn/global");
|
|
17744
|
+
var isPnpmGlobalInstall = (path8) => path8.includes("/.pnpm/") || path8.includes("/pnpm/global");
|
|
17745
|
+
var isBunGlobalInstall = (path8) => path8.includes("/.bun/bin") || path8.includes("/.bun/install/global");
|
|
17746
|
+
var isNpmGlobalInstall = (path8) => path8.includes("/.npm/") || path8.includes("/node_modules/");
|
|
17747
|
+
function detectInstallMethod() {
|
|
17748
|
+
if (isCompiledBinary()) {
|
|
17749
|
+
return "curl";
|
|
17750
|
+
}
|
|
17751
|
+
const scriptPath = process.argv[1] ?? "";
|
|
17752
|
+
if (isTempExecution(scriptPath))
|
|
17753
|
+
return "unknown";
|
|
17754
|
+
if (isYarnGlobalInstall(scriptPath))
|
|
17755
|
+
return "yarn";
|
|
17756
|
+
if (isPnpmGlobalInstall(scriptPath))
|
|
17757
|
+
return "pnpm";
|
|
17758
|
+
if (isBunGlobalInstall(scriptPath))
|
|
17759
|
+
return "bun";
|
|
17760
|
+
if (isNpmGlobalInstall(scriptPath))
|
|
17761
|
+
return "npm";
|
|
17762
|
+
const userAgent = process.env.npm_config_user_agent ?? "";
|
|
17763
|
+
if (userAgent.includes("yarn"))
|
|
17764
|
+
return "yarn";
|
|
17765
|
+
if (userAgent.includes("pnpm"))
|
|
17766
|
+
return "pnpm";
|
|
17767
|
+
if (userAgent.includes("bun"))
|
|
17768
|
+
return "bun";
|
|
17769
|
+
if (userAgent.includes("npm"))
|
|
17770
|
+
return "npm";
|
|
17771
|
+
return "unknown";
|
|
17772
|
+
}
|
|
17773
|
+
function getExecutablePath() {
|
|
17774
|
+
if (typeof Bun !== "undefined" && Bun.main.startsWith("/$bunfs/")) {
|
|
17775
|
+
return process.execPath;
|
|
17776
|
+
}
|
|
17777
|
+
return process.argv[1] ?? process.execPath;
|
|
17778
|
+
}
|
|
17779
|
+
|
|
17780
|
+
// src/self-update/download.ts
|
|
17781
|
+
import { chmodSync, existsSync as existsSync4, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
17782
|
+
var GITHUB_REPO2 = "kdcokenny/ocx";
|
|
17783
|
+
var DEFAULT_DOWNLOAD_BASE_URL = `https://github.com/${GITHUB_REPO2}/releases/download`;
|
|
17784
|
+
var PLATFORM_MAP = {
|
|
17785
|
+
"arm64-darwin": "ocx-darwin-arm64",
|
|
17786
|
+
"x64-darwin": "ocx-darwin-x64",
|
|
17787
|
+
"arm64-linux": "ocx-linux-arm64",
|
|
17788
|
+
"x64-linux": "ocx-linux-x64",
|
|
17789
|
+
"x64-win32": "ocx-windows-x64.exe"
|
|
17790
|
+
};
|
|
17791
|
+
function getDownloadBaseUrl() {
|
|
17792
|
+
const envUrl = process.env.OCX_DOWNLOAD_URL;
|
|
17793
|
+
if (envUrl) {
|
|
17794
|
+
return envUrl.replace(/\/+$/, "");
|
|
17795
|
+
}
|
|
17796
|
+
return DEFAULT_DOWNLOAD_BASE_URL;
|
|
17797
|
+
}
|
|
17798
|
+
function getDownloadUrl(version) {
|
|
17799
|
+
const platform = `${process.arch}-${process.platform}`;
|
|
17800
|
+
const target = PLATFORM_MAP[platform];
|
|
17801
|
+
if (!target) {
|
|
17802
|
+
const supported = Object.keys(PLATFORM_MAP).join(", ");
|
|
17803
|
+
throw new SelfUpdateError(`Unsupported platform: ${platform}
|
|
17804
|
+
` + `Supported platforms: ${supported}`);
|
|
17805
|
+
}
|
|
17806
|
+
const baseUrl = getDownloadBaseUrl();
|
|
17807
|
+
return `${baseUrl}/v${version}/${target}`;
|
|
17808
|
+
}
|
|
17809
|
+
async function downloadWithProgress(url, dest) {
|
|
17810
|
+
const spin = createSpinner({ text: "Downloading update..." });
|
|
17811
|
+
spin.start();
|
|
17812
|
+
let response;
|
|
17813
|
+
try {
|
|
17814
|
+
response = await fetch(url, { redirect: "follow" });
|
|
17815
|
+
} catch (error) {
|
|
17816
|
+
spin.fail("Download failed");
|
|
17817
|
+
throw new SelfUpdateError(`Network error: ${error instanceof Error ? error.message : String(error)}`);
|
|
17818
|
+
}
|
|
17819
|
+
if (!response.ok) {
|
|
17820
|
+
spin.fail("Download failed");
|
|
17821
|
+
throw new SelfUpdateError(`Failed to download: HTTP ${response.status} ${response.statusText}`);
|
|
17822
|
+
}
|
|
17823
|
+
if (!response.body) {
|
|
17824
|
+
spin.fail("Download failed");
|
|
17825
|
+
throw new SelfUpdateError("Download failed: Empty response body");
|
|
17826
|
+
}
|
|
17827
|
+
const reader = response.body.getReader();
|
|
17828
|
+
const writer = Bun.file(dest).writer();
|
|
17829
|
+
const total = Number(response.headers.get("content-length") || 0);
|
|
17830
|
+
let received = 0;
|
|
17831
|
+
try {
|
|
17832
|
+
while (true) {
|
|
17833
|
+
const { done, value } = await reader.read();
|
|
17834
|
+
if (done)
|
|
17835
|
+
break;
|
|
17836
|
+
await writer.write(value);
|
|
17837
|
+
received += value.length;
|
|
17838
|
+
if (total > 0) {
|
|
17839
|
+
const pct = Math.round(received / total * 100);
|
|
17840
|
+
spin.text = `Downloading... ${pct}%`;
|
|
17841
|
+
}
|
|
17842
|
+
}
|
|
17843
|
+
await writer.end();
|
|
17844
|
+
spin.succeed("Download complete");
|
|
17845
|
+
} catch (error) {
|
|
17846
|
+
spin.fail("Download failed");
|
|
17847
|
+
await writer.end();
|
|
17848
|
+
throw new SelfUpdateError(`Download interrupted: ${error instanceof Error ? error.message : String(error)}`);
|
|
17849
|
+
}
|
|
17850
|
+
}
|
|
17851
|
+
async function downloadToTemp(version) {
|
|
17852
|
+
const execPath = getExecutablePath();
|
|
17853
|
+
const tempPath = `${execPath}.new.${Date.now()}`;
|
|
17854
|
+
const url = getDownloadUrl(version);
|
|
17855
|
+
await downloadWithProgress(url, tempPath);
|
|
17856
|
+
try {
|
|
17857
|
+
chmodSync(tempPath, 493);
|
|
17858
|
+
} catch (error) {
|
|
17859
|
+
if (existsSync4(tempPath)) {
|
|
17860
|
+
unlinkSync2(tempPath);
|
|
17861
|
+
}
|
|
17862
|
+
throw new SelfUpdateError(`Failed to set permissions: ${error instanceof Error ? error.message : String(error)}`);
|
|
17863
|
+
}
|
|
17864
|
+
return { tempPath, execPath };
|
|
17865
|
+
}
|
|
17866
|
+
function atomicReplace(tempPath, execPath) {
|
|
17867
|
+
const backupPath = `${execPath}.backup`;
|
|
17868
|
+
try {
|
|
17869
|
+
if (existsSync4(execPath)) {
|
|
17870
|
+
renameSync2(execPath, backupPath);
|
|
17871
|
+
}
|
|
17872
|
+
renameSync2(tempPath, execPath);
|
|
17873
|
+
if (existsSync4(backupPath)) {
|
|
17874
|
+
unlinkSync2(backupPath);
|
|
17875
|
+
}
|
|
17876
|
+
} catch (error) {
|
|
17877
|
+
if (existsSync4(backupPath) && !existsSync4(execPath)) {
|
|
17878
|
+
try {
|
|
17879
|
+
renameSync2(backupPath, execPath);
|
|
17880
|
+
} catch {}
|
|
17881
|
+
}
|
|
17882
|
+
if (existsSync4(tempPath)) {
|
|
17883
|
+
try {
|
|
17884
|
+
unlinkSync2(tempPath);
|
|
17885
|
+
} catch {}
|
|
17886
|
+
}
|
|
17887
|
+
throw new SelfUpdateError(`Update failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
17888
|
+
}
|
|
17889
|
+
}
|
|
17890
|
+
function cleanupTempFile(tempPath) {
|
|
17891
|
+
if (existsSync4(tempPath)) {
|
|
17892
|
+
try {
|
|
17893
|
+
unlinkSync2(tempPath);
|
|
17894
|
+
} catch {}
|
|
17895
|
+
}
|
|
17896
|
+
}
|
|
17897
|
+
|
|
17898
|
+
// src/self-update/notify.ts
|
|
17899
|
+
function notifyUpdate(current, latest) {
|
|
17900
|
+
if (!process.stdout.isTTY)
|
|
17901
|
+
return;
|
|
17902
|
+
console.error(`${kleur_default.cyan("info")}: update available - ${kleur_default.green(latest)} (current: ${kleur_default.dim(current)})`);
|
|
17903
|
+
console.error(` run ${kleur_default.cyan("`ocx self update`")} to upgrade`);
|
|
17904
|
+
}
|
|
17905
|
+
function notifyUpToDate(version) {
|
|
17906
|
+
console.error(`${kleur_default.cyan("info")}: ocx unchanged - ${kleur_default.dim(version)}`);
|
|
17907
|
+
}
|
|
17908
|
+
function notifyUpdated(from, to) {
|
|
17909
|
+
console.error(` ${kleur_default.green("ocx updated")} - ${to} (from ${from})`);
|
|
17910
|
+
}
|
|
17911
|
+
|
|
17912
|
+
// src/self-update/verify.ts
|
|
15561
17913
|
import { createHash as createHash2 } from "crypto";
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
17914
|
+
var GITHUB_REPO3 = "kdcokenny/ocx";
|
|
17915
|
+
function parseSha256Sums(content2) {
|
|
17916
|
+
const checksums = new Map;
|
|
17917
|
+
for (const line of content2.split(`
|
|
17918
|
+
`)) {
|
|
17919
|
+
const match = line.match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
|
|
17920
|
+
if (match?.[1] && match[2]) {
|
|
17921
|
+
checksums.set(match[2].trim(), match[1].toLowerCase());
|
|
17922
|
+
}
|
|
17923
|
+
}
|
|
17924
|
+
return checksums;
|
|
17925
|
+
}
|
|
17926
|
+
function hashContent2(content2) {
|
|
17927
|
+
return createHash2("sha256").update(content2).digest("hex");
|
|
17928
|
+
}
|
|
17929
|
+
async function fetchChecksums(version) {
|
|
17930
|
+
const url = `https://github.com/${GITHUB_REPO3}/releases/download/v${version}/SHA256SUMS.txt`;
|
|
17931
|
+
const response = await fetch(url);
|
|
17932
|
+
if (!response.ok) {
|
|
17933
|
+
throw new SelfUpdateError(`Failed to fetch checksums: ${response.status}`);
|
|
17934
|
+
}
|
|
17935
|
+
const content2 = await response.text();
|
|
17936
|
+
return parseSha256Sums(content2);
|
|
17937
|
+
}
|
|
17938
|
+
async function verifyChecksum(filePath, expectedHash, filename) {
|
|
17939
|
+
const file = Bun.file(filePath);
|
|
17940
|
+
const content2 = await file.arrayBuffer();
|
|
17941
|
+
const actualHash = hashContent2(Buffer.from(content2));
|
|
17942
|
+
if (actualHash !== expectedHash) {
|
|
17943
|
+
throw new IntegrityError(filename, expectedHash, actualHash);
|
|
17944
|
+
}
|
|
17945
|
+
}
|
|
17946
|
+
|
|
17947
|
+
// src/commands/self/update.ts
|
|
17948
|
+
var SEMVER_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
17949
|
+
async function updateCommand(options2) {
|
|
17950
|
+
const method = options2.method ? parseInstallMethod(options2.method) : detectInstallMethod();
|
|
17951
|
+
const result = await checkForUpdate();
|
|
17952
|
+
if (!result) {
|
|
17953
|
+
throw new SelfUpdateError("Failed to check for updates");
|
|
17954
|
+
}
|
|
17955
|
+
const { current, latest, updateAvailable } = result;
|
|
17956
|
+
if (!updateAvailable && !options2.force) {
|
|
17957
|
+
notifyUpToDate(current);
|
|
17958
|
+
return;
|
|
17959
|
+
}
|
|
17960
|
+
const targetVersion = latest;
|
|
17961
|
+
switch (method) {
|
|
17962
|
+
case "curl": {
|
|
17963
|
+
await updateViaCurl(current, targetVersion);
|
|
17964
|
+
break;
|
|
17965
|
+
}
|
|
17966
|
+
case "npm":
|
|
17967
|
+
case "pnpm":
|
|
17968
|
+
case "bun":
|
|
17969
|
+
case "unknown": {
|
|
17970
|
+
await updateViaPackageManager(method, current, targetVersion);
|
|
17971
|
+
break;
|
|
17972
|
+
}
|
|
17973
|
+
}
|
|
17974
|
+
}
|
|
17975
|
+
async function updateViaCurl(current, targetVersion) {
|
|
17976
|
+
const url = getDownloadUrl(targetVersion);
|
|
17977
|
+
const filename = url.split("/").pop();
|
|
17978
|
+
if (!filename) {
|
|
17979
|
+
throw new SelfUpdateError("Failed to determine binary filename from download URL");
|
|
17980
|
+
}
|
|
17981
|
+
const checksums = await fetchChecksums(targetVersion);
|
|
17982
|
+
const expectedHash = checksums.get(filename);
|
|
17983
|
+
if (!expectedHash) {
|
|
17984
|
+
throw new SelfUpdateError(`Security error: No checksum found for ${filename}. Update aborted.`);
|
|
17985
|
+
}
|
|
17986
|
+
const { tempPath, execPath } = await downloadToTemp(targetVersion);
|
|
17987
|
+
try {
|
|
17988
|
+
await verifyChecksum(tempPath, expectedHash, filename);
|
|
17989
|
+
} catch (error) {
|
|
17990
|
+
cleanupTempFile(tempPath);
|
|
17991
|
+
throw error;
|
|
17992
|
+
}
|
|
17993
|
+
atomicReplace(tempPath, execPath);
|
|
17994
|
+
notifyUpdated(current, targetVersion);
|
|
17995
|
+
}
|
|
17996
|
+
async function runPackageManager(cmd) {
|
|
17997
|
+
const proc = Bun.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
|
|
17998
|
+
const exitCode = await proc.exited;
|
|
17999
|
+
if (exitCode !== 0) {
|
|
18000
|
+
const stderr = await new Response(proc.stderr).text();
|
|
18001
|
+
throw new SelfUpdateError(`Package manager command failed: ${stderr.trim()}`);
|
|
18002
|
+
}
|
|
18003
|
+
}
|
|
18004
|
+
async function updateViaPackageManager(method, current, targetVersion) {
|
|
18005
|
+
if (!SEMVER_PATTERN.test(targetVersion)) {
|
|
18006
|
+
throw new SelfUpdateError(`Invalid version format: ${targetVersion}`);
|
|
18007
|
+
}
|
|
18008
|
+
const spin = createSpinner({ text: `Updating via ${method}...` });
|
|
18009
|
+
spin.start();
|
|
18010
|
+
try {
|
|
18011
|
+
switch (method) {
|
|
18012
|
+
case "npm": {
|
|
18013
|
+
await runPackageManager(["npm", "install", "-g", `ocx@${targetVersion}`]);
|
|
18014
|
+
break;
|
|
18015
|
+
}
|
|
18016
|
+
case "yarn": {
|
|
18017
|
+
await runPackageManager(["yarn", "global", "add", `ocx@${targetVersion}`]);
|
|
18018
|
+
break;
|
|
18019
|
+
}
|
|
18020
|
+
case "pnpm": {
|
|
18021
|
+
await runPackageManager(["pnpm", "install", "-g", `ocx@${targetVersion}`]);
|
|
18022
|
+
break;
|
|
18023
|
+
}
|
|
18024
|
+
case "bun": {
|
|
18025
|
+
await runPackageManager(["bun", "install", "-g", `ocx@${targetVersion}`]);
|
|
18026
|
+
break;
|
|
18027
|
+
}
|
|
18028
|
+
case "unknown": {
|
|
18029
|
+
throw new SelfUpdateError(`Could not detect install method. Update manually with one of:
|
|
18030
|
+
` + ` npm install -g ocx@latest
|
|
18031
|
+
` + ` pnpm install -g ocx@latest
|
|
18032
|
+
` + " bun install -g ocx@latest");
|
|
18033
|
+
}
|
|
18034
|
+
}
|
|
18035
|
+
spin.succeed(`Updated via ${method}`);
|
|
18036
|
+
notifyUpdated(current, targetVersion);
|
|
18037
|
+
} catch (error) {
|
|
18038
|
+
if (error instanceof SelfUpdateError) {
|
|
18039
|
+
spin.fail(`Update failed`);
|
|
18040
|
+
throw error;
|
|
18041
|
+
}
|
|
18042
|
+
spin.fail(`Update failed`);
|
|
18043
|
+
throw new SelfUpdateError(`Failed to run ${method}: ${error instanceof Error ? error.message : String(error)}`);
|
|
18044
|
+
}
|
|
18045
|
+
}
|
|
18046
|
+
function registerSelfUpdateCommand(parent) {
|
|
18047
|
+
parent.command("update").description("Update OCX to the latest version").option("-f, --force", "Reinstall even if already up to date").option("-m, --method <method>", "Override install method detection (curl|npm|pnpm|bun)").action(wrapAction(async (options2) => {
|
|
18048
|
+
await updateCommand(options2);
|
|
18049
|
+
}));
|
|
18050
|
+
}
|
|
18051
|
+
|
|
18052
|
+
// src/commands/self/index.ts
|
|
18053
|
+
function registerSelfCommand(program2) {
|
|
18054
|
+
const self = program2.command("self").description("Manage the OCX CLI");
|
|
18055
|
+
registerSelfUpdateCommand(self);
|
|
18056
|
+
}
|
|
18057
|
+
|
|
18058
|
+
// src/commands/update.ts
|
|
18059
|
+
import { createHash as createHash3 } from "crypto";
|
|
18060
|
+
import { existsSync as existsSync5 } from "fs";
|
|
18061
|
+
import { mkdir as mkdir7, writeFile as writeFile3 } from "fs/promises";
|
|
18062
|
+
import { dirname as dirname7, join as join9 } from "path";
|
|
15565
18063
|
function registerUpdateCommand(program2) {
|
|
15566
18064
|
program2.command("update [components...]").description("Update installed components (use @version suffix to pin, e.g., kdco/agents@1.2.0)").option("--all", "Update all installed components").option("--registry <name>", "Update all components from a specific registry").option("--dry-run", "Preview changes without applying").option("--cwd <path>", "Working directory", process.cwd()).option("-q, --quiet", "Suppress output").option("-v, --verbose", "Verbose output").option("--json", "Output as JSON").action(async (components, options2) => {
|
|
15567
18065
|
try {
|
|
@@ -15573,7 +18071,7 @@ function registerUpdateCommand(program2) {
|
|
|
15573
18071
|
}
|
|
15574
18072
|
async function runUpdate(componentNames, options2) {
|
|
15575
18073
|
const cwd = options2.cwd ?? process.cwd();
|
|
15576
|
-
const lockPath =
|
|
18074
|
+
const lockPath = join9(cwd, "ocx.lock");
|
|
15577
18075
|
const config = await readOcxConfig(cwd);
|
|
15578
18076
|
if (!config) {
|
|
15579
18077
|
throw new ConfigError("No ocx.jsonc found. Run 'ocx init' first.");
|
|
@@ -15698,10 +18196,10 @@ Version cannot be empty. Use 'kdco/agents@1.2.0' or omit the version for latest.
|
|
|
15698
18196
|
const fileObj = update.component.files.find((f) => f.path === file.path);
|
|
15699
18197
|
if (!fileObj)
|
|
15700
18198
|
continue;
|
|
15701
|
-
const targetPath =
|
|
15702
|
-
const targetDir =
|
|
15703
|
-
if (!
|
|
15704
|
-
await
|
|
18199
|
+
const targetPath = join9(cwd, fileObj.target);
|
|
18200
|
+
const targetDir = dirname7(targetPath);
|
|
18201
|
+
if (!existsSync5(targetDir)) {
|
|
18202
|
+
await mkdir7(targetDir, { recursive: true });
|
|
15705
18203
|
}
|
|
15706
18204
|
await writeFile3(targetPath, file.content);
|
|
15707
18205
|
if (options2.verbose) {
|
|
@@ -15822,21 +18320,49 @@ function outputDryRun(results, options2) {
|
|
|
15822
18320
|
}
|
|
15823
18321
|
}
|
|
15824
18322
|
}
|
|
15825
|
-
async function
|
|
15826
|
-
return
|
|
18323
|
+
async function hashContent3(content2) {
|
|
18324
|
+
return createHash3("sha256").update(content2).digest("hex");
|
|
15827
18325
|
}
|
|
15828
18326
|
async function hashBundle2(files) {
|
|
15829
18327
|
const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));
|
|
15830
18328
|
const manifestParts = [];
|
|
15831
18329
|
for (const file of sorted) {
|
|
15832
|
-
const hash = await
|
|
18330
|
+
const hash = await hashContent3(file.content);
|
|
15833
18331
|
manifestParts.push(`${file.path}:${hash}`);
|
|
15834
18332
|
}
|
|
15835
|
-
return
|
|
18333
|
+
return hashContent3(manifestParts.join(`
|
|
15836
18334
|
`));
|
|
15837
18335
|
}
|
|
18336
|
+
|
|
18337
|
+
// src/self-update/index.ts
|
|
18338
|
+
function shouldCheckForUpdate() {
|
|
18339
|
+
if (process.env.OCX_SELF_UPDATE === "off")
|
|
18340
|
+
return false;
|
|
18341
|
+
if (parseEnvBool(process.env.OCX_NO_UPDATE_CHECK, false))
|
|
18342
|
+
return false;
|
|
18343
|
+
if (process.env.CI)
|
|
18344
|
+
return false;
|
|
18345
|
+
if (!process.stdout.isTTY)
|
|
18346
|
+
return false;
|
|
18347
|
+
return true;
|
|
18348
|
+
}
|
|
18349
|
+
function registerUpdateCheckHook(program2) {
|
|
18350
|
+
program2.hook("postAction", async (thisCommand) => {
|
|
18351
|
+
if (thisCommand.name() === "update" && thisCommand.parent?.name() === "self") {
|
|
18352
|
+
return;
|
|
18353
|
+
}
|
|
18354
|
+
if (!shouldCheckForUpdate())
|
|
18355
|
+
return;
|
|
18356
|
+
try {
|
|
18357
|
+
const result = await checkForUpdate();
|
|
18358
|
+
if (result?.updateAvailable) {
|
|
18359
|
+
notifyUpdate(result.current, result.latest);
|
|
18360
|
+
}
|
|
18361
|
+
} catch {}
|
|
18362
|
+
});
|
|
18363
|
+
}
|
|
15838
18364
|
// src/index.ts
|
|
15839
|
-
var version = "1.
|
|
18365
|
+
var version = "1.3.0";
|
|
15840
18366
|
async function main2() {
|
|
15841
18367
|
const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version);
|
|
15842
18368
|
registerInitCommand(program2);
|
|
@@ -15847,6 +18373,8 @@ async function main2() {
|
|
|
15847
18373
|
registerRegistryCommand(program2);
|
|
15848
18374
|
registerBuildCommand(program2);
|
|
15849
18375
|
registerGhostCommand(program2);
|
|
18376
|
+
registerSelfCommand(program2);
|
|
18377
|
+
registerUpdateCheckHook(program2);
|
|
15850
18378
|
await program2.parseAsync(process.argv);
|
|
15851
18379
|
}
|
|
15852
18380
|
if (import.meta.main) {
|
|
@@ -15863,4 +18391,4 @@ export {
|
|
|
15863
18391
|
buildRegistry
|
|
15864
18392
|
};
|
|
15865
18393
|
|
|
15866
|
-
//# debugId=
|
|
18394
|
+
//# debugId=FE5CBBF0E272CBE164756E2164756E21
|