perchai-cli 2.4.11 → 2.4.13
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/perch.mjs +1885 -456
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -5198,8 +5198,8 @@ var require_xlsx = __commonJS({
|
|
|
5198
5198
|
}
|
|
5199
5199
|
return L.length - R.length;
|
|
5200
5200
|
}
|
|
5201
|
-
function
|
|
5202
|
-
if (p.charAt(p.length - 1) == "/") return p.slice(0, -1).indexOf("/") === -1 ? p :
|
|
5201
|
+
function dirname2(p) {
|
|
5202
|
+
if (p.charAt(p.length - 1) == "/") return p.slice(0, -1).indexOf("/") === -1 ? p : dirname2(p.slice(0, -1));
|
|
5203
5203
|
var c = p.lastIndexOf("/");
|
|
5204
5204
|
return c === -1 ? p : p.slice(0, c + 1);
|
|
5205
5205
|
}
|
|
@@ -5620,7 +5620,7 @@ var require_xlsx = __commonJS({
|
|
|
5620
5620
|
data.push([cfb.FullPaths[i2], cfb.FileIndex[i2]]);
|
|
5621
5621
|
}
|
|
5622
5622
|
for (i2 = 0; i2 < data.length; ++i2) {
|
|
5623
|
-
var dad =
|
|
5623
|
+
var dad = dirname2(data[i2][0]);
|
|
5624
5624
|
s = fullPaths[dad];
|
|
5625
5625
|
if (!s) {
|
|
5626
5626
|
data.push([dad, {
|
|
@@ -5656,13 +5656,13 @@ var require_xlsx = __commonJS({
|
|
|
5656
5656
|
elt.size = 0;
|
|
5657
5657
|
elt.type = 5;
|
|
5658
5658
|
} else if (nm.slice(-1) == "/") {
|
|
5659
|
-
for (j = i2 + 1; j < data.length; ++j) if (
|
|
5659
|
+
for (j = i2 + 1; j < data.length; ++j) if (dirname2(cfb.FullPaths[j]) == nm) break;
|
|
5660
5660
|
elt.C = j >= data.length ? -1 : j;
|
|
5661
|
-
for (j = i2 + 1; j < data.length; ++j) if (
|
|
5661
|
+
for (j = i2 + 1; j < data.length; ++j) if (dirname2(cfb.FullPaths[j]) == dirname2(nm)) break;
|
|
5662
5662
|
elt.R = j >= data.length ? -1 : j;
|
|
5663
5663
|
elt.type = 1;
|
|
5664
5664
|
} else {
|
|
5665
|
-
if (
|
|
5665
|
+
if (dirname2(cfb.FullPaths[i2 + 1] || "") == dirname2(nm)) elt.R = i2 + 1;
|
|
5666
5666
|
elt.type = 2;
|
|
5667
5667
|
}
|
|
5668
5668
|
}
|
|
@@ -41950,11 +41950,11 @@ var require_html2canvas = __commonJS({
|
|
|
41950
41950
|
};
|
|
41951
41951
|
function __awaiter3(thisArg, _arguments, P, generator) {
|
|
41952
41952
|
function adopt(value) {
|
|
41953
|
-
return value instanceof P ? value : new P(function(
|
|
41954
|
-
|
|
41953
|
+
return value instanceof P ? value : new P(function(resolve5) {
|
|
41954
|
+
resolve5(value);
|
|
41955
41955
|
});
|
|
41956
41956
|
}
|
|
41957
|
-
return new (P || (P = Promise))(function(
|
|
41957
|
+
return new (P || (P = Promise))(function(resolve5, reject2) {
|
|
41958
41958
|
function fulfilled(value) {
|
|
41959
41959
|
try {
|
|
41960
41960
|
step(generator.next(value));
|
|
@@ -41970,7 +41970,7 @@ var require_html2canvas = __commonJS({
|
|
|
41970
41970
|
}
|
|
41971
41971
|
}
|
|
41972
41972
|
function step(result2) {
|
|
41973
|
-
result2.done ?
|
|
41973
|
+
result2.done ? resolve5(result2.value) : adopt(result2.value).then(fulfilled, rejected);
|
|
41974
41974
|
}
|
|
41975
41975
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
41976
41976
|
});
|
|
@@ -43962,16 +43962,16 @@ var require_html2canvas = __commonJS({
|
|
|
43962
43962
|
[width, 0],
|
|
43963
43963
|
[width, height]
|
|
43964
43964
|
];
|
|
43965
|
-
return corners.reduce(function(
|
|
43965
|
+
return corners.reduce(function(stat2, corner) {
|
|
43966
43966
|
var cx = corner[0], cy = corner[1];
|
|
43967
43967
|
var d = distance(x - cx, y - cy);
|
|
43968
|
-
if (closest ? d <
|
|
43968
|
+
if (closest ? d < stat2.optimumDistance : d > stat2.optimumDistance) {
|
|
43969
43969
|
return {
|
|
43970
43970
|
optimumCorner: corner,
|
|
43971
43971
|
optimumDistance: d
|
|
43972
43972
|
};
|
|
43973
43973
|
}
|
|
43974
|
-
return
|
|
43974
|
+
return stat2;
|
|
43975
43975
|
}, {
|
|
43976
43976
|
optimumDistance: closest ? Infinity : -Infinity,
|
|
43977
43977
|
optimumCorner: null
|
|
@@ -46099,10 +46099,10 @@ var require_html2canvas = __commonJS({
|
|
|
46099
46099
|
return svg;
|
|
46100
46100
|
};
|
|
46101
46101
|
var loadSerializedSVG$1 = function(svg) {
|
|
46102
|
-
return new Promise(function(
|
|
46102
|
+
return new Promise(function(resolve5, reject2) {
|
|
46103
46103
|
var img = new Image();
|
|
46104
46104
|
img.onload = function() {
|
|
46105
|
-
return
|
|
46105
|
+
return resolve5(img);
|
|
46106
46106
|
};
|
|
46107
46107
|
img.onerror = reject2;
|
|
46108
46108
|
img.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(new XMLSerializer().serializeToString(svg));
|
|
@@ -47464,24 +47464,24 @@ var require_html2canvas = __commonJS({
|
|
|
47464
47464
|
return cloneIframeContainer;
|
|
47465
47465
|
};
|
|
47466
47466
|
var imageReady = function(img) {
|
|
47467
|
-
return new Promise(function(
|
|
47467
|
+
return new Promise(function(resolve5) {
|
|
47468
47468
|
if (img.complete) {
|
|
47469
|
-
|
|
47469
|
+
resolve5();
|
|
47470
47470
|
return;
|
|
47471
47471
|
}
|
|
47472
47472
|
if (!img.src) {
|
|
47473
|
-
|
|
47473
|
+
resolve5();
|
|
47474
47474
|
return;
|
|
47475
47475
|
}
|
|
47476
|
-
img.onload =
|
|
47477
|
-
img.onerror =
|
|
47476
|
+
img.onload = resolve5;
|
|
47477
|
+
img.onerror = resolve5;
|
|
47478
47478
|
});
|
|
47479
47479
|
};
|
|
47480
47480
|
var imagesReady = function(document2) {
|
|
47481
47481
|
return Promise.all([].slice.call(document2.images, 0).map(imageReady));
|
|
47482
47482
|
};
|
|
47483
47483
|
var iframeLoader = function(iframe) {
|
|
47484
|
-
return new Promise(function(
|
|
47484
|
+
return new Promise(function(resolve5, reject2) {
|
|
47485
47485
|
var cloneWindow = iframe.contentWindow;
|
|
47486
47486
|
if (!cloneWindow) {
|
|
47487
47487
|
return reject2("No window assigned for iframe");
|
|
@@ -47492,7 +47492,7 @@ var require_html2canvas = __commonJS({
|
|
|
47492
47492
|
var interval = setInterval(function() {
|
|
47493
47493
|
if (documentClone.body.childNodes.length > 0 && documentClone.readyState === "complete") {
|
|
47494
47494
|
clearInterval(interval);
|
|
47495
|
-
|
|
47495
|
+
resolve5(iframe);
|
|
47496
47496
|
}
|
|
47497
47497
|
}, 50);
|
|
47498
47498
|
};
|
|
@@ -47631,10 +47631,10 @@ var require_html2canvas = __commonJS({
|
|
|
47631
47631
|
_a.label = 2;
|
|
47632
47632
|
case 2:
|
|
47633
47633
|
this.context.logger.debug("Added image " + key.substring(0, 256));
|
|
47634
|
-
return [4, new Promise(function(
|
|
47634
|
+
return [4, new Promise(function(resolve5, reject2) {
|
|
47635
47635
|
var img = new Image();
|
|
47636
47636
|
img.onload = function() {
|
|
47637
|
-
return
|
|
47637
|
+
return resolve5(img);
|
|
47638
47638
|
};
|
|
47639
47639
|
img.onerror = reject2;
|
|
47640
47640
|
if (isInlineBase64Image(src) || useCORS) {
|
|
@@ -47643,7 +47643,7 @@ var require_html2canvas = __commonJS({
|
|
|
47643
47643
|
img.src = src;
|
|
47644
47644
|
if (img.complete === true) {
|
|
47645
47645
|
setTimeout(function() {
|
|
47646
|
-
return
|
|
47646
|
+
return resolve5(img);
|
|
47647
47647
|
}, 500);
|
|
47648
47648
|
}
|
|
47649
47649
|
if (_this._options.imageTimeout > 0) {
|
|
@@ -47671,17 +47671,17 @@ var require_html2canvas = __commonJS({
|
|
|
47671
47671
|
throw new Error("No proxy defined");
|
|
47672
47672
|
}
|
|
47673
47673
|
var key = src.substring(0, 256);
|
|
47674
|
-
return new Promise(function(
|
|
47674
|
+
return new Promise(function(resolve5, reject2) {
|
|
47675
47675
|
var responseType = FEATURES.SUPPORT_RESPONSE_TYPE ? "blob" : "text";
|
|
47676
47676
|
var xhr = new XMLHttpRequest();
|
|
47677
47677
|
xhr.onload = function() {
|
|
47678
47678
|
if (xhr.status === 200) {
|
|
47679
47679
|
if (responseType === "text") {
|
|
47680
|
-
|
|
47680
|
+
resolve5(xhr.response);
|
|
47681
47681
|
} else {
|
|
47682
47682
|
var reader_1 = new FileReader();
|
|
47683
47683
|
reader_1.addEventListener("load", function() {
|
|
47684
|
-
return
|
|
47684
|
+
return resolve5(reader_1.result);
|
|
47685
47685
|
}, false);
|
|
47686
47686
|
reader_1.addEventListener("error", function(e2) {
|
|
47687
47687
|
return reject2(e2);
|
|
@@ -49496,10 +49496,10 @@ var require_html2canvas = __commonJS({
|
|
|
49496
49496
|
})(Renderer)
|
|
49497
49497
|
);
|
|
49498
49498
|
var loadSerializedSVG = function(svg) {
|
|
49499
|
-
return new Promise(function(
|
|
49499
|
+
return new Promise(function(resolve5, reject2) {
|
|
49500
49500
|
var img = new Image();
|
|
49501
49501
|
img.onload = function() {
|
|
49502
|
-
|
|
49502
|
+
resolve5(img);
|
|
49503
49503
|
};
|
|
49504
49504
|
img.onerror = reject2;
|
|
49505
49505
|
img.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(new XMLSerializer().serializeToString(svg));
|
|
@@ -51584,7 +51584,7 @@ var require_make_built_in = __commonJS({
|
|
|
51584
51584
|
var defineProperty = Object.defineProperty;
|
|
51585
51585
|
var stringSlice = uncurryThis("".slice);
|
|
51586
51586
|
var replace = uncurryThis("".replace);
|
|
51587
|
-
var
|
|
51587
|
+
var join2 = uncurryThis([].join);
|
|
51588
51588
|
var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
|
|
51589
51589
|
return defineProperty(function() {
|
|
51590
51590
|
}, "length", { value: 8 }).length !== 8;
|
|
@@ -51611,7 +51611,7 @@ var require_make_built_in = __commonJS({
|
|
|
51611
51611
|
}
|
|
51612
51612
|
var state = enforceInternalState(value);
|
|
51613
51613
|
if (!hasOwn(state, "source")) {
|
|
51614
|
-
state.source =
|
|
51614
|
+
state.source = join2(TEMPLATE, typeof name == "string" ? name : "");
|
|
51615
51615
|
}
|
|
51616
51616
|
return value;
|
|
51617
51617
|
};
|
|
@@ -52685,8 +52685,8 @@ var require_promise_constructor_detection = __commonJS({
|
|
|
52685
52685
|
if (!GLOBAL_CORE_JS_PROMISE && V8_VERSION === 66) return true;
|
|
52686
52686
|
if (IS_PURE && !(NativePromisePrototype["catch"] && NativePromisePrototype["finally"])) return true;
|
|
52687
52687
|
if (!V8_VERSION || V8_VERSION < 51 || !/native code/.test(PROMISE_CONSTRUCTOR_SOURCE)) {
|
|
52688
|
-
var promise = new NativePromiseConstructor(function(
|
|
52689
|
-
|
|
52688
|
+
var promise = new NativePromiseConstructor(function(resolve5) {
|
|
52689
|
+
resolve5(1);
|
|
52690
52690
|
});
|
|
52691
52691
|
var FakePromise = function(exec3) {
|
|
52692
52692
|
exec3(function() {
|
|
@@ -52716,13 +52716,13 @@ var require_new_promise_capability = __commonJS({
|
|
|
52716
52716
|
var aCallable = require_a_callable();
|
|
52717
52717
|
var $TypeError = TypeError;
|
|
52718
52718
|
var PromiseCapability = function(C) {
|
|
52719
|
-
var
|
|
52719
|
+
var resolve5, reject2;
|
|
52720
52720
|
this.promise = new C(function($$resolve, $$reject) {
|
|
52721
|
-
if (
|
|
52722
|
-
|
|
52721
|
+
if (resolve5 !== void 0 || reject2 !== void 0) throw new $TypeError("Bad Promise constructor");
|
|
52722
|
+
resolve5 = $$resolve;
|
|
52723
52723
|
reject2 = $$reject;
|
|
52724
52724
|
});
|
|
52725
|
-
this.resolve = aCallable(
|
|
52725
|
+
this.resolve = aCallable(resolve5);
|
|
52726
52726
|
this.reject = aCallable(reject2);
|
|
52727
52727
|
};
|
|
52728
52728
|
module2.exports.f = function(C) {
|
|
@@ -52793,7 +52793,7 @@ var require_es_promise_constructor = __commonJS({
|
|
|
52793
52793
|
var value = state.value;
|
|
52794
52794
|
var ok = state.state === FULFILLED;
|
|
52795
52795
|
var handler = ok ? reaction.ok : reaction.fail;
|
|
52796
|
-
var
|
|
52796
|
+
var resolve5 = reaction.resolve;
|
|
52797
52797
|
var reject2 = reaction.reject;
|
|
52798
52798
|
var domain = reaction.domain;
|
|
52799
52799
|
var result2, then, exited;
|
|
@@ -52815,8 +52815,8 @@ var require_es_promise_constructor = __commonJS({
|
|
|
52815
52815
|
if (result2 === reaction.promise) {
|
|
52816
52816
|
reject2(new TypeError2("Promise-chain cycle"));
|
|
52817
52817
|
} else if (then = isThenable(result2)) {
|
|
52818
|
-
call(then, result2,
|
|
52819
|
-
} else
|
|
52818
|
+
call(then, result2, resolve5, reject2);
|
|
52819
|
+
} else resolve5(result2);
|
|
52820
52820
|
} else reject2(value);
|
|
52821
52821
|
} catch (error) {
|
|
52822
52822
|
if (domain && !exited) domain.exit();
|
|
@@ -52972,8 +52972,8 @@ var require_es_promise_constructor = __commonJS({
|
|
|
52972
52972
|
if (!NATIVE_PROMISE_SUBCLASSING) {
|
|
52973
52973
|
defineBuiltIn(NativePromisePrototype, "then", function then(onFulfilled, onRejected) {
|
|
52974
52974
|
var that = this;
|
|
52975
|
-
return new PromiseConstructor(function(
|
|
52976
|
-
call(nativeThen, that,
|
|
52975
|
+
return new PromiseConstructor(function(resolve5, reject2) {
|
|
52976
|
+
call(nativeThen, that, resolve5, reject2);
|
|
52977
52977
|
}).then(onFulfilled, onRejected);
|
|
52978
52978
|
}, { unsafe: true });
|
|
52979
52979
|
}
|
|
@@ -53233,7 +53233,7 @@ var require_es_promise_all = __commonJS({
|
|
|
53233
53233
|
all: function all(iterable) {
|
|
53234
53234
|
var C = this;
|
|
53235
53235
|
var capability = newPromiseCapabilityModule.f(C);
|
|
53236
|
-
var
|
|
53236
|
+
var resolve5 = capability.resolve;
|
|
53237
53237
|
var reject2 = capability.reject;
|
|
53238
53238
|
var result2 = perform(function() {
|
|
53239
53239
|
var $promiseResolve = aCallable(C.resolve);
|
|
@@ -53248,10 +53248,10 @@ var require_es_promise_all = __commonJS({
|
|
|
53248
53248
|
if (alreadyCalled) return;
|
|
53249
53249
|
alreadyCalled = true;
|
|
53250
53250
|
values2[index] = value;
|
|
53251
|
-
--remaining ||
|
|
53251
|
+
--remaining || resolve5(values2);
|
|
53252
53252
|
}, reject2);
|
|
53253
53253
|
});
|
|
53254
|
-
--remaining ||
|
|
53254
|
+
--remaining || resolve5(values2);
|
|
53255
53255
|
});
|
|
53256
53256
|
if (result2.error) reject2(result2.value);
|
|
53257
53257
|
return capability.promise;
|
|
@@ -53345,8 +53345,8 @@ var require_promise_resolve = __commonJS({
|
|
|
53345
53345
|
anObject(C);
|
|
53346
53346
|
if (isObject4(x) && x.constructor === C) return x;
|
|
53347
53347
|
var promiseCapability = newPromiseCapability.f(C);
|
|
53348
|
-
var
|
|
53349
|
-
|
|
53348
|
+
var resolve5 = promiseCapability.resolve;
|
|
53349
|
+
resolve5(x);
|
|
53350
53350
|
return promiseCapability.promise;
|
|
53351
53351
|
};
|
|
53352
53352
|
}
|
|
@@ -53365,7 +53365,7 @@ var require_es_promise_resolve = __commonJS({
|
|
|
53365
53365
|
var PromiseConstructorWrapper = getBuiltIn("Promise");
|
|
53366
53366
|
var CHECK_WRAPPER = IS_PURE && !FORCED_PROMISE_CONSTRUCTOR;
|
|
53367
53367
|
$2({ target: "Promise", stat: true, forced: IS_PURE || FORCED_PROMISE_CONSTRUCTOR }, {
|
|
53368
|
-
resolve: function
|
|
53368
|
+
resolve: function resolve5(x) {
|
|
53369
53369
|
return promiseResolve(CHECK_WRAPPER && this === PromiseConstructorWrapper ? NativePromiseConstructor : this, x);
|
|
53370
53370
|
}
|
|
53371
53371
|
});
|
|
@@ -54854,7 +54854,7 @@ var require_es_array_join = __commonJS({
|
|
|
54854
54854
|
var ES3_STRINGS = IndexedObject !== Object;
|
|
54855
54855
|
var FORCED = ES3_STRINGS || !arrayMethodIsStrict("join", ",");
|
|
54856
54856
|
$2({ target: "Array", proto: true, forced: FORCED }, {
|
|
54857
|
-
join: function
|
|
54857
|
+
join: function join2(separator) {
|
|
54858
54858
|
return nativeJoin(toIndexedObject(this), separator === void 0 ? "," : separator);
|
|
54859
54859
|
}
|
|
54860
54860
|
});
|
|
@@ -58983,8 +58983,8 @@ var require_lib2 = __commonJS({
|
|
|
58983
58983
|
var FRAMERATE = this.FRAMERATE, mouse = this.mouse;
|
|
58984
58984
|
var frameDuration = 1e3 / FRAMERATE;
|
|
58985
58985
|
this.frameDuration = frameDuration;
|
|
58986
|
-
this.readyPromise = new Promise(function(
|
|
58987
|
-
_this.resolveReady =
|
|
58986
|
+
this.readyPromise = new Promise(function(resolve5) {
|
|
58987
|
+
_this.resolveReady = resolve5;
|
|
58988
58988
|
});
|
|
58989
58989
|
if (this.isReady()) {
|
|
58990
58990
|
this.render(element, ignoreDimensions, ignoreClear, scaleWidth, scaleHeight, offsetX, offsetY);
|
|
@@ -65022,9 +65022,9 @@ var require_lib2 = __commonJS({
|
|
|
65022
65022
|
if (anonymousCrossOrigin) {
|
|
65023
65023
|
image2.crossOrigin = "Anonymous";
|
|
65024
65024
|
}
|
|
65025
|
-
return _context.abrupt("return", new Promise(function(
|
|
65025
|
+
return _context.abrupt("return", new Promise(function(resolve5, reject2) {
|
|
65026
65026
|
image2.onload = function() {
|
|
65027
|
-
|
|
65027
|
+
resolve5(image2);
|
|
65028
65028
|
};
|
|
65029
65029
|
image2.onerror = function(_event, _source, _lineno, _colno, error) {
|
|
65030
65030
|
reject2(error);
|
|
@@ -73320,7 +73320,7 @@ async function walk(rootPath, currentPath, files) {
|
|
|
73320
73320
|
continue;
|
|
73321
73321
|
}
|
|
73322
73322
|
if (!entry.isFile()) continue;
|
|
73323
|
-
const
|
|
73323
|
+
const stat2 = await fs3.promises.stat(fullPath);
|
|
73324
73324
|
const extension2 = path3.extname(entry.name).toLowerCase();
|
|
73325
73325
|
const role = sensitivity.sensitive ? "secret_sensitive" : classifyFileRole(entry.name, relativePath);
|
|
73326
73326
|
const ignored = sensitivity.sensitive;
|
|
@@ -73329,11 +73329,11 @@ async function walk(rootPath, currentPath, files) {
|
|
|
73329
73329
|
relativePath,
|
|
73330
73330
|
fileName: entry.name,
|
|
73331
73331
|
extension: extension2,
|
|
73332
|
-
sizeBytes:
|
|
73332
|
+
sizeBytes: stat2.size,
|
|
73333
73333
|
role,
|
|
73334
73334
|
ignored,
|
|
73335
73335
|
ignoreReason: sensitivity.reason,
|
|
73336
|
-
textSnippet: ignored ? void 0 : await safeTextSnippet(fullPath, extension2,
|
|
73336
|
+
textSnippet: ignored ? void 0 : await safeTextSnippet(fullPath, extension2, stat2.size)
|
|
73337
73337
|
});
|
|
73338
73338
|
}
|
|
73339
73339
|
}
|
|
@@ -75408,8 +75408,8 @@ async function listDirs(root2) {
|
|
|
75408
75408
|
}
|
|
75409
75409
|
async function fileExists(filePath) {
|
|
75410
75410
|
try {
|
|
75411
|
-
const
|
|
75412
|
-
return
|
|
75411
|
+
const stat2 = await fs7.promises.stat(filePath);
|
|
75412
|
+
return stat2.isFile();
|
|
75413
75413
|
} catch {
|
|
75414
75414
|
return false;
|
|
75415
75415
|
}
|
|
@@ -75566,7 +75566,6 @@ var init_payroll = __esm({
|
|
|
75566
75566
|
// lib/perchBusinessTools/index.ts
|
|
75567
75567
|
var init_perchBusinessTools = __esm({
|
|
75568
75568
|
"lib/perchBusinessTools/index.ts"() {
|
|
75569
|
-
"use strict";
|
|
75570
75569
|
init_generateAPAuditPacket();
|
|
75571
75570
|
init_inventoryFolder();
|
|
75572
75571
|
init_loadBusinessTables();
|
|
@@ -80628,13 +80627,13 @@ function buildDesktopContextSection(input) {
|
|
|
80628
80627
|
label: "CLI workspace",
|
|
80629
80628
|
content: [
|
|
80630
80629
|
"## CLI local workspace",
|
|
80631
|
-
"Perch is running from a terminal. Local filesystem, shell, sandbox-code, and AP evidence tools are available through the CLI local
|
|
80630
|
+
"Perch is running from a terminal. Local filesystem, shell, sandbox-code, and AP evidence tools are available through the CLI local runtime.",
|
|
80632
80631
|
input.activeRootPath?.trim() ? `Workspace root: ${input.activeRootPath}. Treat relative paths as relative to this root.` : "Workspace root: current terminal directory.",
|
|
80633
|
-
"
|
|
80632
|
+
"GUI-only services are not connected here: embedded browser, Google/Gmail/Calendar delivery, Desktop RAG indexing, MCP Desktop servers, and project memory writes are unavailable unless the desktop app is running.",
|
|
80634
80633
|
localReadTools.length > 0 ? `Read tools: ${localReadTools.join(", ")}.` : "Read tools: none exposed for this turn.",
|
|
80635
80634
|
localWriteTools.length > 0 ? `Write/command tools: ${localWriteTools.join(", ")}. These are governed by the selected permission mode and command policy.` : "Write/command tools: none exposed for this turn."
|
|
80636
80635
|
].join("\n"),
|
|
80637
|
-
reason: "Terminal local
|
|
80636
|
+
reason: "Terminal local runtime state and CLI tool availability for this turn.",
|
|
80638
80637
|
sourcePath: input.activeRootPath,
|
|
80639
80638
|
metadata: {
|
|
80640
80639
|
desktopConnected: false,
|
|
@@ -80649,7 +80648,7 @@ function buildDesktopContextSection(input) {
|
|
|
80649
80648
|
lane: "desktop",
|
|
80650
80649
|
label: "Desktop workspace",
|
|
80651
80650
|
content: "",
|
|
80652
|
-
reason: "
|
|
80651
|
+
reason: "Local workspace runtime is unavailable in browser mode.",
|
|
80653
80652
|
sourcePath: input.activeRootPath,
|
|
80654
80653
|
skipped: true,
|
|
80655
80654
|
metadata: { desktopConnected: false }
|
|
@@ -80736,7 +80735,7 @@ function buildDesktopContextSection(input) {
|
|
|
80736
80735
|
label: "Desktop workspace",
|
|
80737
80736
|
content: [
|
|
80738
80737
|
"## Desktop environment",
|
|
80739
|
-
"Desktop
|
|
80738
|
+
"Desktop local runtime is connected. Local filesystem tools are available to the operator runtime.",
|
|
80740
80739
|
input.activeRootPath?.trim() ? `Optional folder scope: ${input.activeRootPath} (you are NOT limited to it \u2014 absolute paths anywhere in the user's home work directly).` : "No folder scope is selected, and none is needed. When the user gives a file path, USE IT DIRECTLY \u2014 call readLocalFile / glob / grep / visionInspect with the absolute path (e.g. /Users/you/Desktop/shot.png). Full-access policy already allows any path in the user's home. NEVER tell the user to select or approve a folder, and NEVER refuse a file because no folder is selected.",
|
|
80741
80740
|
`Visible local sources: ${totalVisibleFiles}`,
|
|
80742
80741
|
input.localSourcesMeta?.refreshedAt ? `Local source snapshot refreshed: ${input.localSourcesMeta.refreshedAt}` : null,
|
|
@@ -80754,7 +80753,7 @@ function buildDesktopContextSection(input) {
|
|
|
80754
80753
|
availableReadTools.length > 0 ? `Read tools: ${availableReadTools.join(", ")}.` : "Read tools: none exposed for this turn.",
|
|
80755
80754
|
availableWriteTools.length > 0 ? `Write/command tools: ${availableWriteTools.join(", ")}. These are governed by the selected permission mode and command policy.` : "Write/command tools: none exposed for this turn."
|
|
80756
80755
|
].filter(Boolean).join("\n"),
|
|
80757
|
-
reason: "
|
|
80756
|
+
reason: "Local runtime state, optional folder scope, and tool availability for this turn.",
|
|
80758
80757
|
sourcePath: input.activeRootPath,
|
|
80759
80758
|
metadata: {
|
|
80760
80759
|
desktopConnected: true,
|
|
@@ -81720,7 +81719,7 @@ function buildThreadLedgerItemsFromTurn(input) {
|
|
|
81720
81719
|
kind: "context_boundary",
|
|
81721
81720
|
ts: event.ts,
|
|
81722
81721
|
runId: input.runId,
|
|
81723
|
-
summary: `Context compacted from ${event.tokensBefore} to ${event.tokensAfter} tokens
|
|
81722
|
+
summary: `Context compacted from ${event.tokensBefore} to ${event.tokensAfter} tokens` + (event.targetTokens ? ` (target ${event.targetTokens}).` : "."),
|
|
81724
81723
|
resultPreview: truncate3(event.summary, MAX_TEXT)
|
|
81725
81724
|
});
|
|
81726
81725
|
} else if (event.type === "live_card_end" && event.receipt) {
|
|
@@ -82300,6 +82299,8 @@ function sanitizePendingActionPayload(value) {
|
|
|
82300
82299
|
}
|
|
82301
82300
|
function parseContextCompaction(value) {
|
|
82302
82301
|
if (!isRecord4(value)) return null;
|
|
82302
|
+
const compactBoundary = parseCompactBoundary(value.compactBoundary);
|
|
82303
|
+
const compactionReport = parseCompactionReport(value.compactionReport);
|
|
82303
82304
|
return {
|
|
82304
82305
|
compactConversation: value.compactConversation === true,
|
|
82305
82306
|
dropNotFoundRows: value.dropNotFoundRows === true,
|
|
@@ -82310,9 +82311,38 @@ function parseContextCompaction(value) {
|
|
|
82310
82311
|
autoCompactedAtIso: typeof value.autoCompactedAtIso === "string" ? value.autoCompactedAtIso : void 0,
|
|
82311
82312
|
autoCompactedMessageCount: asFiniteNonNegativeInt(value.autoCompactedMessageCount) ?? void 0,
|
|
82312
82313
|
compactedSummary: typeof value.compactedSummary === "string" ? value.compactedSummary : void 0,
|
|
82313
|
-
effectiveContextLimitTokens: asFiniteNonNegativeInt(value.effectiveContextLimitTokens) ?? void 0
|
|
82314
|
+
effectiveContextLimitTokens: asFiniteNonNegativeInt(value.effectiveContextLimitTokens) ?? void 0,
|
|
82315
|
+
...compactBoundary ? { compactBoundary } : {},
|
|
82316
|
+
...compactionReport ? { compactionReport } : {}
|
|
82314
82317
|
};
|
|
82315
82318
|
}
|
|
82319
|
+
function parseCompactBoundary(value) {
|
|
82320
|
+
if (!isRecord4(value)) return void 0;
|
|
82321
|
+
const kind = value.kind === "manual" ? "manual" : value.kind === "auto" ? "auto" : null;
|
|
82322
|
+
const compactedAtIso = typeof value.compactedAtIso === "string" ? value.compactedAtIso : null;
|
|
82323
|
+
if (!kind || !compactedAtIso) return void 0;
|
|
82324
|
+
return {
|
|
82325
|
+
kind,
|
|
82326
|
+
compactedAtIso,
|
|
82327
|
+
compactedThroughMessageId: typeof value.compactedThroughMessageId === "string" ? value.compactedThroughMessageId : null,
|
|
82328
|
+
compactedThroughMessageCreatedAt: typeof value.compactedThroughMessageCreatedAt === "string" ? value.compactedThroughMessageCreatedAt : null,
|
|
82329
|
+
compactedThroughWireIndex: asFiniteNonNegativeInt(value.compactedThroughWireIndex)
|
|
82330
|
+
};
|
|
82331
|
+
}
|
|
82332
|
+
function parseCompactionReport(value) {
|
|
82333
|
+
if (!isRecord4(value)) return void 0;
|
|
82334
|
+
const parsed = {
|
|
82335
|
+
tokensBefore: asFiniteNonNegativeInt(value.tokensBefore) ?? void 0,
|
|
82336
|
+
tokensAfter: asFiniteNonNegativeInt(value.tokensAfter) ?? void 0,
|
|
82337
|
+
targetTokens: asFiniteNonNegativeInt(value.targetTokens) ?? void 0,
|
|
82338
|
+
summaryTokens: asFiniteNonNegativeInt(value.summaryTokens) ?? void 0,
|
|
82339
|
+
recentTailTokens: asFiniteNonNegativeInt(value.recentTailTokens) ?? void 0,
|
|
82340
|
+
recentTailMessages: asFiniteNonNegativeInt(value.recentTailMessages) ?? void 0,
|
|
82341
|
+
summarizedMessages: asFiniteNonNegativeInt(value.summarizedMessages) ?? void 0,
|
|
82342
|
+
restoredToolsOrFiles: asFiniteNonNegativeInt(value.restoredToolsOrFiles) ?? void 0
|
|
82343
|
+
};
|
|
82344
|
+
return Object.values(parsed).some((entry) => typeof entry === "number") ? parsed : void 0;
|
|
82345
|
+
}
|
|
82316
82346
|
function parseWorkerRuns(value) {
|
|
82317
82347
|
if (!Array.isArray(value)) return void 0;
|
|
82318
82348
|
const parsed = [];
|
|
@@ -82425,6 +82455,7 @@ function parseContextMetrics(value) {
|
|
|
82425
82455
|
const consecutiveAutoCompactFailures = asFiniteNonNegativeInt(value.consecutiveAutoCompactFailures);
|
|
82426
82456
|
const lastApiUsage = parseModelUsage(value.lastApiUsage);
|
|
82427
82457
|
const turnApiUsage = parseModelUsage(value.turnApiUsage);
|
|
82458
|
+
const compactionReport = parseCompactionReport(value.compactionReport);
|
|
82428
82459
|
return {
|
|
82429
82460
|
threadContextTokens,
|
|
82430
82461
|
latestSendTokens,
|
|
@@ -82448,6 +82479,7 @@ function parseContextMetrics(value) {
|
|
|
82448
82479
|
...consecutiveAutoCompactFailures !== null ? { consecutiveAutoCompactFailures } : {},
|
|
82449
82480
|
...typeof value.autoCompactedAtIso === "string" ? { autoCompactedAtIso: value.autoCompactedAtIso } : {},
|
|
82450
82481
|
...asFiniteNonNegativeInt(value.autoCompactedMessageCount) !== null ? { autoCompactedMessageCount: asFiniteNonNegativeInt(value.autoCompactedMessageCount) } : {},
|
|
82482
|
+
...compactionReport ? { compactionReport } : {},
|
|
82451
82483
|
resetAtIso: typeof value.resetAtIso === "string" ? value.resetAtIso : null,
|
|
82452
82484
|
updatedAtIso: typeof value.updatedAtIso === "string" ? value.updatedAtIso : (/* @__PURE__ */ new Date()).toISOString()
|
|
82453
82485
|
};
|
|
@@ -82895,7 +82927,6 @@ function truncateHistoryLine(value, max2) {
|
|
|
82895
82927
|
}
|
|
82896
82928
|
var init_operatorTruth = __esm({
|
|
82897
82929
|
"features/perchTerminal/runtime/operatorTruth.ts"() {
|
|
82898
|
-
"use strict";
|
|
82899
82930
|
}
|
|
82900
82931
|
});
|
|
82901
82932
|
|
|
@@ -82906,7 +82937,17 @@ function buildMessageHistory(recentMessages, currentInput, options) {
|
|
|
82906
82937
|
const hasCompactedSummary = compactedSummary.length > 0;
|
|
82907
82938
|
const shouldUseCompactedHistory = options?.compactConversation === true && hasCompactedSummary;
|
|
82908
82939
|
const keepCount = options?.keepCount ?? (shouldUseCompactedHistory ? 12 : recentMessages.length);
|
|
82909
|
-
const sourceMessages = shouldUseCompactedHistory ?
|
|
82940
|
+
const sourceMessages = shouldUseCompactedHistory ? selectRecentHistoryTail(
|
|
82941
|
+
filterMessagesAfterCompactBoundary(recentMessages, {
|
|
82942
|
+
compactedThroughMessageId: options?.compactedThroughMessageId,
|
|
82943
|
+
compactedThroughMessageCreatedAt: options?.compactedThroughMessageCreatedAt
|
|
82944
|
+
}),
|
|
82945
|
+
{
|
|
82946
|
+
tokenTarget: options?.recentTailTokenTarget,
|
|
82947
|
+
fallbackKeepCount: keepCount,
|
|
82948
|
+
minMessages: Math.min(DEFAULT_COMPACTED_MIN_RECENT_MESSAGES, keepCount)
|
|
82949
|
+
}
|
|
82950
|
+
) : recentMessages;
|
|
82910
82951
|
if (hasCompactedSummary) {
|
|
82911
82952
|
history.push({
|
|
82912
82953
|
role: "user",
|
|
@@ -82955,6 +82996,47 @@ ${compactedSummary}`
|
|
|
82955
82996
|
history.push({ role: "user", content: currentInput });
|
|
82956
82997
|
return history;
|
|
82957
82998
|
}
|
|
82999
|
+
function filterMessagesAfterCompactBoundary(messages, boundary) {
|
|
83000
|
+
const boundaryId = boundary.compactedThroughMessageId?.trim();
|
|
83001
|
+
if (boundaryId) {
|
|
83002
|
+
const idx = messages.findIndex((message) => message.id === boundaryId);
|
|
83003
|
+
if (idx >= 0) return messages.slice(idx + 1);
|
|
83004
|
+
}
|
|
83005
|
+
const boundaryAt = boundary.compactedThroughMessageCreatedAt?.trim();
|
|
83006
|
+
if (boundaryAt) {
|
|
83007
|
+
const boundaryMs = Date.parse(boundaryAt);
|
|
83008
|
+
if (Number.isFinite(boundaryMs)) {
|
|
83009
|
+
return messages.filter((message) => {
|
|
83010
|
+
const createdMs = Date.parse(message.createdAt);
|
|
83011
|
+
return !Number.isFinite(createdMs) || createdMs > boundaryMs;
|
|
83012
|
+
});
|
|
83013
|
+
}
|
|
83014
|
+
}
|
|
83015
|
+
return messages;
|
|
83016
|
+
}
|
|
83017
|
+
function selectRecentHistoryTail(messages, input) {
|
|
83018
|
+
const tokenTarget = typeof input.tokenTarget === "number" && Number.isFinite(input.tokenTarget) && input.tokenTarget > 0 ? Math.floor(input.tokenTarget) : null;
|
|
83019
|
+
if (!tokenTarget) {
|
|
83020
|
+
return messages.slice(-Math.max(1, input.fallbackKeepCount));
|
|
83021
|
+
}
|
|
83022
|
+
const minMessages = Math.max(1, input.minMessages ?? DEFAULT_COMPACTED_MIN_RECENT_MESSAGES);
|
|
83023
|
+
let startIndex = messages.length;
|
|
83024
|
+
let tokens = 0;
|
|
83025
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
83026
|
+
const msgTokens = estimateHistoryMessageTokens(messages[i]);
|
|
83027
|
+
const selectedCount = messages.length - startIndex;
|
|
83028
|
+
const mustKeep = selectedCount === 0;
|
|
83029
|
+
if (!mustKeep && tokens + msgTokens > tokenTarget) break;
|
|
83030
|
+
tokens += msgTokens;
|
|
83031
|
+
startIndex = i;
|
|
83032
|
+
if (selectedCount + 1 >= minMessages && tokens >= tokenTarget) break;
|
|
83033
|
+
}
|
|
83034
|
+
return messages.slice(startIndex);
|
|
83035
|
+
}
|
|
83036
|
+
function estimateHistoryMessageTokens(message) {
|
|
83037
|
+
const text = message.kind === "text" ? messageContentForModelHistory(message) : `[Plan: ${message.plan.title}] ${message.plan.goal}`;
|
|
83038
|
+
return Math.max(1, Math.ceil(`${message.kind}:${text}`.length / 4));
|
|
83039
|
+
}
|
|
82958
83040
|
function messageContentForModelHistory(msg) {
|
|
82959
83041
|
if (msg.role !== "assistant" || !msg.operatorState?.events?.length) {
|
|
82960
83042
|
return msg.text;
|
|
@@ -82966,11 +83048,14 @@ function messageContentForModelHistory(msg) {
|
|
|
82966
83048
|
turnSummary: msg.turnSummary
|
|
82967
83049
|
});
|
|
82968
83050
|
}
|
|
83051
|
+
var DEFAULT_COMPACTED_RECENT_TAIL_TOKENS, DEFAULT_COMPACTED_MIN_RECENT_MESSAGES;
|
|
82969
83052
|
var init_messageHistory = __esm({
|
|
82970
83053
|
"features/perchTerminal/runtime/messageContext/messageHistory.ts"() {
|
|
82971
83054
|
"use strict";
|
|
82972
83055
|
init_operatorTruth();
|
|
82973
83056
|
init_wireTranscript();
|
|
83057
|
+
DEFAULT_COMPACTED_RECENT_TAIL_TOKENS = 24e3;
|
|
83058
|
+
DEFAULT_COMPACTED_MIN_RECENT_MESSAGES = 4;
|
|
82974
83059
|
}
|
|
82975
83060
|
});
|
|
82976
83061
|
|
|
@@ -91612,6 +91697,9 @@ function assembleContext(input) {
|
|
|
91612
91697
|
{
|
|
91613
91698
|
compactConversation: contextCompaction?.compactConversation === true,
|
|
91614
91699
|
compactedSummary: contextCompaction?.compactedSummary ?? null,
|
|
91700
|
+
compactedThroughMessageId: contextCompaction?.compactBoundary?.compactedThroughMessageId ?? null,
|
|
91701
|
+
compactedThroughMessageCreatedAt: contextCompaction?.compactBoundary?.compactedThroughMessageCreatedAt ?? null,
|
|
91702
|
+
recentTailTokenTarget: contextCompaction?.compactionReport?.recentTailTokens ?? DEFAULT_COMPACTED_RECENT_TAIL_TOKENS,
|
|
91615
91703
|
wireReplayMessages: threadSession?.threadWireMessages ?? null,
|
|
91616
91704
|
wireReplayContextLimitTokens: input.contextLimitTokens ?? threadSession?.contextMetrics?.effectiveLimitTokens ?? null,
|
|
91617
91705
|
// Coordinator sessions reference planIds and worker completions from earlier
|
|
@@ -91740,7 +91828,7 @@ function assembleContext(input) {
|
|
|
91740
91828
|
);
|
|
91741
91829
|
if (!input.desktopConnected && input.cliLocalTools !== true) {
|
|
91742
91830
|
warnings.push(
|
|
91743
|
-
"
|
|
91831
|
+
"Local workspace runtime is not connected. Local workspace tools are unavailable in browser mode."
|
|
91744
91832
|
);
|
|
91745
91833
|
}
|
|
91746
91834
|
return {
|
|
@@ -93571,11 +93659,11 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
93571
93659
|
}
|
|
93572
93660
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
93573
93661
|
function adopt(value) {
|
|
93574
|
-
return value instanceof P ? value : new P(function(
|
|
93575
|
-
|
|
93662
|
+
return value instanceof P ? value : new P(function(resolve5) {
|
|
93663
|
+
resolve5(value);
|
|
93576
93664
|
});
|
|
93577
93665
|
}
|
|
93578
|
-
return new (P || (P = Promise))(function(
|
|
93666
|
+
return new (P || (P = Promise))(function(resolve5, reject2) {
|
|
93579
93667
|
function fulfilled(value) {
|
|
93580
93668
|
try {
|
|
93581
93669
|
step(generator.next(value));
|
|
@@ -93591,7 +93679,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
93591
93679
|
}
|
|
93592
93680
|
}
|
|
93593
93681
|
function step(result2) {
|
|
93594
|
-
result2.done ?
|
|
93682
|
+
result2.done ? resolve5(result2.value) : adopt(result2.value).then(fulfilled, rejected);
|
|
93595
93683
|
}
|
|
93596
93684
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
93597
93685
|
});
|
|
@@ -93782,14 +93870,14 @@ function __asyncValues(o) {
|
|
|
93782
93870
|
}, i);
|
|
93783
93871
|
function verb(n) {
|
|
93784
93872
|
i[n] = o[n] && function(v) {
|
|
93785
|
-
return new Promise(function(
|
|
93786
|
-
v = o[n](v), settle(
|
|
93873
|
+
return new Promise(function(resolve5, reject2) {
|
|
93874
|
+
v = o[n](v), settle(resolve5, reject2, v.done, v.value);
|
|
93787
93875
|
});
|
|
93788
93876
|
};
|
|
93789
93877
|
}
|
|
93790
|
-
function settle(
|
|
93878
|
+
function settle(resolve5, reject2, d, v) {
|
|
93791
93879
|
Promise.resolve(v).then(function(v2) {
|
|
93792
|
-
|
|
93880
|
+
resolve5({ value: v2, done: d });
|
|
93793
93881
|
}, reject2);
|
|
93794
93882
|
}
|
|
93795
93883
|
}
|
|
@@ -94404,18 +94492,18 @@ var require_dist = __commonJS({
|
|
|
94404
94492
|
}
|
|
94405
94493
|
};
|
|
94406
94494
|
function sleep2(ms, signal) {
|
|
94407
|
-
return new Promise((
|
|
94495
|
+
return new Promise((resolve5) => {
|
|
94408
94496
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
94409
|
-
|
|
94497
|
+
resolve5();
|
|
94410
94498
|
return;
|
|
94411
94499
|
}
|
|
94412
94500
|
const id = setTimeout(() => {
|
|
94413
94501
|
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
94414
|
-
|
|
94502
|
+
resolve5();
|
|
94415
94503
|
}, ms);
|
|
94416
94504
|
function onAbort() {
|
|
94417
94505
|
clearTimeout(id);
|
|
94418
|
-
|
|
94506
|
+
resolve5();
|
|
94419
94507
|
}
|
|
94420
94508
|
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
|
|
94421
94509
|
});
|
|
@@ -102425,15 +102513,15 @@ var require_RealtimeChannel = __commonJS({
|
|
|
102425
102513
|
}
|
|
102426
102514
|
}
|
|
102427
102515
|
} else {
|
|
102428
|
-
return new Promise((
|
|
102516
|
+
return new Promise((resolve5) => {
|
|
102429
102517
|
var _a2, _b2, _c;
|
|
102430
102518
|
const push2 = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
|
|
102431
102519
|
if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
|
|
102432
|
-
|
|
102520
|
+
resolve5("ok");
|
|
102433
102521
|
}
|
|
102434
|
-
push2.receive("ok", () =>
|
|
102435
|
-
push2.receive("error", () =>
|
|
102436
|
-
push2.receive("timeout", () =>
|
|
102522
|
+
push2.receive("ok", () => resolve5("ok"));
|
|
102523
|
+
push2.receive("error", () => resolve5("error"));
|
|
102524
|
+
push2.receive("timeout", () => resolve5("timed out"));
|
|
102437
102525
|
});
|
|
102438
102526
|
}
|
|
102439
102527
|
}
|
|
@@ -102458,8 +102546,8 @@ var require_RealtimeChannel = __commonJS({
|
|
|
102458
102546
|
* @category Realtime
|
|
102459
102547
|
*/
|
|
102460
102548
|
async unsubscribe(timeout = this.timeout) {
|
|
102461
|
-
return new Promise((
|
|
102462
|
-
this.channelAdapter.unsubscribe(timeout).receive("ok", () =>
|
|
102549
|
+
return new Promise((resolve5) => {
|
|
102550
|
+
this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve5("ok")).receive("timeout", () => resolve5("timed out")).receive("error", () => resolve5("error"));
|
|
102463
102551
|
});
|
|
102464
102552
|
}
|
|
102465
102553
|
/**
|
|
@@ -102540,8 +102628,8 @@ var require_RealtimeChannel = __commonJS({
|
|
|
102540
102628
|
}
|
|
102541
102629
|
/** @internal */
|
|
102542
102630
|
_notThisChannelEvent(event, ref) {
|
|
102543
|
-
const { close, error, leave, join } = constants_1.CHANNEL_EVENTS;
|
|
102544
|
-
const events = [close, error, leave,
|
|
102631
|
+
const { close, error, leave, join: join2 } = constants_1.CHANNEL_EVENTS;
|
|
102632
|
+
const events = [close, error, leave, join2];
|
|
102545
102633
|
return ref && events.includes(event) && ref !== this.joinPush.ref;
|
|
102546
102634
|
}
|
|
102547
102635
|
/** @internal */
|
|
@@ -102663,11 +102751,11 @@ var require_socketAdapter = __commonJS({
|
|
|
102663
102751
|
this.socket.connect();
|
|
102664
102752
|
}
|
|
102665
102753
|
disconnect(callback, code, reason, timeout = 1e4) {
|
|
102666
|
-
return new Promise((
|
|
102667
|
-
setTimeout(() =>
|
|
102754
|
+
return new Promise((resolve5) => {
|
|
102755
|
+
setTimeout(() => resolve5("timeout"), timeout);
|
|
102668
102756
|
this.socket.disconnect(() => {
|
|
102669
102757
|
callback();
|
|
102670
|
-
|
|
102758
|
+
resolve5("ok");
|
|
102671
102759
|
}, code, reason);
|
|
102672
102760
|
});
|
|
102673
102761
|
}
|
|
@@ -104213,7 +104301,7 @@ var require_dist3 = __commonJS({
|
|
|
104213
104301
|
return _objectSpread24(_objectSpread24({}, params), parameters);
|
|
104214
104302
|
};
|
|
104215
104303
|
async function _handleRequest2(fetcher, method, url, options, parameters, body, namespace) {
|
|
104216
|
-
return new Promise((
|
|
104304
|
+
return new Promise((resolve5, reject2) => {
|
|
104217
104305
|
fetcher(url, _getRequestParams2(method, options, parameters, body)).then((result2) => {
|
|
104218
104306
|
if (!result2.ok) throw result2;
|
|
104219
104307
|
if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result2;
|
|
@@ -104223,7 +104311,7 @@ var require_dist3 = __commonJS({
|
|
|
104223
104311
|
if (!contentType || !contentType.includes("application/json")) return {};
|
|
104224
104312
|
}
|
|
104225
104313
|
return result2.json();
|
|
104226
|
-
}).then((data) =>
|
|
104314
|
+
}).then((data) => resolve5(data)).catch((error) => handleError2(error, reject2, options, namespace));
|
|
104227
104315
|
});
|
|
104228
104316
|
}
|
|
104229
104317
|
function createFetchApi2(namespace = "storage") {
|
|
@@ -114757,11 +114845,11 @@ var require_dist4 = __commonJS({
|
|
|
114757
114845
|
};
|
|
114758
114846
|
function __awaiter3(thisArg, _arguments, P, generator) {
|
|
114759
114847
|
function adopt(value) {
|
|
114760
|
-
return value instanceof P ? value : new P(function(
|
|
114761
|
-
|
|
114848
|
+
return value instanceof P ? value : new P(function(resolve5) {
|
|
114849
|
+
resolve5(value);
|
|
114762
114850
|
});
|
|
114763
114851
|
}
|
|
114764
|
-
return new (P || (P = Promise))(function(
|
|
114852
|
+
return new (P || (P = Promise))(function(resolve5, reject2) {
|
|
114765
114853
|
function fulfilled(value) {
|
|
114766
114854
|
try {
|
|
114767
114855
|
step(generator.next(value));
|
|
@@ -114777,7 +114865,7 @@ var require_dist4 = __commonJS({
|
|
|
114777
114865
|
}
|
|
114778
114866
|
}
|
|
114779
114867
|
function step(result2) {
|
|
114780
|
-
result2.done ?
|
|
114868
|
+
result2.done ? resolve5(result2.value) : adopt(result2.value).then(fulfilled, rejected);
|
|
114781
114869
|
}
|
|
114782
114870
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
114783
114871
|
});
|
|
@@ -118758,18 +118846,18 @@ var init_streamNormalizer = __esm({
|
|
|
118758
118846
|
|
|
118759
118847
|
// node_modules/@supabase/postgrest-js/dist/index.mjs
|
|
118760
118848
|
function sleep(ms, signal) {
|
|
118761
|
-
return new Promise((
|
|
118849
|
+
return new Promise((resolve5) => {
|
|
118762
118850
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
118763
|
-
|
|
118851
|
+
resolve5();
|
|
118764
118852
|
return;
|
|
118765
118853
|
}
|
|
118766
118854
|
const id = setTimeout(() => {
|
|
118767
118855
|
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
118768
|
-
|
|
118856
|
+
resolve5();
|
|
118769
118857
|
}, ms);
|
|
118770
118858
|
function onAbort() {
|
|
118771
118859
|
clearTimeout(id);
|
|
118772
|
-
|
|
118860
|
+
resolve5();
|
|
118773
118861
|
}
|
|
118774
118862
|
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
|
|
118775
118863
|
});
|
|
@@ -124304,7 +124392,7 @@ function normalizeHeaders(headers) {
|
|
|
124304
124392
|
return result2;
|
|
124305
124393
|
}
|
|
124306
124394
|
async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
|
|
124307
|
-
return new Promise((
|
|
124395
|
+
return new Promise((resolve5, reject2) => {
|
|
124308
124396
|
fetcher(url, _getRequestParams(method, options, parameters, body)).then((result2) => {
|
|
124309
124397
|
if (!result2.ok) throw result2;
|
|
124310
124398
|
if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result2;
|
|
@@ -124314,7 +124402,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
|
|
|
124314
124402
|
if (!contentType || !contentType.includes("application/json")) return {};
|
|
124315
124403
|
}
|
|
124316
124404
|
return result2.json();
|
|
124317
|
-
}).then((data) =>
|
|
124405
|
+
}).then((data) => resolve5(data)).catch((error) => handleError(error, reject2, options, namespace));
|
|
124318
124406
|
});
|
|
124319
124407
|
}
|
|
124320
124408
|
function createFetchApi(namespace = "storage") {
|
|
@@ -126932,11 +127020,11 @@ __export(dist_exports, {
|
|
|
126932
127020
|
});
|
|
126933
127021
|
function __awaiter2(thisArg, _arguments, P, generator) {
|
|
126934
127022
|
function adopt(value) {
|
|
126935
|
-
return value instanceof P ? value : new P(function(
|
|
126936
|
-
|
|
127023
|
+
return value instanceof P ? value : new P(function(resolve5) {
|
|
127024
|
+
resolve5(value);
|
|
126937
127025
|
});
|
|
126938
127026
|
}
|
|
126939
|
-
return new (P || (P = Promise))(function(
|
|
127027
|
+
return new (P || (P = Promise))(function(resolve5, reject2) {
|
|
126940
127028
|
function fulfilled(value) {
|
|
126941
127029
|
try {
|
|
126942
127030
|
step(generator.next(value));
|
|
@@ -126952,7 +127040,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
|
|
|
126952
127040
|
}
|
|
126953
127041
|
}
|
|
126954
127042
|
function step(result2) {
|
|
126955
|
-
result2.done ?
|
|
127043
|
+
result2.done ? resolve5(result2.value) : adopt(result2.value).then(fulfilled, rejected);
|
|
126956
127044
|
}
|
|
126957
127045
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
126958
127046
|
});
|
|
@@ -128257,12 +128345,12 @@ async function callAutoRaced(opts, parallelism) {
|
|
|
128257
128345
|
}
|
|
128258
128346
|
async function firstSuccessful(promises) {
|
|
128259
128347
|
const pending = new Set(promises);
|
|
128260
|
-
return new Promise((
|
|
128348
|
+
return new Promise((resolve5, reject2) => {
|
|
128261
128349
|
promises.forEach((promise) => {
|
|
128262
128350
|
promise.then((outcome) => {
|
|
128263
128351
|
pending.delete(promise);
|
|
128264
128352
|
if ("result" in outcome) {
|
|
128265
|
-
|
|
128353
|
+
resolve5(outcome);
|
|
128266
128354
|
} else if (pending.size === 0) {
|
|
128267
128355
|
reject2(new Error(`All ${promises.length} racers failed`));
|
|
128268
128356
|
}
|
|
@@ -130156,7 +130244,7 @@ function createProviderAbortSignal(parent, timeoutMs = AUTO_ROUTER_PROVIDER_TIME
|
|
|
130156
130244
|
};
|
|
130157
130245
|
}
|
|
130158
130246
|
function readStreamChunkWithIdleTimeout(reader, idleMs, abortSignal) {
|
|
130159
|
-
return new Promise((
|
|
130247
|
+
return new Promise((resolve5, reject2) => {
|
|
130160
130248
|
const timer = setTimeout(
|
|
130161
130249
|
() => reject2(new Error(`stream idle timeout after ${idleMs}ms`)),
|
|
130162
130250
|
idleMs
|
|
@@ -130177,7 +130265,7 @@ function readStreamChunkWithIdleTimeout(reader, idleMs, abortSignal) {
|
|
|
130177
130265
|
(result2) => {
|
|
130178
130266
|
clearTimeout(timer);
|
|
130179
130267
|
if (abortSignal) abortSignal.removeEventListener("abort", onAbort);
|
|
130180
|
-
|
|
130268
|
+
resolve5(result2);
|
|
130181
130269
|
},
|
|
130182
130270
|
(err) => {
|
|
130183
130271
|
clearTimeout(timer);
|
|
@@ -133482,7 +133570,7 @@ function validateToolCallPolicy(input) {
|
|
|
133482
133570
|
return {
|
|
133483
133571
|
ok: false,
|
|
133484
133572
|
code: "tool_desktop_required",
|
|
133485
|
-
message: "
|
|
133573
|
+
message: "This tool requires a local runtime. Filesystem access is validated per path by the current permission mode.",
|
|
133486
133574
|
riskLevel: classified.riskLevel,
|
|
133487
133575
|
desktopRequired: true
|
|
133488
133576
|
};
|
|
@@ -133824,8 +133912,8 @@ function validateArgs(name, args) {
|
|
|
133824
133912
|
return `${name}.path must be a safe path.`;
|
|
133825
133913
|
return null;
|
|
133826
133914
|
case TOOL_NAMES.writeLocalFile:
|
|
133827
|
-
if (!
|
|
133828
|
-
return "writeLocalFile.path must be a
|
|
133915
|
+
if (!isSafeFilePath(args.path))
|
|
133916
|
+
return "writeLocalFile.path must be a safe local path.";
|
|
133829
133917
|
if (typeof args.content !== "string")
|
|
133830
133918
|
return "writeLocalFile.content must be a string.";
|
|
133831
133919
|
if (args.overwrite !== void 0 && typeof args.overwrite !== "boolean")
|
|
@@ -133833,20 +133921,20 @@ function validateArgs(name, args) {
|
|
|
133833
133921
|
return null;
|
|
133834
133922
|
case TOOL_NAMES.moveLocalFile:
|
|
133835
133923
|
case TOOL_NAMES.copyLocalFile:
|
|
133836
|
-
if (!
|
|
133837
|
-
return `${name}.from must be a safe
|
|
133838
|
-
if (!
|
|
133839
|
-
return `${name}.to must be a safe
|
|
133924
|
+
if (!isSafeFilePath(args.from))
|
|
133925
|
+
return `${name}.from must be a safe local path.`;
|
|
133926
|
+
if (!isSafeFilePath(args.to))
|
|
133927
|
+
return `${name}.to must be a safe local path.`;
|
|
133840
133928
|
return null;
|
|
133841
133929
|
case TOOL_NAMES.createDirectory:
|
|
133842
133930
|
case TOOL_NAMES.deleteLocalFile:
|
|
133843
133931
|
case TOOL_NAMES.printFile:
|
|
133844
|
-
if (!
|
|
133845
|
-
return `${name}.path must be a safe
|
|
133932
|
+
if (!isSafeFilePath(args.path))
|
|
133933
|
+
return `${name}.path must be a safe local path.`;
|
|
133846
133934
|
return null;
|
|
133847
133935
|
case TOOL_NAMES.editLocalFile:
|
|
133848
|
-
if (!
|
|
133849
|
-
return "editLocalFile.path must be a safe
|
|
133936
|
+
if (!isSafeFilePath(args.path))
|
|
133937
|
+
return "editLocalFile.path must be a safe local path.";
|
|
133850
133938
|
if (typeof args.oldText !== "string" || !args.oldText)
|
|
133851
133939
|
return "editLocalFile.oldText must be a non-empty string.";
|
|
133852
133940
|
if (typeof args.newText !== "string")
|
|
@@ -133871,8 +133959,8 @@ function validateArgs(name, args) {
|
|
|
133871
133959
|
return "listLocalSources.maxResults must be a positive number.";
|
|
133872
133960
|
return null;
|
|
133873
133961
|
case TOOL_NAMES.readLocalSourceFile:
|
|
133874
|
-
if (!isSafeLocalSourceId(args.localSourceId) && !
|
|
133875
|
-
return "readLocalSourceFile.localSourceId must be a valid local source id or safe
|
|
133962
|
+
if (!isSafeLocalSourceId(args.localSourceId) && !isSafeFilePath(args.localSourceId))
|
|
133963
|
+
return "readLocalSourceFile.localSourceId must be a valid local source id or safe local path.";
|
|
133876
133964
|
return null;
|
|
133877
133965
|
case TOOL_NAMES.generateAPAuditPacket:
|
|
133878
133966
|
if (typeof args.folderPath !== "string" || !args.folderPath.trim())
|
|
@@ -134140,7 +134228,7 @@ function isSafeFilePath(value) {
|
|
|
134140
134228
|
if (typeof value !== "string") return false;
|
|
134141
134229
|
const trimmed = value.trim();
|
|
134142
134230
|
if (!trimmed) return false;
|
|
134143
|
-
if (/^file:/i.test(trimmed) || trimmed.includes("::")
|
|
134231
|
+
if (/^file:/i.test(trimmed) || trimmed.includes("::"))
|
|
134144
134232
|
return false;
|
|
134145
134233
|
return !trimmed.split(/[\\/]+/).includes("..");
|
|
134146
134234
|
}
|
|
@@ -134423,13 +134511,13 @@ function getDesktopToolDefinitions() {
|
|
|
134423
134511
|
type: "function",
|
|
134424
134512
|
function: {
|
|
134425
134513
|
name: TOOL_NAMES.writeLocalFile,
|
|
134426
|
-
description: "Create or overwrite a local UTF-8 text file. Permission mode controls whether it runs immediately or asks for approval.",
|
|
134514
|
+
description: "Create or overwrite a local UTF-8 text file. Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Permission mode controls whether it runs immediately or asks for approval.",
|
|
134427
134515
|
parameters: {
|
|
134428
134516
|
type: "object",
|
|
134429
134517
|
properties: {
|
|
134430
134518
|
path: {
|
|
134431
134519
|
type: "string",
|
|
134432
|
-
description: "
|
|
134520
|
+
description: "Path to write. May be absolute, ~/..., or relative to the current local working directory."
|
|
134433
134521
|
},
|
|
134434
134522
|
content: {
|
|
134435
134523
|
type: "string",
|
|
@@ -134449,17 +134537,17 @@ function getDesktopToolDefinitions() {
|
|
|
134449
134537
|
type: "function",
|
|
134450
134538
|
function: {
|
|
134451
134539
|
name: TOOL_NAMES.moveLocalFile,
|
|
134452
|
-
description: "Move or rename a file
|
|
134540
|
+
description: "Move or rename a local file. Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Write-tier risk.",
|
|
134453
134541
|
parameters: {
|
|
134454
134542
|
type: "object",
|
|
134455
134543
|
properties: {
|
|
134456
134544
|
from: {
|
|
134457
134545
|
type: "string",
|
|
134458
|
-
description: "
|
|
134546
|
+
description: "Source path to move."
|
|
134459
134547
|
},
|
|
134460
134548
|
to: {
|
|
134461
134549
|
type: "string",
|
|
134462
|
-
description: "
|
|
134550
|
+
description: "Destination path."
|
|
134463
134551
|
}
|
|
134464
134552
|
},
|
|
134465
134553
|
required: ["from", "to"],
|
|
@@ -134471,17 +134559,17 @@ function getDesktopToolDefinitions() {
|
|
|
134471
134559
|
type: "function",
|
|
134472
134560
|
function: {
|
|
134473
134561
|
name: TOOL_NAMES.copyLocalFile,
|
|
134474
|
-
description: "Copy a file
|
|
134562
|
+
description: "Copy a local file. Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Write-tier risk.",
|
|
134475
134563
|
parameters: {
|
|
134476
134564
|
type: "object",
|
|
134477
134565
|
properties: {
|
|
134478
134566
|
from: {
|
|
134479
134567
|
type: "string",
|
|
134480
|
-
description: "
|
|
134568
|
+
description: "Source path to copy."
|
|
134481
134569
|
},
|
|
134482
134570
|
to: {
|
|
134483
134571
|
type: "string",
|
|
134484
|
-
description: "
|
|
134572
|
+
description: "Destination path."
|
|
134485
134573
|
}
|
|
134486
134574
|
},
|
|
134487
134575
|
required: ["from", "to"],
|
|
@@ -134493,13 +134581,13 @@ function getDesktopToolDefinitions() {
|
|
|
134493
134581
|
type: "function",
|
|
134494
134582
|
function: {
|
|
134495
134583
|
name: TOOL_NAMES.createDirectory,
|
|
134496
|
-
description: "Create a
|
|
134584
|
+
description: "Create a local directory recursively (mkdir -p). Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Write-tier risk.",
|
|
134497
134585
|
parameters: {
|
|
134498
134586
|
type: "object",
|
|
134499
134587
|
properties: {
|
|
134500
134588
|
path: {
|
|
134501
134589
|
type: "string",
|
|
134502
|
-
description: "
|
|
134590
|
+
description: "Directory path to create."
|
|
134503
134591
|
}
|
|
134504
134592
|
},
|
|
134505
134593
|
required: ["path"],
|
|
@@ -134511,13 +134599,13 @@ function getDesktopToolDefinitions() {
|
|
|
134511
134599
|
type: "function",
|
|
134512
134600
|
function: {
|
|
134513
134601
|
name: TOOL_NAMES.deleteLocalFile,
|
|
134514
|
-
description: "Delete a single
|
|
134602
|
+
description: "Delete a single local file. Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Lower permission modes ask for approval; Take the Wheel runs it without asking.",
|
|
134515
134603
|
parameters: {
|
|
134516
134604
|
type: "object",
|
|
134517
134605
|
properties: {
|
|
134518
134606
|
path: {
|
|
134519
134607
|
type: "string",
|
|
134520
|
-
description: "
|
|
134608
|
+
description: "File path to delete."
|
|
134521
134609
|
}
|
|
134522
134610
|
},
|
|
134523
134611
|
required: ["path"],
|
|
@@ -134529,13 +134617,13 @@ function getDesktopToolDefinitions() {
|
|
|
134529
134617
|
type: "function",
|
|
134530
134618
|
function: {
|
|
134531
134619
|
name: TOOL_NAMES.printFile,
|
|
134532
|
-
description: "Send a
|
|
134620
|
+
description: "Send a local file to the default printer using the system print command. Write-tier risk.",
|
|
134533
134621
|
parameters: {
|
|
134534
134622
|
type: "object",
|
|
134535
134623
|
properties: {
|
|
134536
134624
|
path: {
|
|
134537
134625
|
type: "string",
|
|
134538
|
-
description: "
|
|
134626
|
+
description: "File path to print."
|
|
134539
134627
|
}
|
|
134540
134628
|
},
|
|
134541
134629
|
required: ["path"],
|
|
@@ -134547,13 +134635,13 @@ function getDesktopToolDefinitions() {
|
|
|
134547
134635
|
type: "function",
|
|
134548
134636
|
function: {
|
|
134549
134637
|
name: TOOL_NAMES.editLocalFile,
|
|
134550
|
-
description: "Exact find/replace edit in a
|
|
134638
|
+
description: "Exact find/replace edit in a local UTF-8 text file. Accepts absolute paths, ~/ paths, or paths relative to the current local working directory. Lower permission modes ask for approval; Take the Wheel runs it without asking.",
|
|
134551
134639
|
parameters: {
|
|
134552
134640
|
type: "object",
|
|
134553
134641
|
properties: {
|
|
134554
134642
|
path: {
|
|
134555
134643
|
type: "string",
|
|
134556
|
-
description: "
|
|
134644
|
+
description: "Path to edit."
|
|
134557
134645
|
},
|
|
134558
134646
|
oldText: { type: "string", description: "Exact text to replace." },
|
|
134559
134647
|
newText: { type: "string", description: "Replacement text." },
|
|
@@ -135943,7 +136031,7 @@ function getNativeToolDefinitions() {
|
|
|
135943
136031
|
type: "function",
|
|
135944
136032
|
function: {
|
|
135945
136033
|
name: TOOL_NAMES.configInspect,
|
|
135946
|
-
description: "Inspect the Perch Terminal runtime configuration: execution host,
|
|
136034
|
+
description: "Inspect the Perch Terminal runtime configuration: execution host, local runtime status, optional folder scope, permission mode, and capabilities.",
|
|
135947
136035
|
parameters: {
|
|
135948
136036
|
type: "object",
|
|
135949
136037
|
properties: {},
|
|
@@ -136846,7 +136934,7 @@ function notifyApprovedRootsChanged() {
|
|
|
136846
136934
|
}
|
|
136847
136935
|
async function pickFolder(request) {
|
|
136848
136936
|
const bridge = getDesktopBridge();
|
|
136849
|
-
if (!bridge) return { ok: false, error: "
|
|
136937
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136850
136938
|
const result2 = await bridge.pickFolder({
|
|
136851
136939
|
permissionMode: currentPermissionMode(),
|
|
136852
136940
|
defaultPath: request?.defaultPath ?? null,
|
|
@@ -136859,7 +136947,7 @@ async function pickFolder(request) {
|
|
|
136859
136947
|
}
|
|
136860
136948
|
async function approveFolderAccess(path14, options) {
|
|
136861
136949
|
const bridge = getDesktopBridge();
|
|
136862
|
-
if (!bridge) return { ok: false, error: "
|
|
136950
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136863
136951
|
const result2 = await bridge.approveFolderAccess({
|
|
136864
136952
|
path: path14,
|
|
136865
136953
|
permissionMode: currentPermissionMode(),
|
|
@@ -136873,7 +136961,7 @@ async function checkFsAccess(request) {
|
|
|
136873
136961
|
if (!bridge) {
|
|
136874
136962
|
return {
|
|
136875
136963
|
decision: "block",
|
|
136876
|
-
reason: "
|
|
136964
|
+
reason: "Local runtime not available",
|
|
136877
136965
|
absolutePath: request.absolutePath,
|
|
136878
136966
|
approvalPath: request.absolutePath
|
|
136879
136967
|
};
|
|
@@ -136892,7 +136980,7 @@ async function checkFullDiskAccess() {
|
|
|
136892
136980
|
}
|
|
136893
136981
|
async function resolveDefaultSavePath(request) {
|
|
136894
136982
|
const bridge = getDesktopBridge();
|
|
136895
|
-
if (!bridge) return { ok: false, error: "
|
|
136983
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136896
136984
|
return bridge.resolveDefaultSavePath(request);
|
|
136897
136985
|
}
|
|
136898
136986
|
async function getApprovedRoots() {
|
|
@@ -136902,17 +136990,17 @@ async function getApprovedRoots() {
|
|
|
136902
136990
|
}
|
|
136903
136991
|
async function removeRoot(rootId) {
|
|
136904
136992
|
const bridge = getDesktopBridge();
|
|
136905
|
-
if (!bridge) return { ok: false, error: "
|
|
136993
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136906
136994
|
return bridge.removeRoot(rootId);
|
|
136907
136995
|
}
|
|
136908
136996
|
async function listFiles(rootId, relativePath, depth) {
|
|
136909
136997
|
const bridge = getDesktopBridge();
|
|
136910
|
-
if (!bridge) return { ok: false, rootId, basePath: "", entries: [], truncated: false, error: "
|
|
136998
|
+
if (!bridge) return { ok: false, rootId, basePath: "", entries: [], truncated: false, error: "Local runtime not available" };
|
|
136911
136999
|
return bridge.listFiles(withPermissionMode({ rootId, relativePath, depth }));
|
|
136912
137000
|
}
|
|
136913
137001
|
async function readFile2(rootId, relativePath) {
|
|
136914
137002
|
const bridge = getDesktopBridge();
|
|
136915
|
-
if (!bridge) return { ok: false, error: "
|
|
137003
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136916
137004
|
return bridge.readFile(withPermissionMode({ rootId, relativePath }));
|
|
136917
137005
|
}
|
|
136918
137006
|
function normalizeLegacyListResult(result2, request) {
|
|
@@ -136948,7 +137036,7 @@ async function listLocalSourcesDetailed(request) {
|
|
|
136948
137036
|
query: typeof request === "object" && request ? request.query ?? null : null,
|
|
136949
137037
|
refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
136950
137038
|
maxSources: 0,
|
|
136951
|
-
warning: "
|
|
137039
|
+
warning: "Local runtime not available"
|
|
136952
137040
|
};
|
|
136953
137041
|
}
|
|
136954
137042
|
const raw = await bridge.listLocalSources(request);
|
|
@@ -136956,7 +137044,7 @@ async function listLocalSourcesDetailed(request) {
|
|
|
136956
137044
|
}
|
|
136957
137045
|
async function readLocalSourceFile(localSourceId) {
|
|
136958
137046
|
const bridge = getDesktopBridge();
|
|
136959
|
-
if (!bridge) return { ok: false, error: "
|
|
137047
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136960
137048
|
return bridge.readLocalFile(localSourceId, { permissionMode: currentPermissionMode() });
|
|
136961
137049
|
}
|
|
136962
137050
|
async function getProjectRules(rootId) {
|
|
@@ -136966,37 +137054,37 @@ async function getProjectRules(rootId) {
|
|
|
136966
137054
|
}
|
|
136967
137055
|
async function readProjectMemory(rootId) {
|
|
136968
137056
|
const bridge = getDesktopBridge();
|
|
136969
|
-
if (!bridge) return { ok: false, error: "
|
|
137057
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136970
137058
|
return bridge.readProjectMemory({ rootId });
|
|
136971
137059
|
}
|
|
136972
137060
|
async function writeProjectMemory(rootId, meta) {
|
|
136973
137061
|
const bridge = getDesktopBridge();
|
|
136974
|
-
if (!bridge) return { ok: false, error: "
|
|
137062
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136975
137063
|
return bridge.writeProjectMemory({ rootId, meta });
|
|
136976
137064
|
}
|
|
136977
137065
|
async function writeMemoryFile(rootId, request) {
|
|
136978
137066
|
const bridge = getDesktopBridge();
|
|
136979
|
-
if (!bridge) return { ok: false, error: "
|
|
137067
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136980
137068
|
return bridge.writeMemoryFile({ rootId, ...request });
|
|
136981
137069
|
}
|
|
136982
137070
|
async function writeRule(rootId, request) {
|
|
136983
137071
|
const bridge = getDesktopBridge();
|
|
136984
|
-
if (!bridge) return { ok: false, error: "
|
|
137072
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136985
137073
|
return bridge.writeRule({ rootId, ...request });
|
|
136986
137074
|
}
|
|
136987
137075
|
async function writePerchMd(rootId, request) {
|
|
136988
137076
|
const bridge = getDesktopBridge();
|
|
136989
|
-
if (!bridge) return { ok: false, error: "
|
|
137077
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136990
137078
|
return bridge.writePerchMd({ rootId, ...request });
|
|
136991
137079
|
}
|
|
136992
137080
|
async function readGlobalPerchMd() {
|
|
136993
137081
|
const bridge = getDesktopBridge();
|
|
136994
|
-
if (!bridge) return { ok: false, error: "
|
|
137082
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
136995
137083
|
return bridge.readGlobalPerchMd();
|
|
136996
137084
|
}
|
|
136997
137085
|
async function writeGlobalPerchMd(content) {
|
|
136998
137086
|
const bridge = getDesktopBridge();
|
|
136999
|
-
if (!bridge) return { ok: false, error: "
|
|
137087
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137000
137088
|
return bridge.writeGlobalPerchMd({ content });
|
|
137001
137089
|
}
|
|
137002
137090
|
async function getMcpStatus() {
|
|
@@ -137011,12 +137099,12 @@ async function listMcpTools() {
|
|
|
137011
137099
|
}
|
|
137012
137100
|
async function callMcpTool(request) {
|
|
137013
137101
|
const bridge = getDesktopBridge();
|
|
137014
|
-
if (!bridge) return { ok: false, error: "
|
|
137102
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137015
137103
|
return bridge.callMcpTool(request);
|
|
137016
137104
|
}
|
|
137017
137105
|
async function callEmbeddedBrowserTool(request) {
|
|
137018
137106
|
const bridge = getDesktopBridge();
|
|
137019
|
-
if (!bridge) return { ok: false, error: "
|
|
137107
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137020
137108
|
if (typeof bridge.callEmbeddedBrowserTool !== "function") {
|
|
137021
137109
|
return { ok: false, error: "Embedded browser bridge not available in this desktop build" };
|
|
137022
137110
|
}
|
|
@@ -137024,7 +137112,7 @@ async function callEmbeddedBrowserTool(request) {
|
|
|
137024
137112
|
}
|
|
137025
137113
|
async function setEmbeddedBrowserVisible(open) {
|
|
137026
137114
|
const bridge = getDesktopBridge();
|
|
137027
|
-
if (!bridge) return { ok: false, error: "
|
|
137115
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137028
137116
|
if (typeof bridge.setEmbeddedBrowserVisible !== "function") {
|
|
137029
137117
|
return { ok: false, error: "Embedded browser bridge not available in this desktop build" };
|
|
137030
137118
|
}
|
|
@@ -137047,7 +137135,7 @@ function onEmbeddedBrowserState(handler) {
|
|
|
137047
137135
|
}
|
|
137048
137136
|
async function reconnectMcp() {
|
|
137049
137137
|
const bridge = getDesktopBridge();
|
|
137050
|
-
if (!bridge) return { ok: false, error: "
|
|
137138
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137051
137139
|
return bridge.reconnectMcp();
|
|
137052
137140
|
}
|
|
137053
137141
|
async function getOrStartBashTerminal(request) {
|
|
@@ -137092,37 +137180,37 @@ async function runLocalBash(request) {
|
|
|
137092
137180
|
}
|
|
137093
137181
|
async function readWorkspaceFile(request) {
|
|
137094
137182
|
const bridge = getDesktopBridge();
|
|
137095
|
-
if (!bridge) return { ok: false, error: "
|
|
137183
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137096
137184
|
return bridge.readWorkspaceFile(withPermissionMode(request, request));
|
|
137097
137185
|
}
|
|
137098
137186
|
async function writeWorkspaceFile(request) {
|
|
137099
137187
|
const bridge = getDesktopBridge();
|
|
137100
|
-
if (!bridge) return { ok: false, error: "
|
|
137188
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137101
137189
|
return bridge.writeWorkspaceFile(withPermissionMode(request, request));
|
|
137102
137190
|
}
|
|
137103
137191
|
async function moveLocalFile(request) {
|
|
137104
137192
|
const bridge = getDesktopBridge();
|
|
137105
|
-
if (!bridge) return { ok: false, error: "
|
|
137193
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137106
137194
|
return bridge.moveLocalFile(withPermissionMode(request, request));
|
|
137107
137195
|
}
|
|
137108
137196
|
async function copyLocalFile(request) {
|
|
137109
137197
|
const bridge = getDesktopBridge();
|
|
137110
|
-
if (!bridge) return { ok: false, error: "
|
|
137198
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137111
137199
|
return bridge.copyLocalFile(withPermissionMode(request, request));
|
|
137112
137200
|
}
|
|
137113
137201
|
async function createDirectory(request) {
|
|
137114
137202
|
const bridge = getDesktopBridge();
|
|
137115
|
-
if (!bridge) return { ok: false, error: "
|
|
137203
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137116
137204
|
return bridge.createDirectory(withPermissionMode(request, request));
|
|
137117
137205
|
}
|
|
137118
137206
|
async function deleteLocalFile(request) {
|
|
137119
137207
|
const bridge = getDesktopBridge();
|
|
137120
|
-
if (!bridge) return { ok: false, error: "
|
|
137208
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137121
137209
|
return bridge.deleteLocalFile(withPermissionMode(request, request));
|
|
137122
137210
|
}
|
|
137123
137211
|
async function printFile(request) {
|
|
137124
137212
|
const bridge = getDesktopBridge();
|
|
137125
|
-
if (!bridge) return { ok: false, error: "
|
|
137213
|
+
if (!bridge) return { ok: false, error: "Local runtime not available" };
|
|
137126
137214
|
return bridge.printFile(withPermissionMode(request, request));
|
|
137127
137215
|
}
|
|
137128
137216
|
async function listWorkspaceFilesGlob(request) {
|
|
@@ -137181,7 +137269,7 @@ async function runLocalAPAuditPacket(request) {
|
|
|
137181
137269
|
if (!bridge) {
|
|
137182
137270
|
return {
|
|
137183
137271
|
ok: false,
|
|
137184
|
-
error: "
|
|
137272
|
+
error: "Local runtime not available",
|
|
137185
137273
|
errorCode: "desktop_bridge_unavailable",
|
|
137186
137274
|
executionHost: "electron_desktop",
|
|
137187
137275
|
durationMs: 0
|
|
@@ -137194,7 +137282,7 @@ async function runLocalPrepareAPEvidence(request) {
|
|
|
137194
137282
|
if (!bridge?.runLocalPrepareAPEvidence) {
|
|
137195
137283
|
return {
|
|
137196
137284
|
ok: false,
|
|
137197
|
-
error: "
|
|
137285
|
+
error: "AP evidence tool not available in local runtime",
|
|
137198
137286
|
errorCode: bridge ? "missing_dependency" : "desktop_bridge_unavailable",
|
|
137199
137287
|
executionHost: "electron_desktop",
|
|
137200
137288
|
durationMs: 0
|
|
@@ -137207,7 +137295,7 @@ async function runLocalQueryAPCases(request) {
|
|
|
137207
137295
|
if (!bridge?.runLocalQueryAPCases) {
|
|
137208
137296
|
return {
|
|
137209
137297
|
ok: false,
|
|
137210
|
-
error: "
|
|
137298
|
+
error: "AP case query tool not available in local runtime",
|
|
137211
137299
|
errorCode: bridge ? "missing_dependency" : "desktop_bridge_unavailable",
|
|
137212
137300
|
executionHost: "electron_desktop",
|
|
137213
137301
|
durationMs: 0
|
|
@@ -137220,7 +137308,7 @@ async function runLocalRenderAPControlGraph(request) {
|
|
|
137220
137308
|
if (!bridge?.runLocalRenderAPControlGraph) {
|
|
137221
137309
|
return {
|
|
137222
137310
|
ok: false,
|
|
137223
|
-
error: "
|
|
137311
|
+
error: "AP control graph tool not available in local runtime",
|
|
137224
137312
|
errorCode: bridge ? "missing_dependency" : "desktop_bridge_unavailable",
|
|
137225
137313
|
executionHost: "electron_desktop",
|
|
137226
137314
|
durationMs: 0
|
|
@@ -137233,7 +137321,7 @@ async function runLocalPayrollRunArtifact(request) {
|
|
|
137233
137321
|
if (!bridge) {
|
|
137234
137322
|
return {
|
|
137235
137323
|
ok: false,
|
|
137236
|
-
error: "
|
|
137324
|
+
error: "Local runtime not available",
|
|
137237
137325
|
errorCode: "desktop_bridge_unavailable",
|
|
137238
137326
|
executionHost: "electron_desktop",
|
|
137239
137327
|
durationMs: 0
|
|
@@ -137248,7 +137336,7 @@ function desktopGLReconcileAvailable() {
|
|
|
137248
137336
|
async function runLocalGLReconcileArtifact(folderPath) {
|
|
137249
137337
|
const bridge = getDesktopBridge();
|
|
137250
137338
|
if (!bridge?.runLocalGLReconcileArtifact) {
|
|
137251
|
-
return { ok: false, error: "
|
|
137339
|
+
return { ok: false, error: "Local runtime unavailable", errorCode: "desktop_bridge_unavailable", executionHost: "electron_desktop", durationMs: 0 };
|
|
137252
137340
|
}
|
|
137253
137341
|
return bridge.runLocalGLReconcileArtifact({ folderPath });
|
|
137254
137342
|
}
|
|
@@ -137259,7 +137347,7 @@ function desktopStatementAuditAvailable() {
|
|
|
137259
137347
|
async function runLocalStatementAuditArtifact(folderPath) {
|
|
137260
137348
|
const bridge = getDesktopBridge();
|
|
137261
137349
|
if (!bridge?.runLocalStatementAuditArtifact) {
|
|
137262
|
-
return { ok: false, error: "
|
|
137350
|
+
return { ok: false, error: "Local runtime unavailable", errorCode: "desktop_bridge_unavailable", executionHost: "electron_desktop", durationMs: 0 };
|
|
137263
137351
|
}
|
|
137264
137352
|
return bridge.runLocalStatementAuditArtifact({ folderPath });
|
|
137265
137353
|
}
|
|
@@ -137284,7 +137372,7 @@ async function runSandboxCodeJob(request) {
|
|
|
137284
137372
|
kind: "blocked",
|
|
137285
137373
|
error: bridge ? "capability_unavailable" : "not_desktop",
|
|
137286
137374
|
executionHost: "electron-main",
|
|
137287
|
-
message: bridge ? "This Perch
|
|
137375
|
+
message: bridge ? "This Perch build does not expose runSandboxCodeJob." : "Local runtime is unavailable."
|
|
137288
137376
|
};
|
|
137289
137377
|
}
|
|
137290
137378
|
return bridge.runSandboxCodeJob(request);
|
|
@@ -138738,8 +138826,8 @@ var init_capabilityBus = __esm({
|
|
|
138738
138826
|
}
|
|
138739
138827
|
let resolvePromise = () => {
|
|
138740
138828
|
};
|
|
138741
|
-
const promise = new Promise((
|
|
138742
|
-
resolvePromise =
|
|
138829
|
+
const promise = new Promise((resolve5) => {
|
|
138830
|
+
resolvePromise = resolve5;
|
|
138743
138831
|
});
|
|
138744
138832
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
138745
138833
|
const request = {
|
|
@@ -138796,7 +138884,7 @@ var init_capabilityBus = __esm({
|
|
|
138796
138884
|
return true;
|
|
138797
138885
|
}
|
|
138798
138886
|
getPending(sessionId) {
|
|
138799
|
-
return Array.from(this.pending.values()).filter((entry) => !sessionId || entry.sessionId === sessionId).map(({ resolve:
|
|
138887
|
+
return Array.from(this.pending.values()).filter((entry) => !sessionId || entry.sessionId === sessionId).map(({ resolve: resolve5, promise, ...request }) => request);
|
|
138800
138888
|
}
|
|
138801
138889
|
dispatchBrowserEvent(type, payload) {
|
|
138802
138890
|
if (typeof window === "undefined") return;
|
|
@@ -139236,7 +139324,7 @@ function createAbortableBrowserDriver(driver, signal, timeoutMs = DEFAULT_BROWSE
|
|
|
139236
139324
|
};
|
|
139237
139325
|
}
|
|
139238
139326
|
function withAbortAndTimeout(promise, signal, timeoutMs, label) {
|
|
139239
|
-
return new Promise((
|
|
139327
|
+
return new Promise((resolve5, reject2) => {
|
|
139240
139328
|
if (signal?.aborted) {
|
|
139241
139329
|
reject2(abortError(`${label} cancelled.`));
|
|
139242
139330
|
return;
|
|
@@ -139262,7 +139350,7 @@ function withAbortAndTimeout(promise, signal, timeoutMs, label) {
|
|
|
139262
139350
|
);
|
|
139263
139351
|
}
|
|
139264
139352
|
promise.then(
|
|
139265
|
-
(value) => finish(() =>
|
|
139353
|
+
(value) => finish(() => resolve5(value)),
|
|
139266
139354
|
(error) => finish(() => reject2(error))
|
|
139267
139355
|
);
|
|
139268
139356
|
});
|
|
@@ -140021,7 +140109,7 @@ async function maybeWaitForCapabilityAndRetry(failureKind, input, runtime, snaps
|
|
|
140021
140109
|
function waitForAbortable(promise, signal) {
|
|
140022
140110
|
if (!signal) return promise;
|
|
140023
140111
|
if (signal.aborted) return Promise.reject(new DOMException("Browser action cancelled.", "AbortError"));
|
|
140024
|
-
return new Promise((
|
|
140112
|
+
return new Promise((resolve5, reject2) => {
|
|
140025
140113
|
const onAbort = () => {
|
|
140026
140114
|
signal.removeEventListener("abort", onAbort);
|
|
140027
140115
|
reject2(new DOMException("Browser action cancelled.", "AbortError"));
|
|
@@ -140030,7 +140118,7 @@ function waitForAbortable(promise, signal) {
|
|
|
140030
140118
|
promise.then(
|
|
140031
140119
|
(value) => {
|
|
140032
140120
|
signal.removeEventListener("abort", onAbort);
|
|
140033
|
-
|
|
140121
|
+
resolve5(value);
|
|
140034
140122
|
},
|
|
140035
140123
|
(error) => {
|
|
140036
140124
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -140726,8 +140814,8 @@ function pasteShortcut() {
|
|
|
140726
140814
|
}
|
|
140727
140815
|
function browserShortcut(key) {
|
|
140728
140816
|
const override = (typeof process !== "undefined" ? process.env?.PERCH_PLAYWRIGHT_OS : "")?.toLowerCase();
|
|
140729
|
-
const
|
|
140730
|
-
const isMac = override === "mac" || override !== "windows" && override !== "linux" &&
|
|
140817
|
+
const platform3 = (typeof process !== "undefined" ? process.platform : "") ?? "";
|
|
140818
|
+
const isMac = override === "mac" || override !== "windows" && override !== "linux" && platform3 === "darwin";
|
|
140731
140819
|
return isMac ? `Meta+${key}` : `Control+${key}`;
|
|
140732
140820
|
}
|
|
140733
140821
|
function failureMessage(kind) {
|
|
@@ -140766,12 +140854,12 @@ function isAbortError(err) {
|
|
|
140766
140854
|
return err instanceof DOMException && err.name === "AbortError";
|
|
140767
140855
|
}
|
|
140768
140856
|
function delay(ms, signal) {
|
|
140769
|
-
return new Promise((
|
|
140857
|
+
return new Promise((resolve5, reject2) => {
|
|
140770
140858
|
if (signal?.aborted) {
|
|
140771
140859
|
reject2(new DOMException("Browser action cancelled.", "AbortError"));
|
|
140772
140860
|
return;
|
|
140773
140861
|
}
|
|
140774
|
-
const timeout = globalThis.setTimeout(
|
|
140862
|
+
const timeout = globalThis.setTimeout(resolve5, ms);
|
|
140775
140863
|
signal?.addEventListener(
|
|
140776
140864
|
"abort",
|
|
140777
140865
|
() => {
|
|
@@ -141197,12 +141285,12 @@ function toStringArray2(value) {
|
|
|
141197
141285
|
return result2.length > 0 ? result2 : void 0;
|
|
141198
141286
|
}
|
|
141199
141287
|
function pause(ms, signal) {
|
|
141200
|
-
return new Promise((
|
|
141288
|
+
return new Promise((resolve5, reject2) => {
|
|
141201
141289
|
if (signal?.aborted) {
|
|
141202
141290
|
reject2(new DOMException("Browser research cancelled.", "AbortError"));
|
|
141203
141291
|
return;
|
|
141204
141292
|
}
|
|
141205
|
-
const timer = setTimeout(
|
|
141293
|
+
const timer = setTimeout(resolve5, ms);
|
|
141206
141294
|
signal?.addEventListener(
|
|
141207
141295
|
"abort",
|
|
141208
141296
|
() => {
|
|
@@ -141589,7 +141677,7 @@ async function fetchData(url, type = "text") {
|
|
|
141589
141677
|
}
|
|
141590
141678
|
return response.text();
|
|
141591
141679
|
}
|
|
141592
|
-
return new Promise((
|
|
141680
|
+
return new Promise((resolve5, reject2) => {
|
|
141593
141681
|
const request = new XMLHttpRequest();
|
|
141594
141682
|
request.open("GET", url, true);
|
|
141595
141683
|
request.responseType = type;
|
|
@@ -141602,10 +141690,10 @@ async function fetchData(url, type = "text") {
|
|
|
141602
141690
|
case "arraybuffer":
|
|
141603
141691
|
case "blob":
|
|
141604
141692
|
case "json":
|
|
141605
|
-
|
|
141693
|
+
resolve5(request.response);
|
|
141606
141694
|
return;
|
|
141607
141695
|
}
|
|
141608
|
-
|
|
141696
|
+
resolve5(request.responseText);
|
|
141609
141697
|
return;
|
|
141610
141698
|
}
|
|
141611
141699
|
reject2(new Error(request.statusText));
|
|
@@ -144612,7 +144700,7 @@ var init_pdf = __esm({
|
|
|
144612
144700
|
var defineProperty = Object.defineProperty;
|
|
144613
144701
|
var stringSlice = uncurryThis("".slice);
|
|
144614
144702
|
var replace = uncurryThis("".replace);
|
|
144615
|
-
var
|
|
144703
|
+
var join2 = uncurryThis([].join);
|
|
144616
144704
|
var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
|
|
144617
144705
|
return defineProperty(function() {
|
|
144618
144706
|
}, "length", { value: 8 }).length !== 8;
|
|
@@ -144639,7 +144727,7 @@ var init_pdf = __esm({
|
|
|
144639
144727
|
}
|
|
144640
144728
|
var state = enforceInternalState(value);
|
|
144641
144729
|
if (!hasOwn(state, "source")) {
|
|
144642
|
-
state.source =
|
|
144730
|
+
state.source = join2(TEMPLATE, typeof name == "string" ? name : "");
|
|
144643
144731
|
}
|
|
144644
144732
|
return value;
|
|
144645
144733
|
};
|
|
@@ -144667,13 +144755,13 @@ var init_pdf = __esm({
|
|
|
144667
144755
|
var aCallable = __webpack_require__2(9306);
|
|
144668
144756
|
var $TypeError = TypeError;
|
|
144669
144757
|
var PromiseCapability = function(C) {
|
|
144670
|
-
var
|
|
144758
|
+
var resolve5, reject2;
|
|
144671
144759
|
this.promise = new C(function($$resolve, $$reject) {
|
|
144672
|
-
if (
|
|
144673
|
-
|
|
144760
|
+
if (resolve5 !== void 0 || reject2 !== void 0) throw new $TypeError("Bad Promise constructor");
|
|
144761
|
+
resolve5 = $$resolve;
|
|
144674
144762
|
reject2 = $$reject;
|
|
144675
144763
|
});
|
|
144676
|
-
this.resolve = aCallable(
|
|
144764
|
+
this.resolve = aCallable(resolve5);
|
|
144677
144765
|
this.reject = aCallable(reject2);
|
|
144678
144766
|
};
|
|
144679
144767
|
module2.exports.f = function(C) {
|
|
@@ -147791,11 +147879,11 @@ var init_pdf = __esm({
|
|
|
147791
147879
|
const mustRemoveAspectRatioPromise = _ImageManager._isSVGFittingCanvas;
|
|
147792
147880
|
const fileReader = new FileReader();
|
|
147793
147881
|
const imageElement = new Image();
|
|
147794
|
-
const imagePromise = new Promise((
|
|
147882
|
+
const imagePromise = new Promise((resolve5, reject2) => {
|
|
147795
147883
|
imageElement.onload = () => {
|
|
147796
147884
|
data.bitmap = imageElement;
|
|
147797
147885
|
data.isSvg = true;
|
|
147798
|
-
|
|
147886
|
+
resolve5();
|
|
147799
147887
|
};
|
|
147800
147888
|
fileReader.onload = async () => {
|
|
147801
147889
|
const url = data.svgUrl = fileReader.result;
|
|
@@ -151644,8 +151732,8 @@ var init_pdf = __esm({
|
|
|
151644
151732
|
if (this.isSyncFontLoadingSupported) {
|
|
151645
151733
|
return;
|
|
151646
151734
|
}
|
|
151647
|
-
await new Promise((
|
|
151648
|
-
const request = this._queueLoadingCallback(
|
|
151735
|
+
await new Promise((resolve5) => {
|
|
151736
|
+
const request = this._queueLoadingCallback(resolve5);
|
|
151649
151737
|
this._prepareFontLoadEvent(font, request);
|
|
151650
151738
|
});
|
|
151651
151739
|
}
|
|
@@ -155985,8 +156073,8 @@ var init_pdf = __esm({
|
|
|
155985
156073
|
this._readCapability = Promise.withResolvers();
|
|
155986
156074
|
this._headersCapability = Promise.withResolvers();
|
|
155987
156075
|
const fs14 = process.getBuiltinModule("fs");
|
|
155988
|
-
fs14.promises.lstat(this._url).then((
|
|
155989
|
-
this._contentLength =
|
|
156076
|
+
fs14.promises.lstat(this._url).then((stat2) => {
|
|
156077
|
+
this._contentLength = stat2.size;
|
|
155990
156078
|
this._setReadableStream(fs14.createReadStream(this._url));
|
|
155991
156079
|
this._headersCapability.resolve();
|
|
155992
156080
|
}, (error) => {
|
|
@@ -157002,14 +157090,14 @@ var init_pdf = __esm({
|
|
|
157002
157090
|
return this.getXfa().then((xfa) => XfaText.textContent(xfa));
|
|
157003
157091
|
}
|
|
157004
157092
|
const readableStream = this.streamTextContent(params);
|
|
157005
|
-
return new Promise(function(
|
|
157093
|
+
return new Promise(function(resolve5, reject2) {
|
|
157006
157094
|
function pump() {
|
|
157007
157095
|
reader.read().then(function({
|
|
157008
157096
|
value,
|
|
157009
157097
|
done
|
|
157010
157098
|
}) {
|
|
157011
157099
|
if (done) {
|
|
157012
|
-
|
|
157100
|
+
resolve5(textContent);
|
|
157013
157101
|
return;
|
|
157014
157102
|
}
|
|
157015
157103
|
textContent.lang ??= value.lang;
|
|
@@ -165106,7 +165194,7 @@ var init_pdf = __esm({
|
|
|
165106
165194
|
input.type = "file";
|
|
165107
165195
|
input.accept = _StampEditor.supportedTypesStr;
|
|
165108
165196
|
const signal = this._uiManager._signal;
|
|
165109
|
-
this.#bitmapPromise = new Promise((
|
|
165197
|
+
this.#bitmapPromise = new Promise((resolve5) => {
|
|
165110
165198
|
input.addEventListener("change", async () => {
|
|
165111
165199
|
if (!input.files || input.files.length === 0) {
|
|
165112
165200
|
this.remove();
|
|
@@ -165121,13 +165209,13 @@ var init_pdf = __esm({
|
|
|
165121
165209
|
});
|
|
165122
165210
|
this.#getBitmapFetched(data);
|
|
165123
165211
|
}
|
|
165124
|
-
|
|
165212
|
+
resolve5();
|
|
165125
165213
|
}, {
|
|
165126
165214
|
signal
|
|
165127
165215
|
});
|
|
165128
165216
|
input.addEventListener("cancel", () => {
|
|
165129
165217
|
this.remove();
|
|
165130
|
-
|
|
165218
|
+
resolve5();
|
|
165131
165219
|
}, {
|
|
165132
165220
|
signal
|
|
165133
165221
|
});
|
|
@@ -170434,13 +170522,13 @@ var require_thenables = __commonJS({
|
|
|
170434
170522
|
promise._captureStackTrace();
|
|
170435
170523
|
if (context) context._popContext();
|
|
170436
170524
|
var synchronous = true;
|
|
170437
|
-
var result2 = util.tryCatch(then).call(x,
|
|
170525
|
+
var result2 = util.tryCatch(then).call(x, resolve5, reject2);
|
|
170438
170526
|
synchronous = false;
|
|
170439
170527
|
if (promise && result2 === errorObj2) {
|
|
170440
170528
|
promise._rejectCallback(result2.e, true, true);
|
|
170441
170529
|
promise = null;
|
|
170442
170530
|
}
|
|
170443
|
-
function
|
|
170531
|
+
function resolve5(value) {
|
|
170444
170532
|
if (!promise) return;
|
|
170445
170533
|
promise._resolveCallback(value);
|
|
170446
170534
|
promise = null;
|
|
@@ -170975,9 +171063,9 @@ var require_debuggability = __commonJS({
|
|
|
170975
171063
|
return false;
|
|
170976
171064
|
}
|
|
170977
171065
|
Promise2.prototype._fireEvent = defaultFireEvent;
|
|
170978
|
-
Promise2.prototype._execute = function(executor,
|
|
171066
|
+
Promise2.prototype._execute = function(executor, resolve5, reject2) {
|
|
170979
171067
|
try {
|
|
170980
|
-
executor(
|
|
171068
|
+
executor(resolve5, reject2);
|
|
170981
171069
|
} catch (e) {
|
|
170982
171070
|
return e;
|
|
170983
171071
|
}
|
|
@@ -171000,10 +171088,10 @@ var require_debuggability = __commonJS({
|
|
|
171000
171088
|
;
|
|
171001
171089
|
;
|
|
171002
171090
|
};
|
|
171003
|
-
function cancellationExecute(executor,
|
|
171091
|
+
function cancellationExecute(executor, resolve5, reject2) {
|
|
171004
171092
|
var promise = this;
|
|
171005
171093
|
try {
|
|
171006
|
-
executor(
|
|
171094
|
+
executor(resolve5, reject2, function(onCancel) {
|
|
171007
171095
|
if (typeof onCancel !== "function") {
|
|
171008
171096
|
throw new TypeError("onCancel must be a function, got: " + util.toString(onCancel));
|
|
171009
171097
|
}
|
|
@@ -173026,15 +173114,15 @@ var require_generators = __commonJS({
|
|
|
173026
173114
|
var stack = new Error().stack;
|
|
173027
173115
|
return function() {
|
|
173028
173116
|
var generator = generatorFunction.apply(this, arguments);
|
|
173029
|
-
var
|
|
173117
|
+
var spawn3 = new PromiseSpawn$(
|
|
173030
173118
|
void 0,
|
|
173031
173119
|
void 0,
|
|
173032
173120
|
yieldHandler,
|
|
173033
173121
|
stack
|
|
173034
173122
|
);
|
|
173035
|
-
var ret2 =
|
|
173036
|
-
|
|
173037
|
-
|
|
173123
|
+
var ret2 = spawn3.promise();
|
|
173124
|
+
spawn3._generator = generator;
|
|
173125
|
+
spawn3._promiseFulfilled(void 0);
|
|
173038
173126
|
return ret2;
|
|
173039
173127
|
};
|
|
173040
173128
|
};
|
|
@@ -173049,9 +173137,9 @@ var require_generators = __commonJS({
|
|
|
173049
173137
|
if (typeof generatorFunction !== "function") {
|
|
173050
173138
|
return apiRejection("generatorFunction must be a function\n\n See http://goo.gl/MqrFmX\n");
|
|
173051
173139
|
}
|
|
173052
|
-
var
|
|
173053
|
-
var ret2 =
|
|
173054
|
-
|
|
173140
|
+
var spawn3 = new PromiseSpawn(generatorFunction, this);
|
|
173141
|
+
var ret2 = spawn3.promise();
|
|
173142
|
+
spawn3._run(Promise2.spawn);
|
|
173055
173143
|
return ret2;
|
|
173056
173144
|
};
|
|
173057
173145
|
};
|
|
@@ -174649,14 +174737,14 @@ var require_promises = __commonJS({
|
|
|
174649
174737
|
});
|
|
174650
174738
|
};
|
|
174651
174739
|
function defer() {
|
|
174652
|
-
var
|
|
174740
|
+
var resolve5;
|
|
174653
174741
|
var reject2;
|
|
174654
174742
|
var promise = new bluebird.Promise(function(resolveArg, rejectArg) {
|
|
174655
|
-
|
|
174743
|
+
resolve5 = resolveArg;
|
|
174656
174744
|
reject2 = rejectArg;
|
|
174657
174745
|
});
|
|
174658
174746
|
return {
|
|
174659
|
-
resolve:
|
|
174747
|
+
resolve: resolve5,
|
|
174660
174748
|
reject: reject2,
|
|
174661
174749
|
promise
|
|
174662
174750
|
};
|
|
@@ -175345,7 +175433,7 @@ var require_BufferList = __commonJS({
|
|
|
175345
175433
|
this.head = this.tail = null;
|
|
175346
175434
|
this.length = 0;
|
|
175347
175435
|
};
|
|
175348
|
-
BufferList.prototype.join = function
|
|
175436
|
+
BufferList.prototype.join = function join2(s) {
|
|
175349
175437
|
if (this.length === 0) return "";
|
|
175350
175438
|
var p = this.head;
|
|
175351
175439
|
var ret2 = "" + p.data;
|
|
@@ -177320,8 +177408,8 @@ var require_lib4 = __commonJS({
|
|
|
177320
177408
|
return this;
|
|
177321
177409
|
}
|
|
177322
177410
|
var p = this.constructor;
|
|
177323
|
-
return this.then(
|
|
177324
|
-
function
|
|
177411
|
+
return this.then(resolve6, reject3);
|
|
177412
|
+
function resolve6(value) {
|
|
177325
177413
|
function yes() {
|
|
177326
177414
|
return value;
|
|
177327
177415
|
}
|
|
@@ -177474,8 +177562,8 @@ var require_lib4 = __commonJS({
|
|
|
177474
177562
|
}
|
|
177475
177563
|
return out;
|
|
177476
177564
|
}
|
|
177477
|
-
Promise2.resolve =
|
|
177478
|
-
function
|
|
177565
|
+
Promise2.resolve = resolve5;
|
|
177566
|
+
function resolve5(value) {
|
|
177479
177567
|
if (value instanceof this) {
|
|
177480
177568
|
return value;
|
|
177481
177569
|
}
|
|
@@ -178006,10 +178094,10 @@ var require_utils2 = __commonJS({
|
|
|
178006
178094
|
var promise = external.Promise.resolve(inputData).then(function(data) {
|
|
178007
178095
|
var isBlob = support.blob && (data instanceof Blob || ["[object File]", "[object Blob]"].indexOf(Object.prototype.toString.call(data)) !== -1);
|
|
178008
178096
|
if (isBlob && typeof FileReader !== "undefined") {
|
|
178009
|
-
return new external.Promise(function(
|
|
178097
|
+
return new external.Promise(function(resolve5, reject2) {
|
|
178010
178098
|
var reader = new FileReader();
|
|
178011
178099
|
reader.onload = function(e) {
|
|
178012
|
-
|
|
178100
|
+
resolve5(e.target.result);
|
|
178013
178101
|
};
|
|
178014
178102
|
reader.onerror = function(e) {
|
|
178015
178103
|
reject2(e.target.error);
|
|
@@ -178564,7 +178652,7 @@ var require_StreamHelper = __commonJS({
|
|
|
178564
178652
|
}
|
|
178565
178653
|
}
|
|
178566
178654
|
function accumulate(helper, updateCallback) {
|
|
178567
|
-
return new external.Promise(function(
|
|
178655
|
+
return new external.Promise(function(resolve5, reject2) {
|
|
178568
178656
|
var dataArray = [];
|
|
178569
178657
|
var chunkType = helper._internalType, resultType = helper._outputType, mimeType = helper._mimeType;
|
|
178570
178658
|
helper.on("data", function(data, meta) {
|
|
@@ -178578,7 +178666,7 @@ var require_StreamHelper = __commonJS({
|
|
|
178578
178666
|
}).on("end", function() {
|
|
178579
178667
|
try {
|
|
178580
178668
|
var result2 = transformZipOutput(resultType, concat(chunkType, dataArray), mimeType);
|
|
178581
|
-
|
|
178669
|
+
resolve5(result2);
|
|
178582
178670
|
} catch (e) {
|
|
178583
178671
|
reject2(e);
|
|
178584
178672
|
}
|
|
@@ -183370,7 +183458,7 @@ var require_ZipFileWorker = __commonJS({
|
|
|
183370
183458
|
var generateDosExternalFileAttr = function(dosPermissions) {
|
|
183371
183459
|
return (dosPermissions || 0) & 63;
|
|
183372
183460
|
};
|
|
183373
|
-
var generateZipParts = function(streamInfo, streamedContent, streamingEnded, offset,
|
|
183461
|
+
var generateZipParts = function(streamInfo, streamedContent, streamingEnded, offset, platform3, encodeFileName) {
|
|
183374
183462
|
var file = streamInfo["file"], compression = streamInfo["compression"], useCustomEncoding = encodeFileName !== utf8.utf8encode, encodedFileName = utils3.transformTo("string", encodeFileName(file.name)), utfEncodedFileName = utils3.transformTo("string", utf8.utf8encode(file.name)), comment = file.comment, encodedComment = utils3.transformTo("string", encodeFileName(comment)), utfEncodedComment = utils3.transformTo("string", utf8.utf8encode(comment)), useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, useUTF8ForComment = utfEncodedComment.length !== comment.length, dosTime, dosDate, extraFields = "", unicodePathExtraField = "", unicodeCommentExtraField = "", dir = file.dir, date = file.date;
|
|
183375
183463
|
var dataInfo = {
|
|
183376
183464
|
crc32: 0,
|
|
@@ -183394,7 +183482,7 @@ var require_ZipFileWorker = __commonJS({
|
|
|
183394
183482
|
if (dir) {
|
|
183395
183483
|
extFileAttr |= 16;
|
|
183396
183484
|
}
|
|
183397
|
-
if (
|
|
183485
|
+
if (platform3 === "UNIX") {
|
|
183398
183486
|
versionMadeBy = 798;
|
|
183399
183487
|
extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
|
|
183400
183488
|
} else {
|
|
@@ -183479,11 +183567,11 @@ var require_ZipFileWorker = __commonJS({
|
|
|
183479
183567
|
decToHex(streamInfo["uncompressedSize"], 4);
|
|
183480
183568
|
return descriptor;
|
|
183481
183569
|
};
|
|
183482
|
-
function ZipFileWorker(streamFiles, comment,
|
|
183570
|
+
function ZipFileWorker(streamFiles, comment, platform3, encodeFileName) {
|
|
183483
183571
|
GenericWorker.call(this, "ZipFileWorker");
|
|
183484
183572
|
this.bytesWritten = 0;
|
|
183485
183573
|
this.zipComment = comment;
|
|
183486
|
-
this.zipPlatform =
|
|
183574
|
+
this.zipPlatform = platform3;
|
|
183487
183575
|
this.encodeFileName = encodeFileName;
|
|
183488
183576
|
this.streamFiles = streamFiles;
|
|
183489
183577
|
this.accumulate = false;
|
|
@@ -184691,7 +184779,7 @@ var require_load = __commonJS({
|
|
|
184691
184779
|
var Crc32Probe = require_Crc32Probe();
|
|
184692
184780
|
var nodejsUtils = require_nodejsUtils();
|
|
184693
184781
|
function checkEntryCRC32(zipEntry) {
|
|
184694
|
-
return new external.Promise(function(
|
|
184782
|
+
return new external.Promise(function(resolve5, reject2) {
|
|
184695
184783
|
var worker = zipEntry.decompressed.getContentWorker().pipe(new Crc32Probe());
|
|
184696
184784
|
worker.on("error", function(e) {
|
|
184697
184785
|
reject2(e);
|
|
@@ -184699,7 +184787,7 @@ var require_load = __commonJS({
|
|
|
184699
184787
|
if (worker.streamInfo.crc32 !== zipEntry.decompressed.crc32) {
|
|
184700
184788
|
reject2(new Error("Corrupted zip : CRC32 mismatch"));
|
|
184701
184789
|
} else {
|
|
184702
|
-
|
|
184790
|
+
resolve5();
|
|
184703
184791
|
}
|
|
184704
184792
|
}).resume();
|
|
184705
184793
|
});
|
|
@@ -194523,7 +194611,7 @@ var require_files = __commonJS({
|
|
|
194523
194611
|
var fs14 = __require("fs");
|
|
194524
194612
|
var url = __require("url");
|
|
194525
194613
|
var os6 = __require("os");
|
|
194526
|
-
var
|
|
194614
|
+
var dirname2 = __require("path").dirname;
|
|
194527
194615
|
var resolvePath2 = __require("path").resolve;
|
|
194528
194616
|
var isAbsolutePath2 = require_path_is_absolute();
|
|
194529
194617
|
var promises = require_promises();
|
|
@@ -194538,10 +194626,10 @@ var require_files = __commonJS({
|
|
|
194538
194626
|
}
|
|
194539
194627
|
};
|
|
194540
194628
|
}
|
|
194541
|
-
var base = options.relativeToFile ?
|
|
194629
|
+
var base = options.relativeToFile ? dirname2(options.relativeToFile) : null;
|
|
194542
194630
|
function read(uri, encoding) {
|
|
194543
194631
|
return resolveUri(uri).then(function(path14) {
|
|
194544
|
-
return
|
|
194632
|
+
return readFile4(path14, encoding).caught(function(error) {
|
|
194545
194633
|
var message = "could not open external image: '" + uri + "' (document directory: '" + base + "')\n" + error.message;
|
|
194546
194634
|
return promises.reject(new Error(message));
|
|
194547
194635
|
});
|
|
@@ -194561,15 +194649,15 @@ var require_files = __commonJS({
|
|
|
194561
194649
|
read
|
|
194562
194650
|
};
|
|
194563
194651
|
}
|
|
194564
|
-
var
|
|
194565
|
-
function uriToPath(uriString,
|
|
194566
|
-
if (!
|
|
194567
|
-
|
|
194652
|
+
var readFile4 = promises.promisify(fs14.readFile.bind(fs14));
|
|
194653
|
+
function uriToPath(uriString, platform3) {
|
|
194654
|
+
if (!platform3) {
|
|
194655
|
+
platform3 = os6.platform();
|
|
194568
194656
|
}
|
|
194569
194657
|
var uri = url.parse(uriString);
|
|
194570
194658
|
if (isLocalFileUri(uri) || isRelativeUri(uri)) {
|
|
194571
194659
|
var path14 = decodeURIComponent(uri.path);
|
|
194572
|
-
if (
|
|
194660
|
+
if (platform3 === "win32" && /^\/[a-z]:/i.test(path14)) {
|
|
194573
194661
|
return path14.slice(1);
|
|
194574
194662
|
} else {
|
|
194575
194663
|
return path14;
|
|
@@ -197278,10 +197366,10 @@ var require_unzip = __commonJS({
|
|
|
197278
197366
|
var promises = require_promises();
|
|
197279
197367
|
var zipfile = require_zipfile();
|
|
197280
197368
|
exports2.openZip = openZip;
|
|
197281
|
-
var
|
|
197369
|
+
var readFile4 = promises.promisify(fs14.readFile);
|
|
197282
197370
|
function openZip(options) {
|
|
197283
197371
|
if (options.path) {
|
|
197284
|
-
return
|
|
197372
|
+
return readFile4(options.path).then(zipfile.openArrayBuffer);
|
|
197285
197373
|
} else if (options.buffer) {
|
|
197286
197374
|
return promises.resolve(zipfile.openArrayBuffer(options.buffer));
|
|
197287
197375
|
} else if (options.file) {
|
|
@@ -198080,8 +198168,8 @@ async function resolvePlaybookInputs(args) {
|
|
|
198080
198168
|
return {
|
|
198081
198169
|
ok: false,
|
|
198082
198170
|
status: "blocked",
|
|
198083
|
-
errorCode: "
|
|
198084
|
-
message: "Managed playbooks require the
|
|
198171
|
+
errorCode: "local_runtime_unavailable",
|
|
198172
|
+
message: "Managed playbooks require the local runtime for source discovery and file reads.",
|
|
198085
198173
|
folderPath: rawFolderPath,
|
|
198086
198174
|
warnings: []
|
|
198087
198175
|
};
|
|
@@ -198417,9 +198505,9 @@ async function resolveScopedLocalSourceId(localSourceIdOrRelativePath, scopedWor
|
|
|
198417
198505
|
if (localSourceIdOrRelativePath.includes("::")) return localSourceIdOrRelativePath;
|
|
198418
198506
|
const scope = await resolveLocalSourceScope(scopedWorkspaceRoot);
|
|
198419
198507
|
if (!scope) return localSourceIdOrRelativePath;
|
|
198420
|
-
const
|
|
198508
|
+
const relative2 = normalizeRelativePath(localSourceIdOrRelativePath);
|
|
198421
198509
|
const prefix = normalizeRelativePath(scope.relativePrefix);
|
|
198422
|
-
const scopedRelative = [prefix,
|
|
198510
|
+
const scopedRelative = [prefix, relative2].filter(Boolean).join("/");
|
|
198423
198511
|
return `${scope.rootId}::${scopedRelative}`;
|
|
198424
198512
|
}
|
|
198425
198513
|
async function resolveApprovedLocalSourceIdForAbsolutePath(pathValue) {
|
|
@@ -199442,7 +199530,6 @@ function containsBrowserDeliveryTask(tasks) {
|
|
|
199442
199530
|
var BROWSER_DELIVERY_ROLE_IDS;
|
|
199443
199531
|
var init_browserDeliveryLock = __esm({
|
|
199444
199532
|
"features/perchTerminal/agentPlatform/browserDeliveryLock.ts"() {
|
|
199445
|
-
"use strict";
|
|
199446
199533
|
BROWSER_DELIVERY_ROLE_IDS = /* @__PURE__ */ new Set([
|
|
199447
199534
|
"doc_writer",
|
|
199448
199535
|
"email_sender",
|
|
@@ -199813,6 +199900,30 @@ function abortRuntimeRun(runId, reason = "Run cancelled.") {
|
|
|
199813
199900
|
cleanupRun(record);
|
|
199814
199901
|
return true;
|
|
199815
199902
|
}
|
|
199903
|
+
function submitRuntimeSteer(input) {
|
|
199904
|
+
const runId = input.runId?.trim();
|
|
199905
|
+
if (!runId) return { ok: false, error: "No active turn to steer." };
|
|
199906
|
+
if (input.expectedRunId && input.expectedRunId !== runId) {
|
|
199907
|
+
return { ok: false, error: `Expected active turn ${input.expectedRunId}, found ${runId}.` };
|
|
199908
|
+
}
|
|
199909
|
+
const record = getRuntimeRun(runId);
|
|
199910
|
+
if (!record || record.status !== "running" || record.controller.signal.aborted) {
|
|
199911
|
+
return { ok: false, error: "No active turn to steer." };
|
|
199912
|
+
}
|
|
199913
|
+
if (input.threadId && record.threadId && input.threadId !== record.threadId) {
|
|
199914
|
+
return { ok: false, error: "Active turn belongs to a different thread." };
|
|
199915
|
+
}
|
|
199916
|
+
const text = input.text.trim();
|
|
199917
|
+
if (!text) return { ok: false, error: "Steer input cannot be empty." };
|
|
199918
|
+
record.steerQueue.push({
|
|
199919
|
+
text,
|
|
199920
|
+
mode: input.mode ?? "append",
|
|
199921
|
+
clientMessageId: input.clientMessageId ?? null,
|
|
199922
|
+
submittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
199923
|
+
});
|
|
199924
|
+
record.updatedAt = nowMs();
|
|
199925
|
+
return { ok: true, turnId: runId };
|
|
199926
|
+
}
|
|
199816
199927
|
function consumeRuntimeSteers(runId) {
|
|
199817
199928
|
const record = getRuntimeRun(runId);
|
|
199818
199929
|
if (!record || record.status !== "running" || record.controller.signal.aborted) return [];
|
|
@@ -201827,8 +201938,8 @@ function buildWorkerSourceManifest(input) {
|
|
|
201827
201938
|
const exactNames = extractExplicitFileNames(input.objective);
|
|
201828
201939
|
const maxEntries = Math.max(1, Math.min(200, input.maxEntries ?? 80));
|
|
201829
201940
|
const candidates = sources.filter((source) => !isExcludedPath(source.relativePath)).filter((source) => {
|
|
201830
|
-
const
|
|
201831
|
-
if (selectedPrefixes.length > 0 && selectedPrefixes.some((prefix) =>
|
|
201941
|
+
const relative2 = normalize2(source.relativePath);
|
|
201942
|
+
if (selectedPrefixes.length > 0 && selectedPrefixes.some((prefix) => relative2.startsWith(`${prefix}/`) || relative2 === prefix)) {
|
|
201832
201943
|
return true;
|
|
201833
201944
|
}
|
|
201834
201945
|
if (exactNames.size > 0 && exactNames.has(source.fileName.toLowerCase())) {
|
|
@@ -201893,17 +202004,17 @@ function extractExplicitFileNames(objective) {
|
|
|
201893
202004
|
return names;
|
|
201894
202005
|
}
|
|
201895
202006
|
function sourceSortScore(source, objective) {
|
|
201896
|
-
const
|
|
202007
|
+
const relative2 = normalize2(source.relativePath);
|
|
201897
202008
|
const file = source.fileName.toLowerCase();
|
|
201898
202009
|
let score = 0;
|
|
201899
202010
|
if (objective.includes(file)) score += 100;
|
|
201900
|
-
if (
|
|
202011
|
+
if (relative2.includes("perch-output") || relative2.includes("perch-artifacts")) score -= 1e3;
|
|
201901
202012
|
if (/_\d{3}\.(?:txt|csv|md)$/i.test(file)) score -= 15;
|
|
201902
202013
|
if (file.endsWith(".csv")) score += 8;
|
|
201903
202014
|
if (file.endsWith(".txt") || file.endsWith(".md")) score += 5;
|
|
201904
202015
|
if (file.endsWith(".pdf")) score -= 3;
|
|
201905
202016
|
for (const token of objective.split(/[^a-z0-9]+/i).filter((t) => t.length >= 4)) {
|
|
201906
|
-
if (
|
|
202017
|
+
if (relative2.includes(token.toLowerCase())) score += 2;
|
|
201907
202018
|
}
|
|
201908
202019
|
return score;
|
|
201909
202020
|
}
|
|
@@ -202331,13 +202442,13 @@ function clamp2(value, min2, max2) {
|
|
|
202331
202442
|
return Math.max(min2, Math.min(max2, value));
|
|
202332
202443
|
}
|
|
202333
202444
|
function loadImage(dataUrl) {
|
|
202334
|
-
return new Promise((
|
|
202445
|
+
return new Promise((resolve5, reject2) => {
|
|
202335
202446
|
if (typeof Image === "undefined") {
|
|
202336
202447
|
reject2(new Error("Image API unavailable"));
|
|
202337
202448
|
return;
|
|
202338
202449
|
}
|
|
202339
202450
|
const image2 = new Image();
|
|
202340
|
-
image2.onload = () =>
|
|
202451
|
+
image2.onload = () => resolve5(image2);
|
|
202341
202452
|
image2.onerror = () => reject2(new Error("Failed to decode screenshot"));
|
|
202342
202453
|
image2.src = dataUrl;
|
|
202343
202454
|
});
|
|
@@ -202465,9 +202576,9 @@ function fitInside(width, height, maxWidth, maxHeight) {
|
|
|
202465
202576
|
};
|
|
202466
202577
|
}
|
|
202467
202578
|
async function loadImageElement(dataUrl) {
|
|
202468
|
-
return new Promise((
|
|
202579
|
+
return new Promise((resolve5, reject2) => {
|
|
202469
202580
|
const img = new Image();
|
|
202470
|
-
img.onload = () =>
|
|
202581
|
+
img.onload = () => resolve5(img);
|
|
202471
202582
|
img.onerror = () => reject2(new Error("Failed to decode screenshot data URL"));
|
|
202472
202583
|
img.src = dataUrl;
|
|
202473
202584
|
});
|
|
@@ -203689,14 +203800,14 @@ function adapterDriver(ctx) {
|
|
|
203689
203800
|
);
|
|
203690
203801
|
}
|
|
203691
203802
|
function adapterDelay(ms, signal) {
|
|
203692
|
-
return new Promise((
|
|
203803
|
+
return new Promise((resolve5, reject2) => {
|
|
203693
203804
|
if (signal?.aborted) {
|
|
203694
203805
|
reject2(new DOMException("Adapter wait cancelled.", "AbortError"));
|
|
203695
203806
|
return;
|
|
203696
203807
|
}
|
|
203697
203808
|
const timeout = setTimeout(() => {
|
|
203698
203809
|
signal?.removeEventListener("abort", onAbort);
|
|
203699
|
-
|
|
203810
|
+
resolve5();
|
|
203700
203811
|
}, ms);
|
|
203701
203812
|
const onAbort = () => {
|
|
203702
203813
|
clearTimeout(timeout);
|
|
@@ -205289,8 +205400,8 @@ var init_GoogleDocsAdapter = __esm({
|
|
|
205289
205400
|
|
|
205290
205401
|
// features/perchTerminal/runtime/playwright/adapters/GoogleSheetsAdapter.ts
|
|
205291
205402
|
function shortcut2(key) {
|
|
205292
|
-
const
|
|
205293
|
-
return /mac/i.test(
|
|
205403
|
+
const platform3 = typeof navigator === "undefined" ? "" : navigator.platform;
|
|
205404
|
+
return /mac/i.test(platform3) ? `Meta+${key}` : `Control+${key}`;
|
|
205294
205405
|
}
|
|
205295
205406
|
var GoogleSheetsAdapter;
|
|
205296
205407
|
var init_GoogleSheetsAdapter = __esm({
|
|
@@ -205861,14 +205972,14 @@ async function runAPAuditPacketAdapter(args) {
|
|
|
205861
205972
|
const folderPath = (args.folderPath ?? "").trim();
|
|
205862
205973
|
if (!isDesktopAvailable()) {
|
|
205863
205974
|
return blockedEnvelope({
|
|
205864
|
-
reason: "AP audit packet requires the
|
|
205865
|
-
errorCode: "
|
|
205975
|
+
reason: "AP audit packet requires the local runtime for filesystem access. The browser cannot read the user's filesystem.",
|
|
205976
|
+
errorCode: "local_runtime_unavailable",
|
|
205866
205977
|
folderPath: folderPath || null
|
|
205867
205978
|
});
|
|
205868
205979
|
}
|
|
205869
205980
|
if (!desktopAPAuditAvailable()) {
|
|
205870
205981
|
return blockedEnvelope({
|
|
205871
|
-
reason: "This Perch
|
|
205982
|
+
reason: "This Perch build does not expose runLocalAPAuditPacket. Update Perch CLI or rebuild the app package.",
|
|
205872
205983
|
errorCode: "capability_unavailable",
|
|
205873
205984
|
folderPath: folderPath || null
|
|
205874
205985
|
});
|
|
@@ -206091,14 +206202,14 @@ function preflight(toolName) {
|
|
|
206091
206202
|
if (!isDesktopAvailable()) {
|
|
206092
206203
|
return blocked({
|
|
206093
206204
|
toolName,
|
|
206094
|
-
reason: "AP evidence tools require the
|
|
206095
|
-
errorCode: "
|
|
206205
|
+
reason: "AP evidence tools require the local runtime for filesystem access.",
|
|
206206
|
+
errorCode: "local_runtime_unavailable"
|
|
206096
206207
|
});
|
|
206097
206208
|
}
|
|
206098
206209
|
if (!desktopAPEvidenceAvailable()) {
|
|
206099
206210
|
return blocked({
|
|
206100
206211
|
toolName,
|
|
206101
|
-
reason: "This Perch
|
|
206212
|
+
reason: "This Perch build does not expose AP evidence tools. Update Perch CLI or rebuild the app package.",
|
|
206102
206213
|
errorCode: "capability_unavailable"
|
|
206103
206214
|
});
|
|
206104
206215
|
}
|
|
@@ -206849,13 +206960,13 @@ function blocked2(reason, errorCode) {
|
|
|
206849
206960
|
async function runSandboxAnalysisAdapter(args, opts) {
|
|
206850
206961
|
if (!isDesktopAvailable()) {
|
|
206851
206962
|
return blocked2(
|
|
206852
|
-
"runSandboxAnalysis requires the
|
|
206853
|
-
"
|
|
206963
|
+
"runSandboxAnalysis requires the local runtime. The browser cannot execute sandbox jobs against local sources.",
|
|
206964
|
+
"local_runtime_unavailable"
|
|
206854
206965
|
);
|
|
206855
206966
|
}
|
|
206856
206967
|
if (!desktopSandboxAnalysisAvailable()) {
|
|
206857
206968
|
return blocked2(
|
|
206858
|
-
"This Perch
|
|
206969
|
+
"This Perch build does not expose runSandboxAnalysisJob. Update Perch CLI or rebuild the app package.",
|
|
206859
206970
|
"capability_unavailable"
|
|
206860
206971
|
);
|
|
206861
206972
|
}
|
|
@@ -210307,6 +210418,7 @@ function buildContextSnapshotFromMetrics(threadId, metrics) {
|
|
|
210307
210418
|
consecutiveAutoCompactFailures: metrics.consecutiveAutoCompactFailures ?? 0,
|
|
210308
210419
|
autoCompactedAtIso: metrics.autoCompactedAtIso ?? null,
|
|
210309
210420
|
autoCompactedMessageCount: metrics.autoCompactedMessageCount,
|
|
210421
|
+
compactionReport: metrics.compactionReport,
|
|
210310
210422
|
contextResetAtIso: metrics.resetAtIso ?? null,
|
|
210311
210423
|
builtAtIso: builtAt,
|
|
210312
210424
|
createdAt: builtAt
|
|
@@ -210357,7 +210469,7 @@ function validateSuitePlan(plan, opts) {
|
|
|
210357
210469
|
};
|
|
210358
210470
|
}
|
|
210359
210471
|
if (opts?.desktopConnected === false) {
|
|
210360
|
-
return { valid: false, reason: "
|
|
210472
|
+
return { valid: false, reason: "Local runtime required for workflow tools." };
|
|
210361
210473
|
}
|
|
210362
210474
|
return { valid: true };
|
|
210363
210475
|
}
|
|
@@ -212685,6 +212797,29 @@ var init_localSources = __esm({
|
|
|
212685
212797
|
classification: { native: false },
|
|
212686
212798
|
handler: async (args, ctx) => {
|
|
212687
212799
|
const workspaceRoot = effectiveWorkspaceRoot(ctx);
|
|
212800
|
+
const explicitPath = typeof args.path === "string" && args.path.trim() ? args.path.trim() : "";
|
|
212801
|
+
if (explicitPath) {
|
|
212802
|
+
const query2 = typeof args.query === "string" ? args.query.trim().toLowerCase() : "";
|
|
212803
|
+
const maxResults2 = sanitizeListLocalSourcesMaxResults(args.maxResults);
|
|
212804
|
+
const globbed = await listWorkspaceFilesGlob({
|
|
212805
|
+
workspaceRoot: explicitPath,
|
|
212806
|
+
pattern: "*",
|
|
212807
|
+
maxResults: MAX_LIST_LOCAL_SOURCES_MAX_RESULTS,
|
|
212808
|
+
fsAccessOverride: "allow_once"
|
|
212809
|
+
});
|
|
212810
|
+
const allMatches = globbed?.matches ?? [];
|
|
212811
|
+
const filtered = (query2 ? allMatches.filter((m) => m.toLowerCase().includes(query2)) : allMatches).slice(0, maxResults2);
|
|
212812
|
+
return {
|
|
212813
|
+
ok: true,
|
|
212814
|
+
scopedFolderPath: explicitPath,
|
|
212815
|
+
viaGlob: true,
|
|
212816
|
+
query: query2 || null,
|
|
212817
|
+
sources: filtered,
|
|
212818
|
+
matches: filtered,
|
|
212819
|
+
totalFound: globbed?.totalFound ?? allMatches.length,
|
|
212820
|
+
truncated: allMatches.length > maxResults2
|
|
212821
|
+
};
|
|
212822
|
+
}
|
|
212688
212823
|
const scope = await resolveLocalSourceScope(workspaceRoot);
|
|
212689
212824
|
if (!scope) {
|
|
212690
212825
|
const globRoot = typeof args.path === "string" && args.path.trim() || workspaceRoot?.trim() || "";
|
|
@@ -212746,7 +212881,7 @@ var init_localSources = __esm({
|
|
|
212746
212881
|
const requestedLocalSourceId = String(
|
|
212747
212882
|
args.localSourceId ?? args.path ?? args.filePath ?? ""
|
|
212748
212883
|
);
|
|
212749
|
-
const looksLikePath = isAbsolute3(requestedLocalSourceId.trim()) || !requestedLocalSourceId.includes("::") && requestedLocalSourceId.includes("/");
|
|
212884
|
+
const looksLikePath = isAbsolute3(requestedLocalSourceId.trim()) || requestedLocalSourceId.trim().startsWith("~/") || !requestedLocalSourceId.includes("::") && requestedLocalSourceId.includes("/");
|
|
212750
212885
|
if (looksLikePath) {
|
|
212751
212886
|
const r = await readWorkspaceFile({
|
|
212752
212887
|
workspaceRoot,
|
|
@@ -213026,7 +213161,7 @@ var init_config2 = __esm({
|
|
|
213026
213161
|
ok: true,
|
|
213027
213162
|
configured: false,
|
|
213028
213163
|
servers: [],
|
|
213029
|
-
note: "
|
|
213164
|
+
note: "MCP servers are not connected in this runtime."
|
|
213030
213165
|
};
|
|
213031
213166
|
}
|
|
213032
213167
|
const { getMcpStatus: getMcpStatus2 } = await Promise.resolve().then(() => (init_bridge(), bridge_exports));
|
|
@@ -213861,7 +213996,7 @@ async function executeToolCall(call, opts) {
|
|
|
213861
213996
|
startMs,
|
|
213862
213997
|
startedAt,
|
|
213863
213998
|
code: "tool_desktop_required",
|
|
213864
|
-
message: "
|
|
213999
|
+
message: "Local runtime not available. Local tools require Perch Desktop or CLI local mode.",
|
|
213865
214000
|
riskLevel: policy.riskLevel,
|
|
213866
214001
|
desktopRequired: true
|
|
213867
214002
|
});
|
|
@@ -214051,7 +214186,7 @@ async function resolveFsAccessForTool(input) {
|
|
|
214051
214186
|
function waitForCapabilityResolution(promise, signal) {
|
|
214052
214187
|
if (!signal) return promise;
|
|
214053
214188
|
if (signal.aborted) return Promise.reject(new DOMException("Capability wait cancelled.", "AbortError"));
|
|
214054
|
-
return new Promise((
|
|
214189
|
+
return new Promise((resolve5, reject2) => {
|
|
214055
214190
|
const onAbort = () => {
|
|
214056
214191
|
signal.removeEventListener("abort", onAbort);
|
|
214057
214192
|
reject2(new DOMException("Capability wait cancelled.", "AbortError"));
|
|
@@ -214060,7 +214195,7 @@ function waitForCapabilityResolution(promise, signal) {
|
|
|
214060
214195
|
promise.then(
|
|
214061
214196
|
(value) => {
|
|
214062
214197
|
signal.removeEventListener("abort", onAbort);
|
|
214063
|
-
|
|
214198
|
+
resolve5(value);
|
|
214064
214199
|
},
|
|
214065
214200
|
(error) => {
|
|
214066
214201
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -214799,14 +214934,103 @@ function pruneBrowserArtifactsInMessages(messages) {
|
|
|
214799
214934
|
}
|
|
214800
214935
|
return pruned;
|
|
214801
214936
|
}
|
|
214802
|
-
function
|
|
214803
|
-
|
|
214804
|
-
|
|
214937
|
+
function resolvePostCompactTargetTokens(contextLimitTokens) {
|
|
214938
|
+
const limit = Number.isFinite(contextLimitTokens) && contextLimitTokens > 0 ? Math.floor(contextLimitTokens) : 128e3;
|
|
214939
|
+
const windowScaled = Math.floor(limit * 0.25);
|
|
214940
|
+
return Math.max(
|
|
214941
|
+
POST_COMPACT_MIN_TARGET_TOKENS,
|
|
214942
|
+
Math.min(
|
|
214943
|
+
POST_COMPACT_MAX_TARGET_TOKENS,
|
|
214944
|
+
POST_COMPACT_TARGET_TOKENS,
|
|
214945
|
+
windowScaled
|
|
214946
|
+
)
|
|
214947
|
+
);
|
|
214948
|
+
}
|
|
214949
|
+
function estimateSingleMessageTokens(message, modelContext) {
|
|
214950
|
+
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? "");
|
|
214951
|
+
let tokens = tokenizeText(`${message.role}: ${content}`, modelContext).tokenCount;
|
|
214952
|
+
if (message.tool_calls?.length) {
|
|
214953
|
+
tokens += tokenizeText(JSON.stringify(message.tool_calls), modelContext).tokenCount;
|
|
214805
214954
|
}
|
|
214806
|
-
|
|
214955
|
+
return Math.max(1, tokens);
|
|
214956
|
+
}
|
|
214957
|
+
function adjustTailStartForToolPairs(messages, startIndex) {
|
|
214958
|
+
if (startIndex <= 0) return startIndex;
|
|
214959
|
+
const missingToolCallIds = /* @__PURE__ */ new Set();
|
|
214960
|
+
for (let i = startIndex; i < messages.length; i += 1) {
|
|
214961
|
+
const msg = messages[i];
|
|
214962
|
+
if (msg?.role === "tool" && msg.tool_call_id) {
|
|
214963
|
+
missingToolCallIds.add(msg.tool_call_id);
|
|
214964
|
+
}
|
|
214965
|
+
if (msg?.role === "assistant" && msg.tool_calls?.length) {
|
|
214966
|
+
for (const call of msg.tool_calls) missingToolCallIds.delete(call.id);
|
|
214967
|
+
}
|
|
214968
|
+
}
|
|
214969
|
+
if (missingToolCallIds.size === 0) return startIndex;
|
|
214970
|
+
let nextStart = startIndex;
|
|
214971
|
+
for (let i = startIndex - 1; i >= 0 && missingToolCallIds.size > 0; i -= 1) {
|
|
214972
|
+
const msg = messages[i];
|
|
214973
|
+
if (msg.role !== "assistant" || !msg.tool_calls?.length) continue;
|
|
214974
|
+
const matches = msg.tool_calls.some((call) => missingToolCallIds.has(call.id));
|
|
214975
|
+
if (!matches) continue;
|
|
214976
|
+
nextStart = i;
|
|
214977
|
+
for (const call of msg.tool_calls) missingToolCallIds.delete(call.id);
|
|
214978
|
+
}
|
|
214979
|
+
return nextStart;
|
|
214980
|
+
}
|
|
214981
|
+
function selectRecentWireMessagesByTokenBudget(wireMessages, input) {
|
|
214982
|
+
if (wireMessages.length === 0) {
|
|
214983
|
+
return { recent: [], recentTailTokens: 0, startIndex: 0 };
|
|
214984
|
+
}
|
|
214985
|
+
const minMessages = Math.max(1, input.minMessages ?? RECENT_MESSAGES_KEEP_COUNT);
|
|
214986
|
+
const tokenBudget = Math.max(1, Math.floor(input.tokenBudget));
|
|
214987
|
+
let startIndex = wireMessages.length;
|
|
214988
|
+
let tokens = 0;
|
|
214989
|
+
for (let i = wireMessages.length - 1; i >= 0; i -= 1) {
|
|
214990
|
+
const messageTokens = estimateSingleMessageTokens(wireMessages[i], input.modelContext);
|
|
214991
|
+
const selectedCount = wireMessages.length - startIndex;
|
|
214992
|
+
const mustKeep = selectedCount === 0;
|
|
214993
|
+
if (!mustKeep && tokens + messageTokens > tokenBudget) break;
|
|
214994
|
+
tokens += messageTokens;
|
|
214995
|
+
startIndex = i;
|
|
214996
|
+
if (selectedCount + 1 >= minMessages && tokens >= tokenBudget) break;
|
|
214997
|
+
}
|
|
214998
|
+
const adjustedStart = adjustTailStartForToolPairs(wireMessages, startIndex);
|
|
214999
|
+
if (adjustedStart !== startIndex) {
|
|
215000
|
+
startIndex = adjustedStart;
|
|
215001
|
+
tokens = wireMessages.slice(startIndex).reduce(
|
|
215002
|
+
(sum, message) => sum + estimateSingleMessageTokens(message, input.modelContext),
|
|
215003
|
+
0
|
|
215004
|
+
);
|
|
215005
|
+
}
|
|
215006
|
+
return {
|
|
215007
|
+
recent: wireMessages.slice(startIndex),
|
|
215008
|
+
recentTailTokens: tokens,
|
|
215009
|
+
startIndex
|
|
215010
|
+
};
|
|
215011
|
+
}
|
|
215012
|
+
function resolveRecentTailBudgetTokens(input) {
|
|
215013
|
+
const nonMessageTokens = input.breakdownAfterPrune.system + input.breakdownAfterPrune.tools + input.breakdownAfterPrune.overhead;
|
|
215014
|
+
const available = input.postCompactTargetTokens - nonMessageTokens - COMPACT_SUMMARY_RESERVE_TOKENS;
|
|
215015
|
+
return Math.max(
|
|
215016
|
+
POST_COMPACT_RECENT_TAIL_MIN_TOKENS,
|
|
215017
|
+
Math.min(POST_COMPACT_RECENT_TAIL_MAX_TOKENS, available)
|
|
215018
|
+
);
|
|
215019
|
+
}
|
|
215020
|
+
function splitMessagesForCompaction(wireMessages, input) {
|
|
215021
|
+
const { recent, recentTailTokens, startIndex } = selectRecentWireMessagesByTokenBudget(
|
|
215022
|
+
wireMessages,
|
|
215023
|
+
{
|
|
215024
|
+
modelContext: input.modelContext,
|
|
215025
|
+
tokenBudget: input.recentTailTokenBudget,
|
|
215026
|
+
minMessages: input.minMessages
|
|
215027
|
+
}
|
|
215028
|
+
);
|
|
214807
215029
|
return {
|
|
214808
|
-
toSummarize: wireMessages.slice(0,
|
|
214809
|
-
recent
|
|
215030
|
+
toSummarize: wireMessages.slice(0, startIndex),
|
|
215031
|
+
recent,
|
|
215032
|
+
recentTailTokens,
|
|
215033
|
+
compactedThroughWireIndex: startIndex > 0 ? startIndex - 1 : null
|
|
214810
215034
|
};
|
|
214811
215035
|
}
|
|
214812
215036
|
function formatMessagesForSummary(messages) {
|
|
@@ -214901,6 +215125,11 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
214901
215125
|
});
|
|
214902
215126
|
const contextLimitTokens = resolveEffectiveContextLimit(input.option);
|
|
214903
215127
|
const compactThreshold = getAutoCompactThreshold(input.option);
|
|
215128
|
+
const postCompactTargetTokens = resolvePostCompactTargetTokens(contextLimitTokens);
|
|
215129
|
+
const recentTailTokenBudget = resolveRecentTailBudgetTokens({
|
|
215130
|
+
postCompactTargetTokens,
|
|
215131
|
+
breakdownAfterPrune
|
|
215132
|
+
});
|
|
214904
215133
|
let breakdown = breakdownAfterPrune;
|
|
214905
215134
|
const calibrationRatio = typeof input.priorApiContextTokens === "number" && input.priorApiContextTokens > 0 && typeof input.priorEstimateTokens === "number" && input.priorEstimateTokens > 0 ? Math.min(4, Math.max(1, input.priorApiContextTokens / input.priorEstimateTokens)) : 1;
|
|
214906
215135
|
const anchoredTokens = (estimateTotal) => Math.ceil(estimateTotal * calibrationRatio);
|
|
@@ -214929,10 +215158,16 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
214929
215158
|
}
|
|
214930
215159
|
}
|
|
214931
215160
|
if (autoCompactEnabled && anchoredTokens(breakdown.total) >= compactThreshold) {
|
|
214932
|
-
const {
|
|
214933
|
-
|
|
214934
|
-
|
|
214935
|
-
|
|
215161
|
+
const {
|
|
215162
|
+
toSummarize,
|
|
215163
|
+
recent,
|
|
215164
|
+
recentTailTokens,
|
|
215165
|
+
compactedThroughWireIndex
|
|
215166
|
+
} = splitMessagesForCompaction(working, {
|
|
215167
|
+
modelContext,
|
|
215168
|
+
recentTailTokenBudget,
|
|
215169
|
+
minMessages: RECENT_MESSAGES_KEEP_COUNT
|
|
215170
|
+
});
|
|
214936
215171
|
if (toSummarize.length > 0) {
|
|
214937
215172
|
const summary = await summarizeMessagesForCompaction({
|
|
214938
215173
|
priorSummary: input.compactedSummary,
|
|
@@ -214946,6 +215181,7 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
214946
215181
|
signal: input.signal
|
|
214947
215182
|
});
|
|
214948
215183
|
if (summary) {
|
|
215184
|
+
const compactedAtIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
214949
215185
|
const compactedMessages = buildCompactedWireMessages(summary, recent);
|
|
214950
215186
|
working.length = 0;
|
|
214951
215187
|
working.push(...compactedMessages);
|
|
@@ -214956,20 +215192,45 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
214956
215192
|
toolDefinitionsJson,
|
|
214957
215193
|
modelContext
|
|
214958
215194
|
});
|
|
215195
|
+
const tokensAfter = anchoredTokens(breakdown.total);
|
|
215196
|
+
const summaryTokens = tokenizeText(summary, modelContext).tokenCount;
|
|
215197
|
+
const compactionReport = {
|
|
215198
|
+
tokensBefore: tokensBeforeCompact,
|
|
215199
|
+
tokensAfter,
|
|
215200
|
+
targetTokens: postCompactTargetTokens,
|
|
215201
|
+
summaryTokens,
|
|
215202
|
+
recentTailTokens,
|
|
215203
|
+
recentTailMessages: recent.length,
|
|
215204
|
+
summarizedMessages: toSummarize.length,
|
|
215205
|
+
restoredToolsOrFiles: 0
|
|
215206
|
+
};
|
|
214959
215207
|
compactionState = {
|
|
214960
215208
|
compactedSummary: summary,
|
|
214961
215209
|
tokensBefore: tokensBeforeCompact,
|
|
214962
|
-
tokensAfter
|
|
215210
|
+
tokensAfter,
|
|
214963
215211
|
autoCompactEnabled: true,
|
|
214964
215212
|
effectiveContextLimitTokens: contextLimitTokens,
|
|
214965
|
-
compactedAtIso
|
|
215213
|
+
compactedAtIso,
|
|
215214
|
+
compactBoundary: {
|
|
215215
|
+
kind: "auto",
|
|
215216
|
+
compactedAtIso,
|
|
215217
|
+
compactedThroughWireIndex
|
|
215218
|
+
},
|
|
215219
|
+
compactionReport
|
|
214966
215220
|
};
|
|
214967
215221
|
input.onEvent?.({
|
|
214968
215222
|
type: "context_compacted",
|
|
214969
215223
|
tokensBefore: tokensBeforeCompact,
|
|
214970
|
-
tokensAfter
|
|
215224
|
+
tokensAfter,
|
|
214971
215225
|
summary,
|
|
214972
|
-
|
|
215226
|
+
compactionKind: "auto",
|
|
215227
|
+
targetTokens: postCompactTargetTokens,
|
|
215228
|
+
summaryTokens,
|
|
215229
|
+
recentTailTokens,
|
|
215230
|
+
recentTailMessages: recent.length,
|
|
215231
|
+
summarizedMessages: toSummarize.length,
|
|
215232
|
+
restoredToolsOrFiles: 0,
|
|
215233
|
+
ts: compactedAtIso
|
|
214973
215234
|
});
|
|
214974
215235
|
}
|
|
214975
215236
|
}
|
|
@@ -215005,7 +215266,7 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
215005
215266
|
microcompactedToolResults
|
|
215006
215267
|
};
|
|
215007
215268
|
}
|
|
215008
|
-
var OPERATOR_SCREENSHOT_MARKER2, KEPT_SNAPSHOT_MAX_CHARS, KEPT_SNAPSHOT_TRUNCATED_MARKER, BROWSER_TOOL_NAMES, RECENT_MESSAGES_KEEP_COUNT, RECENT_TOOL_RESULTS_KEEP_COUNT, MICROCOMPACT_CLEARED_MARKER, COMPACT_SUMMARY_RESERVE_TOKENS, COMPACT_SYSTEM_PROMPT;
|
|
215269
|
+
var OPERATOR_SCREENSHOT_MARKER2, KEPT_SNAPSHOT_MAX_CHARS, KEPT_SNAPSHOT_TRUNCATED_MARKER, BROWSER_TOOL_NAMES, RECENT_MESSAGES_KEEP_COUNT, RECENT_TOOL_RESULTS_KEEP_COUNT, POST_COMPACT_TARGET_TOKENS, POST_COMPACT_MIN_TARGET_TOKENS, POST_COMPACT_MAX_TARGET_TOKENS, POST_COMPACT_RECENT_TAIL_MIN_TOKENS, POST_COMPACT_RECENT_TAIL_MAX_TOKENS, MICROCOMPACT_CLEARED_MARKER, COMPACT_SUMMARY_RESERVE_TOKENS, COMPACT_SYSTEM_PROMPT;
|
|
215009
215270
|
var init_contextLoopCompaction = __esm({
|
|
215010
215271
|
"features/perchTerminal/runtime/services/contextLoopCompaction.ts"() {
|
|
215011
215272
|
"use strict";
|
|
@@ -215035,6 +215296,11 @@ var init_contextLoopCompaction = __esm({
|
|
|
215035
215296
|
]);
|
|
215036
215297
|
RECENT_MESSAGES_KEEP_COUNT = 12;
|
|
215037
215298
|
RECENT_TOOL_RESULTS_KEEP_COUNT = 6;
|
|
215299
|
+
POST_COMPACT_TARGET_TOKENS = 32e3;
|
|
215300
|
+
POST_COMPACT_MIN_TARGET_TOKENS = 2e4;
|
|
215301
|
+
POST_COMPACT_MAX_TARGET_TOKENS = 4e4;
|
|
215302
|
+
POST_COMPACT_RECENT_TAIL_MIN_TOKENS = 4e3;
|
|
215303
|
+
POST_COMPACT_RECENT_TAIL_MAX_TOKENS = 24e3;
|
|
215038
215304
|
MICROCOMPACT_CLEARED_MARKER = "[Old tool result content cleared to free context]";
|
|
215039
215305
|
COMPACT_SUMMARY_RESERVE_TOKENS = 4096;
|
|
215040
215306
|
COMPACT_SYSTEM_PROMPT = `You summarize conversation history for a delivery assistant using Google Docs, Gmail, Calendar, and browser tools.
|
|
@@ -217109,15 +217375,15 @@ async function dumpModelPayloadIfRequested(input) {
|
|
|
217109
217375
|
const dumpDir = process.env.PERCH_MODEL_PAYLOAD_DUMP_DIR;
|
|
217110
217376
|
if (process.env.PERCH_DUMP_MODEL_PAYLOAD !== "1" && !dumpDir) return;
|
|
217111
217377
|
try {
|
|
217112
|
-
const [{ mkdir, writeFile:
|
|
217378
|
+
const [{ mkdir: mkdir2, writeFile: writeFile3 }, { join: join2 }] = await Promise.all([
|
|
217113
217379
|
import("node:fs/promises"),
|
|
217114
217380
|
import("node:path")
|
|
217115
217381
|
]);
|
|
217116
|
-
const dir = dumpDir ||
|
|
217117
|
-
await
|
|
217118
|
-
const
|
|
217119
|
-
await
|
|
217120
|
-
|
|
217382
|
+
const dir = dumpDir || join2(process.cwd(), ".perch", "debug", "model-payloads");
|
|
217383
|
+
await mkdir2(dir, { recursive: true });
|
|
217384
|
+
const safeRunId2 = (input.runId || "local").replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 80);
|
|
217385
|
+
await writeFile3(
|
|
217386
|
+
join2(dir, `${safeRunId2}-iter-${input.iteration}.json`),
|
|
217121
217387
|
JSON.stringify({
|
|
217122
217388
|
dumpedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
217123
217389
|
runId: input.runId,
|
|
@@ -217605,13 +217871,18 @@ async function runLiveAgentsLoop(input) {
|
|
|
217605
217871
|
effectiveContextLimitTokens: state.effectiveContextLimitTokens,
|
|
217606
217872
|
compactedAtIso: state.compactedAtIso,
|
|
217607
217873
|
autoCompactedAtIso: state.compactedAtIso,
|
|
217874
|
+
autoCompactedMessageCount: state.compactionReport.summarizedMessages,
|
|
217875
|
+
compactBoundary: state.compactBoundary,
|
|
217876
|
+
compactionReport: state.compactionReport,
|
|
217608
217877
|
consecutiveAutoCompactFailures: 0
|
|
217609
217878
|
},
|
|
217610
217879
|
contextMetrics: latest?.contextMetrics ? {
|
|
217611
217880
|
...latest.contextMetrics,
|
|
217612
217881
|
effectiveLimitTokens: state.effectiveContextLimitTokens,
|
|
217613
217882
|
autoCompactEnabled: state.autoCompactEnabled,
|
|
217614
|
-
autoCompactedAtIso: state.compactedAtIso
|
|
217883
|
+
autoCompactedAtIso: state.compactedAtIso,
|
|
217884
|
+
autoCompactedMessageCount: state.compactionReport.summarizedMessages,
|
|
217885
|
+
compactionReport: state.compactionReport
|
|
217615
217886
|
} : latest?.contextMetrics,
|
|
217616
217887
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
217617
217888
|
},
|
|
@@ -219818,7 +220089,13 @@ function emitProgressForRuntimeEvent(event, emit, state = {
|
|
|
219818
220089
|
case "context_compacted":
|
|
219819
220090
|
emitInstantItem(emit, state, turnId, "context", itemId(turnId, "context-compacted", ts), "Context compacted", event.summary, ts, {
|
|
219820
220091
|
tokensBefore: event.tokensBefore,
|
|
219821
|
-
tokensAfter: event.tokensAfter
|
|
220092
|
+
tokensAfter: event.tokensAfter,
|
|
220093
|
+
targetTokens: event.targetTokens,
|
|
220094
|
+
summaryTokens: event.summaryTokens,
|
|
220095
|
+
recentTailTokens: event.recentTailTokens,
|
|
220096
|
+
recentTailMessages: event.recentTailMessages,
|
|
220097
|
+
summarizedMessages: event.summarizedMessages,
|
|
220098
|
+
restoredToolsOrFiles: event.restoredToolsOrFiles
|
|
219822
220099
|
});
|
|
219823
220100
|
break;
|
|
219824
220101
|
case "plan_card_generated": {
|
|
@@ -221003,6 +221280,7 @@ function resolveThreadContextAccounting(input) {
|
|
|
221003
221280
|
consecutiveAutoCompactFailures: priorCompaction?.consecutiveAutoCompactFailures ?? priorMetrics?.consecutiveAutoCompactFailures ?? 0,
|
|
221004
221281
|
autoCompactedAtIso: priorCompaction?.autoCompactedAtIso ?? priorMetrics?.autoCompactedAtIso ?? null,
|
|
221005
221282
|
autoCompactedMessageCount: priorCompaction?.autoCompactedMessageCount ?? priorMetrics?.autoCompactedMessageCount,
|
|
221283
|
+
compactionReport: priorCompaction?.compactionReport ?? priorMetrics?.compactionReport,
|
|
221006
221284
|
tokenCountMethod: fill.tokenCountMethod,
|
|
221007
221285
|
accountingMethod: "thread_fill_v4: headline = retained window fill high-water until compaction; provider usage is last-call detail; workers off-thread only.",
|
|
221008
221286
|
resetAtIso: compactedAtIso,
|
|
@@ -221126,6 +221404,7 @@ function buildClientContextSnapshot(input) {
|
|
|
221126
221404
|
consecutiveAutoCompactFailures: accounting.consecutiveAutoCompactFailures ?? 0,
|
|
221127
221405
|
autoCompactedAtIso: accounting.autoCompactedAtIso ?? null,
|
|
221128
221406
|
autoCompactedMessageCount: accounting.autoCompactedMessageCount,
|
|
221407
|
+
compactionReport: accounting.compactionReport,
|
|
221129
221408
|
builtAtIso: input.builtAtIso,
|
|
221130
221409
|
createdAt: input.builtAtIso,
|
|
221131
221410
|
...wireDisplay ? {
|
|
@@ -222671,8 +222950,849 @@ var init_runOperatorTurn = __esm({
|
|
|
222671
222950
|
}
|
|
222672
222951
|
});
|
|
222673
222952
|
|
|
222674
|
-
//
|
|
222953
|
+
// electron/localSandboxHost.ts
|
|
222954
|
+
import { copyFile, mkdir, mkdtemp, readdir, readFile as readFile3, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
222955
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
222956
|
+
import { basename, dirname, extname, join, relative, resolve as resolve4 } from "node:path";
|
|
222957
|
+
import { homedir, platform, tmpdir } from "node:os";
|
|
222675
222958
|
import { spawn } from "node:child_process";
|
|
222959
|
+
function buildSandboxRuntimeInfo(networkPolicy) {
|
|
222960
|
+
return {
|
|
222961
|
+
networkPolicy,
|
|
222962
|
+
packageInstalls: networkPolicy === "disabled" ? "disabled" : "enabled",
|
|
222963
|
+
pythonCommand: "python3",
|
|
222964
|
+
pipCommand: "python3 -m pip",
|
|
222965
|
+
inputManifestPath: "input_manifest.json",
|
|
222966
|
+
helperModule: "perch_helpers",
|
|
222967
|
+
helperFunctions: [
|
|
222968
|
+
"input_files",
|
|
222969
|
+
"load_tabular",
|
|
222970
|
+
"extract_pdf_text",
|
|
222971
|
+
"extract_invoice_fields",
|
|
222972
|
+
"extract_pdf_tables",
|
|
222973
|
+
"find_duplicates",
|
|
222974
|
+
"write_report",
|
|
222975
|
+
"sandbox_runtime_info"
|
|
222976
|
+
],
|
|
222977
|
+
notes: [
|
|
222978
|
+
"Read copied sources from paths listed in input_manifest.json.",
|
|
222979
|
+
networkPolicy === "disabled" ? "Package installs and network egress are disabled for this run." : "Package installs are allowed for this run; use python3 -m pip install <package> when needed.",
|
|
222980
|
+
"perch_helpers.extract_pdf_text has a stdlib raw-stream fallback for simple invoice PDFs, so PDF parsing should not require pdfplumber/pypdf for text fields."
|
|
222981
|
+
]
|
|
222982
|
+
};
|
|
222983
|
+
}
|
|
222984
|
+
async function writeSandboxManifestFiles(input) {
|
|
222985
|
+
const payload = {
|
|
222986
|
+
...input.inputManifest,
|
|
222987
|
+
runtime: input.runtimeInfo
|
|
222988
|
+
};
|
|
222989
|
+
const text = JSON.stringify(payload, null, 2);
|
|
222990
|
+
await writeFile2(join(input.workspaceRoot, "input_manifest.json"), text, "utf-8");
|
|
222991
|
+
await writeFile2(join(input.workspaceRoot, "sandbox_runtime.json"), JSON.stringify(input.runtimeInfo, null, 2), "utf-8");
|
|
222992
|
+
}
|
|
222993
|
+
async function runDesktopSandboxCodeJob(spec, deps) {
|
|
222994
|
+
const runId = safeRunId(spec.runId) ?? makeRunId2("sandbox-code");
|
|
222995
|
+
const startedAt = Date.now();
|
|
222996
|
+
const now13 = () => (deps.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
222997
|
+
const emitLive = (type, payload) => {
|
|
222998
|
+
deps.onEvent?.({ runId, type, payload, ts: now13() });
|
|
222999
|
+
};
|
|
223000
|
+
const commandText = typeof spec.command === "string" ? spec.command.trim() : "";
|
|
223001
|
+
const code = typeof spec.code === "string" ? spec.code : "";
|
|
223002
|
+
const language = spec.language === "node" ? "node" : "python";
|
|
223003
|
+
const executionMode = commandText ? "command" : "script";
|
|
223004
|
+
const executableText = executionMode === "command" ? commandText : code;
|
|
223005
|
+
const codeSha256 = createHash2("sha256").update(executableText).digest("hex");
|
|
223006
|
+
const networkPolicy = spec.networkPolicy ?? "disabled";
|
|
223007
|
+
if (!executableText.trim()) {
|
|
223008
|
+
return { ok: false, kind: "blocked", message: "run_sandbox_code requires either command or code.", executionHost: "electron-main", runId, codeSha256 };
|
|
223009
|
+
}
|
|
223010
|
+
emitLive("sandbox_started", {
|
|
223011
|
+
executionHost: "electron-main",
|
|
223012
|
+
runnerKind: "dev-local",
|
|
223013
|
+
networkPolicy,
|
|
223014
|
+
label: spec.label ?? null,
|
|
223015
|
+
codeSha256,
|
|
223016
|
+
language: executionMode === "command" ? "shell" : language
|
|
223017
|
+
});
|
|
223018
|
+
const validationReasons = executionMode === "script" ? validateScript(code, language) : [];
|
|
223019
|
+
if (validationReasons.length > 0) {
|
|
223020
|
+
emitLive("sandbox_failed", {
|
|
223021
|
+
stopReason: "validation_rejected",
|
|
223022
|
+
message: "The model-written sandbox code was rejected by validation.",
|
|
223023
|
+
validationReasons,
|
|
223024
|
+
codeSha256
|
|
223025
|
+
});
|
|
223026
|
+
return {
|
|
223027
|
+
ok: false,
|
|
223028
|
+
kind: "failed",
|
|
223029
|
+
message: "The model-written sandbox code was rejected by validation.",
|
|
223030
|
+
runnerKind: "dev-local",
|
|
223031
|
+
executionHost: "electron-main",
|
|
223032
|
+
runId,
|
|
223033
|
+
error: validationReasons.join("; "),
|
|
223034
|
+
validationReasons,
|
|
223035
|
+
codeSha256
|
|
223036
|
+
};
|
|
223037
|
+
}
|
|
223038
|
+
let resolved = [];
|
|
223039
|
+
if (Array.isArray(spec.sources) && spec.sources.length > 0) {
|
|
223040
|
+
try {
|
|
223041
|
+
emitLive("inputs_preparing", { sourceCount: spec.sources.length });
|
|
223042
|
+
resolved = await resolveApprovedInputs(spec.sources, deps);
|
|
223043
|
+
} catch (err) {
|
|
223044
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
223045
|
+
emitLive("sandbox_failed", { message, stopReason: "input_resolution_failed" });
|
|
223046
|
+
return { ok: false, kind: "blocked", message, executionHost: "electron-main", runId, error: message, codeSha256 };
|
|
223047
|
+
}
|
|
223048
|
+
}
|
|
223049
|
+
const workspaceKey = safeWorkspaceKey(spec.workspaceKey) ?? runId;
|
|
223050
|
+
const workspaceRoot = await ensureCodeWorkspace(workspaceKey);
|
|
223051
|
+
const scriptName = language === "python" ? `run-${runId}.py` : `run-${runId}.js`;
|
|
223052
|
+
const command = executionMode === "command" ? commandText : language === "python" ? buildPythonCommand(scriptName) : `"$PERCH_ELECTRON_EXEC" "${scriptName}"`;
|
|
223053
|
+
emitLive("script_planned", {
|
|
223054
|
+
source: "model",
|
|
223055
|
+
fallbackReason: null,
|
|
223056
|
+
script: redactUserVisibleText(executableText),
|
|
223057
|
+
publicPlan: spec.label ?? (executionMode === "command" ? "Sandbox shell command." : "Model-written sandbox code."),
|
|
223058
|
+
plannerContent: null,
|
|
223059
|
+
provider: null,
|
|
223060
|
+
codeSha256,
|
|
223061
|
+
language: executionMode === "command" ? "shell" : language
|
|
223062
|
+
});
|
|
223063
|
+
emitLive("command_started", { command: redactUserVisibleText(command), language: executionMode === "command" ? "shell" : language, codeSha256 });
|
|
223064
|
+
const runResult = await runCodeSandbox({
|
|
223065
|
+
runId,
|
|
223066
|
+
command,
|
|
223067
|
+
workspaceRoot,
|
|
223068
|
+
inputs: resolved,
|
|
223069
|
+
timeoutMs: Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS2, DEFAULT_TIMEOUT_MS2),
|
|
223070
|
+
onEvent: emitLive,
|
|
223071
|
+
networkPolicy,
|
|
223072
|
+
scriptFile: executionMode === "script" ? { name: scriptName, content: code } : null
|
|
223073
|
+
});
|
|
223074
|
+
const outputBundle = buildOutputBundle(runResult);
|
|
223075
|
+
const hasReport = runResult.structuredOutput?.reportJson != null;
|
|
223076
|
+
const completedWithoutReport = runResult.status === "completed" && !hasReport;
|
|
223077
|
+
const eventKind = runResult.status === "completed" ? "completed" : "failed";
|
|
223078
|
+
const stopReason = hasReport ? "completed" : completedWithoutReport ? "completed_unstructured" : runResult.status === "timed_out" ? "run_timed_out" : "run_failed";
|
|
223079
|
+
emitLive(eventKind === "completed" ? "sandbox_completed" : "sandbox_failed", {
|
|
223080
|
+
stopReason,
|
|
223081
|
+
runnerKind: "dev-local",
|
|
223082
|
+
executionHost: "electron-main",
|
|
223083
|
+
codeSha256,
|
|
223084
|
+
outputSummary: {
|
|
223085
|
+
files: outputBundle?.files.length ?? 0,
|
|
223086
|
+
tables: outputBundle?.tables.length ?? 0,
|
|
223087
|
+
charts: outputBundle?.charts.length ?? 0,
|
|
223088
|
+
logs: outputBundle?.logs.length ?? 0,
|
|
223089
|
+
reportJsonPresent: hasReport
|
|
223090
|
+
}
|
|
223091
|
+
});
|
|
223092
|
+
if (runResult.status !== "completed") {
|
|
223093
|
+
return {
|
|
223094
|
+
ok: false,
|
|
223095
|
+
kind: "failed",
|
|
223096
|
+
message: "Model-written sandbox code failed.",
|
|
223097
|
+
runnerKind: "dev-local",
|
|
223098
|
+
executionHost: "electron-main",
|
|
223099
|
+
runId,
|
|
223100
|
+
error: runResult.stderr || stopReason,
|
|
223101
|
+
codeSha256,
|
|
223102
|
+
status: runResult.status,
|
|
223103
|
+
exitCode: runResult.exitCode,
|
|
223104
|
+
durationMs: Date.now() - startedAt,
|
|
223105
|
+
stdout: runResult.stdout,
|
|
223106
|
+
stderr: runResult.stderr,
|
|
223107
|
+
stdoutTruncated: runResult.stdoutTruncated,
|
|
223108
|
+
stderrTruncated: runResult.stderrTruncated,
|
|
223109
|
+
producedFiles: runResult.producedFiles,
|
|
223110
|
+
inputManifest: runResult.inputManifest,
|
|
223111
|
+
runtimeInfo: runResult.runtimeInfo,
|
|
223112
|
+
structuredOutput: runResult.structuredOutput,
|
|
223113
|
+
workspacePath: runResult.workspacePath,
|
|
223114
|
+
language,
|
|
223115
|
+
reportJsonPresent: hasReport,
|
|
223116
|
+
warnings: runResult.warnings
|
|
223117
|
+
};
|
|
223118
|
+
}
|
|
223119
|
+
const kind = "completed";
|
|
223120
|
+
return {
|
|
223121
|
+
ok: true,
|
|
223122
|
+
kind,
|
|
223123
|
+
message: hasReport ? "Sandbox execution completed and emitted output/report.json." : "Sandbox execution completed; stdout/stderr and produced files were captured.",
|
|
223124
|
+
runnerKind: "dev-local",
|
|
223125
|
+
executionHost: "electron-main",
|
|
223126
|
+
runId,
|
|
223127
|
+
status: runResult.status,
|
|
223128
|
+
exitCode: runResult.exitCode,
|
|
223129
|
+
durationMs: Date.now() - startedAt,
|
|
223130
|
+
stdout: runResult.stdout,
|
|
223131
|
+
stderr: runResult.stderr,
|
|
223132
|
+
stdoutTruncated: runResult.stdoutTruncated,
|
|
223133
|
+
stderrTruncated: runResult.stderrTruncated,
|
|
223134
|
+
producedFiles: runResult.producedFiles,
|
|
223135
|
+
inputManifest: runResult.inputManifest,
|
|
223136
|
+
runtimeInfo: runResult.runtimeInfo,
|
|
223137
|
+
structuredOutput: runResult.structuredOutput,
|
|
223138
|
+
workspacePath: runResult.workspacePath,
|
|
223139
|
+
codeSha256,
|
|
223140
|
+
language: executionMode === "command" ? "shell" : language,
|
|
223141
|
+
reportJsonPresent: hasReport,
|
|
223142
|
+
warnings: runResult.warnings
|
|
223143
|
+
};
|
|
223144
|
+
}
|
|
223145
|
+
async function resolveApprovedInputs(sources, deps) {
|
|
223146
|
+
const out = [];
|
|
223147
|
+
const seen = /* @__PURE__ */ new Set();
|
|
223148
|
+
for (const source of sources.slice(0, MAX_SOURCES)) {
|
|
223149
|
+
if (!source.localSourceId || seen.has(source.localSourceId)) continue;
|
|
223150
|
+
seen.add(source.localSourceId);
|
|
223151
|
+
const resolved = resolveSandboxInputRef(source.localSourceId, deps);
|
|
223152
|
+
if (!resolved) continue;
|
|
223153
|
+
const { absPath, relPath } = resolved;
|
|
223154
|
+
const fileName = basename(absPath);
|
|
223155
|
+
if (deps.shouldIgnore(fileName)) continue;
|
|
223156
|
+
const s = await stat(absPath);
|
|
223157
|
+
if (!s.isFile()) continue;
|
|
223158
|
+
if (s.size > MAX_SOURCE_BYTES) continue;
|
|
223159
|
+
out.push({
|
|
223160
|
+
localSourceId: source.localSourceId,
|
|
223161
|
+
fileName: safeRelativeName(source.fileName || fileName),
|
|
223162
|
+
fileType: source.fileType || guessFileTypeFromExt(extname(fileName).toLowerCase()),
|
|
223163
|
+
sizeBytes: s.size,
|
|
223164
|
+
description: source.description,
|
|
223165
|
+
relativePath: safeRelativeName(relPath),
|
|
223166
|
+
sourcePath: absPath
|
|
223167
|
+
});
|
|
223168
|
+
}
|
|
223169
|
+
return out;
|
|
223170
|
+
}
|
|
223171
|
+
function resolveSandboxInputRef(inputRef, deps) {
|
|
223172
|
+
const sep = inputRef.indexOf("::");
|
|
223173
|
+
if (sep >= 0) {
|
|
223174
|
+
const rootId = inputRef.slice(0, sep);
|
|
223175
|
+
const relPath2 = inputRef.slice(sep + 2);
|
|
223176
|
+
const root3 = deps.getApprovedRoot(rootId);
|
|
223177
|
+
if (!root3) return null;
|
|
223178
|
+
if (!deps.isPathSafe(root3.path, relPath2)) return null;
|
|
223179
|
+
const absPath2 = resolve4(root3.path, relPath2);
|
|
223180
|
+
if (!deps.isInsideApprovedRoot(absPath2)) return null;
|
|
223181
|
+
return { absPath: absPath2, relPath: relPath2 };
|
|
223182
|
+
}
|
|
223183
|
+
const absPath = resolve4(inputRef);
|
|
223184
|
+
const root2 = deps.isInsideApprovedRoot(absPath);
|
|
223185
|
+
if (!root2) return null;
|
|
223186
|
+
const relPath = relative(root2.path, absPath);
|
|
223187
|
+
if (!deps.isPathSafe(root2.path, relPath)) return null;
|
|
223188
|
+
return { absPath, relPath };
|
|
223189
|
+
}
|
|
223190
|
+
function validateScript(script, language = "node") {
|
|
223191
|
+
if (language === "python") return validatePythonScript(script);
|
|
223192
|
+
const reasons = [];
|
|
223193
|
+
const blocked3 = [
|
|
223194
|
+
"child_process",
|
|
223195
|
+
"exec(",
|
|
223196
|
+
"spawn(",
|
|
223197
|
+
"process.env",
|
|
223198
|
+
"require('http')",
|
|
223199
|
+
'require("http")',
|
|
223200
|
+
"require('https')",
|
|
223201
|
+
'require("https")',
|
|
223202
|
+
"fetch(",
|
|
223203
|
+
"eval(",
|
|
223204
|
+
"Function("
|
|
223205
|
+
];
|
|
223206
|
+
for (const token of blocked3) {
|
|
223207
|
+
if (script.includes(token)) reasons.push(`blocked token: ${token}`);
|
|
223208
|
+
}
|
|
223209
|
+
return reasons;
|
|
223210
|
+
}
|
|
223211
|
+
function validatePythonScript(script) {
|
|
223212
|
+
const reasons = [];
|
|
223213
|
+
const blocked3 = [
|
|
223214
|
+
"subprocess",
|
|
223215
|
+
"os.system(",
|
|
223216
|
+
"os.popen(",
|
|
223217
|
+
"os.exec",
|
|
223218
|
+
"shutil.rmtree",
|
|
223219
|
+
"__import__(",
|
|
223220
|
+
"importlib",
|
|
223221
|
+
"ctypes",
|
|
223222
|
+
"requests.get",
|
|
223223
|
+
"requests.post",
|
|
223224
|
+
"urllib.request",
|
|
223225
|
+
"http.client",
|
|
223226
|
+
"socket.",
|
|
223227
|
+
"open('/etc",
|
|
223228
|
+
"open('/proc",
|
|
223229
|
+
"open('/sys"
|
|
223230
|
+
];
|
|
223231
|
+
for (const token of blocked3) {
|
|
223232
|
+
if (script.includes(token)) reasons.push(`blocked token: ${token}`);
|
|
223233
|
+
}
|
|
223234
|
+
return reasons;
|
|
223235
|
+
}
|
|
223236
|
+
function buildPythonCommand(scriptPath) {
|
|
223237
|
+
return `python3 "${scriptPath}"`;
|
|
223238
|
+
}
|
|
223239
|
+
async function ensureCodeWorkspace(workspaceKey) {
|
|
223240
|
+
const existing = codeWorkspaces.get(workspaceKey);
|
|
223241
|
+
if (existing) {
|
|
223242
|
+
try {
|
|
223243
|
+
const s = await stat(existing);
|
|
223244
|
+
if (s.isDirectory()) return existing;
|
|
223245
|
+
} catch {
|
|
223246
|
+
codeWorkspaces.delete(workspaceKey);
|
|
223247
|
+
}
|
|
223248
|
+
}
|
|
223249
|
+
const workspaceRoot = await mkdtemp(join(tmpdir(), `perch-code-${workspaceKey.slice(0, 16)}-`));
|
|
223250
|
+
await mkdir(join(workspaceRoot, "input"), { recursive: true });
|
|
223251
|
+
await mkdir(join(workspaceRoot, "output"), { recursive: true });
|
|
223252
|
+
await writeFile2(join(workspaceRoot, "perch_helpers.py"), PYTHON_HELPERS_SOURCE, "utf-8");
|
|
223253
|
+
codeWorkspaces.set(workspaceKey, workspaceRoot);
|
|
223254
|
+
return workspaceRoot;
|
|
223255
|
+
}
|
|
223256
|
+
async function runCodeSandbox(opts) {
|
|
223257
|
+
const warnings = [];
|
|
223258
|
+
const copiedInputFiles = [];
|
|
223259
|
+
const skippedInputFiles = [];
|
|
223260
|
+
const inputManifestFiles = [];
|
|
223261
|
+
const skippedManifestEntries = [];
|
|
223262
|
+
const runtimeInfo = buildSandboxRuntimeInfo(opts.networkPolicy);
|
|
223263
|
+
const inputDir = join(opts.workspaceRoot, "input");
|
|
223264
|
+
const outputDir = join(opts.workspaceRoot, "output");
|
|
223265
|
+
await rm(inputDir, { recursive: true, force: true });
|
|
223266
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
223267
|
+
await mkdir(inputDir, { recursive: true });
|
|
223268
|
+
await mkdir(outputDir, { recursive: true });
|
|
223269
|
+
if (opts.scriptFile) {
|
|
223270
|
+
await writeFile2(join(opts.workspaceRoot, opts.scriptFile.name), opts.scriptFile.content, "utf-8");
|
|
223271
|
+
}
|
|
223272
|
+
await writeFile2(join(opts.workspaceRoot, "perch_helpers.py"), PYTHON_HELPERS_SOURCE, "utf-8");
|
|
223273
|
+
for (const input of opts.inputs) {
|
|
223274
|
+
const safeRel = safeRelativeName(input.relativePath || input.fileName);
|
|
223275
|
+
if (!safeRel) {
|
|
223276
|
+
skippedInputFiles.push(input.fileName);
|
|
223277
|
+
skippedManifestEntries.push({
|
|
223278
|
+
sourcePath: input.sourcePath,
|
|
223279
|
+
localSourceId: input.localSourceId,
|
|
223280
|
+
fileName: input.fileName,
|
|
223281
|
+
sizeBytes: input.sizeBytes,
|
|
223282
|
+
fileType: input.fileType,
|
|
223283
|
+
reason: "invalid_sandbox_relative_path"
|
|
223284
|
+
});
|
|
223285
|
+
continue;
|
|
223286
|
+
}
|
|
223287
|
+
try {
|
|
223288
|
+
const dest = join(inputDir, safeRel);
|
|
223289
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
223290
|
+
await copyFile(input.sourcePath, dest);
|
|
223291
|
+
copiedInputFiles.push(safeRel);
|
|
223292
|
+
inputManifestFiles.push({
|
|
223293
|
+
sandboxPath: `input/${safeRel}`,
|
|
223294
|
+
sourcePath: input.sourcePath,
|
|
223295
|
+
localSourceId: input.localSourceId,
|
|
223296
|
+
fileName: input.fileName || basename(safeRel),
|
|
223297
|
+
sizeBytes: input.sizeBytes,
|
|
223298
|
+
fileType: input.fileType || null
|
|
223299
|
+
});
|
|
223300
|
+
opts.onEvent?.("input_copied", {
|
|
223301
|
+
relativePath: safeRel,
|
|
223302
|
+
fileName: input.fileName,
|
|
223303
|
+
fileType: input.fileType,
|
|
223304
|
+
sizeBytes: input.sizeBytes
|
|
223305
|
+
});
|
|
223306
|
+
} catch (err) {
|
|
223307
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
223308
|
+
skippedInputFiles.push(safeRel);
|
|
223309
|
+
skippedManifestEntries.push({
|
|
223310
|
+
sandboxPath: `input/${safeRel}`,
|
|
223311
|
+
sourcePath: input.sourcePath,
|
|
223312
|
+
localSourceId: input.localSourceId,
|
|
223313
|
+
fileName: input.fileName || basename(safeRel),
|
|
223314
|
+
sizeBytes: input.sizeBytes,
|
|
223315
|
+
fileType: input.fileType,
|
|
223316
|
+
reason: msg
|
|
223317
|
+
});
|
|
223318
|
+
warnings.push(`Failed to copy input ${safeRel}: ${msg}`);
|
|
223319
|
+
}
|
|
223320
|
+
}
|
|
223321
|
+
opts.onEvent?.("inputs_ready", {
|
|
223322
|
+
requestedInputFileCount: opts.inputs.length,
|
|
223323
|
+
copiedInputFiles,
|
|
223324
|
+
skippedInputFiles,
|
|
223325
|
+
workspacePath: redactUserVisibleText(opts.workspaceRoot),
|
|
223326
|
+
inputManifestPath: "input_manifest.json",
|
|
223327
|
+
runtimeInfo
|
|
223328
|
+
});
|
|
223329
|
+
const inputManifest = {
|
|
223330
|
+
root: "input",
|
|
223331
|
+
files: inputManifestFiles,
|
|
223332
|
+
skipped: skippedManifestEntries
|
|
223333
|
+
};
|
|
223334
|
+
await writeSandboxManifestFiles({
|
|
223335
|
+
workspaceRoot: opts.workspaceRoot,
|
|
223336
|
+
inputManifest,
|
|
223337
|
+
runtimeInfo
|
|
223338
|
+
});
|
|
223339
|
+
const execResult = await executeCommand(
|
|
223340
|
+
opts.command,
|
|
223341
|
+
opts.workspaceRoot,
|
|
223342
|
+
opts.timeoutMs,
|
|
223343
|
+
opts.networkPolicy,
|
|
223344
|
+
opts.onEvent
|
|
223345
|
+
);
|
|
223346
|
+
const producedFiles = await collectOutputFiles(outputDir, warnings, opts.onEvent);
|
|
223347
|
+
opts.onEvent?.("outputs_collected", { producedFiles });
|
|
223348
|
+
const structuredOutput = await readStructuredOutput(outputDir, execResult.stdout);
|
|
223349
|
+
if (structuredOutput?.reportJson) opts.onEvent?.("report_detected", { source: "report.json" });
|
|
223350
|
+
return {
|
|
223351
|
+
runId: opts.runId,
|
|
223352
|
+
status: execResult.timedOut ? "timed_out" : execResult.exitCode === 0 ? "completed" : "failed",
|
|
223353
|
+
exitCode: execResult.exitCode,
|
|
223354
|
+
stdout: execResult.stdout,
|
|
223355
|
+
stderr: execResult.stderr,
|
|
223356
|
+
stdoutTruncated: execResult.stdoutTruncated,
|
|
223357
|
+
stderrTruncated: execResult.stderrTruncated,
|
|
223358
|
+
producedFiles,
|
|
223359
|
+
inputManifest,
|
|
223360
|
+
runtimeInfo,
|
|
223361
|
+
structuredOutput,
|
|
223362
|
+
warnings,
|
|
223363
|
+
durationMs: 0,
|
|
223364
|
+
workspacePath: opts.workspaceRoot,
|
|
223365
|
+
cleanedUp: false,
|
|
223366
|
+
executionEvidence: {
|
|
223367
|
+
requestedInputFileCount: opts.inputs.length,
|
|
223368
|
+
copiedInputFiles,
|
|
223369
|
+
skippedInputFiles,
|
|
223370
|
+
command: opts.command
|
|
223371
|
+
}
|
|
223372
|
+
};
|
|
223373
|
+
}
|
|
223374
|
+
async function executeCommand(command, cwd2, timeoutMs, networkPolicy, onEvent) {
|
|
223375
|
+
const launch = await prepareSandboxLaunch(command, cwd2, networkPolicy);
|
|
223376
|
+
if ("error" in launch) {
|
|
223377
|
+
return {
|
|
223378
|
+
stdout: "",
|
|
223379
|
+
stderr: launch.error,
|
|
223380
|
+
exitCode: 126,
|
|
223381
|
+
timedOut: false,
|
|
223382
|
+
stdoutTruncated: false,
|
|
223383
|
+
stderrTruncated: false
|
|
223384
|
+
};
|
|
223385
|
+
}
|
|
223386
|
+
return new Promise((resolvePromise) => {
|
|
223387
|
+
let stdout = "";
|
|
223388
|
+
let stderr = "";
|
|
223389
|
+
let stdoutBytes = 0;
|
|
223390
|
+
let stderrBytes = 0;
|
|
223391
|
+
let stdoutTruncated = false;
|
|
223392
|
+
let stderrTruncated = false;
|
|
223393
|
+
let timedOut = false;
|
|
223394
|
+
const childEnv = {
|
|
223395
|
+
NODE_ENV: "sandbox",
|
|
223396
|
+
PERCH_SANDBOX_NETWORK: networkPolicy,
|
|
223397
|
+
LANG: "en_US.UTF-8",
|
|
223398
|
+
HOME: cwd2,
|
|
223399
|
+
TMPDIR: join(cwd2, "tmp"),
|
|
223400
|
+
PYTHONDONTWRITEBYTECODE: "1",
|
|
223401
|
+
PATH: process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin",
|
|
223402
|
+
ELECTRON_RUN_AS_NODE: "1",
|
|
223403
|
+
PERCH_ELECTRON_EXEC: process.execPath,
|
|
223404
|
+
...launch.env
|
|
223405
|
+
};
|
|
223406
|
+
const child = spawn(launch.command, launch.args, {
|
|
223407
|
+
cwd: cwd2,
|
|
223408
|
+
env: childEnv,
|
|
223409
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
223410
|
+
});
|
|
223411
|
+
const timer = setTimeout(() => {
|
|
223412
|
+
timedOut = true;
|
|
223413
|
+
child.kill("SIGKILL");
|
|
223414
|
+
}, timeoutMs);
|
|
223415
|
+
child.stdout?.on("data", (data) => {
|
|
223416
|
+
stdoutBytes += data.length;
|
|
223417
|
+
const chunk2 = data.toString("utf8");
|
|
223418
|
+
onEvent?.("stdout", { chunk: redactUserVisibleText(chunk2) });
|
|
223419
|
+
if (stdoutBytes <= MAX_STDOUT_BYTES) stdout += chunk2;
|
|
223420
|
+
else stdoutTruncated = true;
|
|
223421
|
+
});
|
|
223422
|
+
child.stderr?.on("data", (data) => {
|
|
223423
|
+
stderrBytes += data.length;
|
|
223424
|
+
const chunk2 = data.toString("utf8");
|
|
223425
|
+
onEvent?.("stderr", { chunk: redactUserVisibleText(chunk2) });
|
|
223426
|
+
if (stderrBytes <= MAX_STDERR_BYTES) stderr += chunk2;
|
|
223427
|
+
else stderrTruncated = true;
|
|
223428
|
+
});
|
|
223429
|
+
child.on("close", (code) => {
|
|
223430
|
+
clearTimeout(timer);
|
|
223431
|
+
resolvePromise({ stdout, stderr, exitCode: code, timedOut, stdoutTruncated, stderrTruncated });
|
|
223432
|
+
});
|
|
223433
|
+
child.on("error", (err) => {
|
|
223434
|
+
clearTimeout(timer);
|
|
223435
|
+
resolvePromise({ stdout, stderr: err.message, exitCode: 1, timedOut: false, stdoutTruncated, stderrTruncated });
|
|
223436
|
+
});
|
|
223437
|
+
});
|
|
223438
|
+
}
|
|
223439
|
+
async function prepareSandboxLaunch(command, cwd2, networkPolicy) {
|
|
223440
|
+
await mkdir(join(cwd2, "tmp"), { recursive: true });
|
|
223441
|
+
if (networkPolicy !== "disabled") {
|
|
223442
|
+
return { command: "bash", args: ["-c", command] };
|
|
223443
|
+
}
|
|
223444
|
+
if (platform() !== "darwin") {
|
|
223445
|
+
return {
|
|
223446
|
+
error: "Sandbox execution requires macOS sandbox-exec for disabled-network local code runs in this build."
|
|
223447
|
+
};
|
|
223448
|
+
}
|
|
223449
|
+
const sandboxExec = "/usr/bin/sandbox-exec";
|
|
223450
|
+
try {
|
|
223451
|
+
const s = await stat(sandboxExec);
|
|
223452
|
+
if (!s.isFile()) throw new Error("not a file");
|
|
223453
|
+
} catch {
|
|
223454
|
+
return {
|
|
223455
|
+
error: "macOS sandbox-exec is unavailable; refusing to run model-written code without OS-level isolation."
|
|
223456
|
+
};
|
|
223457
|
+
}
|
|
223458
|
+
const profilePath = join(cwd2, ".perch-sandbox.sb");
|
|
223459
|
+
await writeFile2(profilePath, buildSeatbeltProfile(cwd2), "utf-8");
|
|
223460
|
+
return {
|
|
223461
|
+
command: sandboxExec,
|
|
223462
|
+
args: ["-f", profilePath, "/bin/bash", "-c", command],
|
|
223463
|
+
env: { PERCH_SANDBOX_PROFILE: profilePath }
|
|
223464
|
+
};
|
|
223465
|
+
}
|
|
223466
|
+
function buildSeatbeltProfile(workspaceRoot) {
|
|
223467
|
+
const home = homedir();
|
|
223468
|
+
const deniedUserDataRoots = Array.from(/* @__PURE__ */ new Set([
|
|
223469
|
+
home,
|
|
223470
|
+
"/Users/Shared",
|
|
223471
|
+
"/Volumes"
|
|
223472
|
+
])).map((path14) => `(subpath ${seatbeltString(path14)})`).join("\n ");
|
|
223473
|
+
return `
|
|
223474
|
+
(version 1)
|
|
223475
|
+
(allow default)
|
|
223476
|
+
(deny network*)
|
|
223477
|
+
(deny file-read*
|
|
223478
|
+
${deniedUserDataRoots})
|
|
223479
|
+
(deny file-write*
|
|
223480
|
+
${deniedUserDataRoots})
|
|
223481
|
+
(allow file-read*
|
|
223482
|
+
(subpath ${seatbeltString(workspaceRoot)})
|
|
223483
|
+
(subpath ${seatbeltString(dirname(process.execPath))}))
|
|
223484
|
+
(allow file-write*
|
|
223485
|
+
(subpath ${seatbeltString(workspaceRoot)}))
|
|
223486
|
+
`.trim();
|
|
223487
|
+
}
|
|
223488
|
+
function seatbeltString(value) {
|
|
223489
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
223490
|
+
}
|
|
223491
|
+
async function collectOutputFiles(outputDir, warnings, onEvent) {
|
|
223492
|
+
const files = [];
|
|
223493
|
+
let totalBytes = 0;
|
|
223494
|
+
async function walk2(dir, base) {
|
|
223495
|
+
let entries;
|
|
223496
|
+
try {
|
|
223497
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
223498
|
+
} catch {
|
|
223499
|
+
return;
|
|
223500
|
+
}
|
|
223501
|
+
for (const entry of entries) {
|
|
223502
|
+
if (files.length >= MAX_OUTPUT_FILES) return;
|
|
223503
|
+
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
223504
|
+
const full = join(dir, entry.name);
|
|
223505
|
+
if (entry.isDirectory()) {
|
|
223506
|
+
await walk2(full, rel);
|
|
223507
|
+
continue;
|
|
223508
|
+
}
|
|
223509
|
+
const s = await stat(full);
|
|
223510
|
+
totalBytes += s.size;
|
|
223511
|
+
if (totalBytes > MAX_OUTPUT_BYTES) {
|
|
223512
|
+
warnings.push("Produced file byte limit exceeded");
|
|
223513
|
+
return;
|
|
223514
|
+
}
|
|
223515
|
+
const file = { relativePath: rel, sizeBytes: s.size, mimeType: guessMimeTypeFromName(entry.name) };
|
|
223516
|
+
files.push(file);
|
|
223517
|
+
onEvent?.("output_detected", file);
|
|
223518
|
+
}
|
|
223519
|
+
}
|
|
223520
|
+
await walk2(outputDir, "");
|
|
223521
|
+
return files;
|
|
223522
|
+
}
|
|
223523
|
+
async function readStructuredOutput(outputDir, stdout) {
|
|
223524
|
+
let parsedStdout = null;
|
|
223525
|
+
const line = stdout.trim().split(/\r?\n/).reverse().find((candidate) => candidate.trim().startsWith("{"));
|
|
223526
|
+
if (line) {
|
|
223527
|
+
try {
|
|
223528
|
+
parsedStdout = JSON.parse(line);
|
|
223529
|
+
} catch {
|
|
223530
|
+
parsedStdout = null;
|
|
223531
|
+
}
|
|
223532
|
+
}
|
|
223533
|
+
let reportJson = parsedStdout?.reportJson;
|
|
223534
|
+
if (!reportJson) {
|
|
223535
|
+
try {
|
|
223536
|
+
reportJson = JSON.parse(await readFile3(join(outputDir, "report.json"), "utf8"));
|
|
223537
|
+
} catch {
|
|
223538
|
+
reportJson = void 0;
|
|
223539
|
+
}
|
|
223540
|
+
}
|
|
223541
|
+
const tables = Array.isArray(parsedStdout?.tables) ? parsedStdout.tables : [];
|
|
223542
|
+
const charts = Array.isArray(parsedStdout?.charts) ? parsedStdout.charts : [];
|
|
223543
|
+
const logs = Array.isArray(parsedStdout?.logs) ? parsedStdout.logs.filter((x) => typeof x === "string") : [];
|
|
223544
|
+
if (!reportJson && tables.length === 0 && charts.length === 0 && logs.length === 0) return null;
|
|
223545
|
+
return { reportJson, tables, charts, logs };
|
|
223546
|
+
}
|
|
223547
|
+
function buildOutputBundle(run) {
|
|
223548
|
+
const structured = run.structuredOutput;
|
|
223549
|
+
if (!structured && run.producedFiles.length === 0) return null;
|
|
223550
|
+
return {
|
|
223551
|
+
status: run.status,
|
|
223552
|
+
files: run.producedFiles.map((file) => ({
|
|
223553
|
+
fileName: safeRelativeName(file.relativePath),
|
|
223554
|
+
sizeBytes: file.sizeBytes,
|
|
223555
|
+
mimeType: file.mimeType
|
|
223556
|
+
})),
|
|
223557
|
+
tables: structured?.tables ?? [],
|
|
223558
|
+
charts: structured?.charts ?? [],
|
|
223559
|
+
logs: structured?.logs ?? [],
|
|
223560
|
+
reportJson: structured?.reportJson ?? null
|
|
223561
|
+
};
|
|
223562
|
+
}
|
|
223563
|
+
function makeRunId2(prefix) {
|
|
223564
|
+
try {
|
|
223565
|
+
return `${prefix}-${randomUUID().slice(0, 12)}`;
|
|
223566
|
+
} catch {
|
|
223567
|
+
return `${prefix}-${Date.now().toString(36)}`;
|
|
223568
|
+
}
|
|
223569
|
+
}
|
|
223570
|
+
function safeRunId(value) {
|
|
223571
|
+
if (!value) return null;
|
|
223572
|
+
return /^[a-zA-Z0-9_-]{1,80}$/.test(value) ? value : null;
|
|
223573
|
+
}
|
|
223574
|
+
function safeWorkspaceKey(value) {
|
|
223575
|
+
if (!value) return null;
|
|
223576
|
+
const cleaned = value.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80);
|
|
223577
|
+
return cleaned || null;
|
|
223578
|
+
}
|
|
223579
|
+
function safeRelativeName(value) {
|
|
223580
|
+
return value.split(/[\\/]+/).filter((part) => part && part !== "." && part !== "..").join("/") || "unnamed";
|
|
223581
|
+
}
|
|
223582
|
+
function redactUserVisibleText(text) {
|
|
223583
|
+
if (!text) return "";
|
|
223584
|
+
return text.replace(/\/Users\/[^/\s"'`]+/g, "[home]").replace(/\/home\/[^/\s"'`]+/g, "[home]").replace(/\/private\/var\/folders\/[^\s"'`]+/g, "[temp]").replace(/\/var\/folders\/[^\s"'`]+/g, "[temp]").replace(/\/tmp\/perch-sandbox-[^\s"'`]+/g, "[sandbox]").replace(/\/var\/tmp\/perch-sandbox-[^\s"'`]+/g, "[sandbox]");
|
|
223585
|
+
}
|
|
223586
|
+
function guessFileTypeFromExt(ext) {
|
|
223587
|
+
if ([".xlsx", ".xls"].includes(ext)) return "spreadsheet";
|
|
223588
|
+
if (ext === ".csv" || ext === ".tsv") return "csv";
|
|
223589
|
+
if (ext === ".pdf") return "pdf";
|
|
223590
|
+
if ([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"].includes(ext)) return "image";
|
|
223591
|
+
if ([".doc", ".docx", ".txt", ".md", ".rtf"].includes(ext)) return "document";
|
|
223592
|
+
return "unknown";
|
|
223593
|
+
}
|
|
223594
|
+
function guessMimeTypeFromName(fileName) {
|
|
223595
|
+
const ext = extname(fileName).toLowerCase();
|
|
223596
|
+
const map2 = {
|
|
223597
|
+
".json": "application/json",
|
|
223598
|
+
".csv": "text/csv",
|
|
223599
|
+
".tsv": "text/tab-separated-values",
|
|
223600
|
+
".txt": "text/plain",
|
|
223601
|
+
".md": "text/markdown",
|
|
223602
|
+
".html": "text/html"
|
|
223603
|
+
};
|
|
223604
|
+
return map2[ext] ?? "application/octet-stream";
|
|
223605
|
+
}
|
|
223606
|
+
var MAX_SOURCES, MAX_SOURCE_BYTES, MAX_STDOUT_BYTES, MAX_STDERR_BYTES, MAX_OUTPUT_FILES, MAX_OUTPUT_BYTES, DEFAULT_TIMEOUT_MS2, codeWorkspaces, PYTHON_HELPERS_SOURCE;
|
|
223607
|
+
var init_localSandboxHost = __esm({
|
|
223608
|
+
"electron/localSandboxHost.ts"() {
|
|
223609
|
+
MAX_SOURCES = 20;
|
|
223610
|
+
MAX_SOURCE_BYTES = 20 * 1024 * 1024;
|
|
223611
|
+
MAX_STDOUT_BYTES = 512 * 1024;
|
|
223612
|
+
MAX_STDERR_BYTES = 128 * 1024;
|
|
223613
|
+
MAX_OUTPUT_FILES = 50;
|
|
223614
|
+
MAX_OUTPUT_BYTES = 50 * 1024 * 1024;
|
|
223615
|
+
DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
223616
|
+
codeWorkspaces = /* @__PURE__ */ new Map();
|
|
223617
|
+
PYTHON_HELPERS_SOURCE = `
|
|
223618
|
+
import csv
|
|
223619
|
+
import json
|
|
223620
|
+
import re
|
|
223621
|
+
import sys
|
|
223622
|
+
import zlib
|
|
223623
|
+
from pathlib import Path
|
|
223624
|
+
from collections import Counter
|
|
223625
|
+
|
|
223626
|
+
def sandbox_runtime_info(path="sandbox_runtime.json"):
|
|
223627
|
+
p = Path(path)
|
|
223628
|
+
if p.exists():
|
|
223629
|
+
return json.loads(p.read_text(encoding="utf-8"))
|
|
223630
|
+
return {
|
|
223631
|
+
"networkPolicy": "unknown",
|
|
223632
|
+
"packageInstalls": "unknown",
|
|
223633
|
+
"pythonCommand": sys.executable,
|
|
223634
|
+
"helperModule": "perch_helpers",
|
|
223635
|
+
}
|
|
223636
|
+
|
|
223637
|
+
def input_manifest(path="input_manifest.json"):
|
|
223638
|
+
p = Path(path)
|
|
223639
|
+
if not p.exists():
|
|
223640
|
+
return {"root": "input", "files": [], "skipped": []}
|
|
223641
|
+
return json.loads(p.read_text(encoding="utf-8"))
|
|
223642
|
+
|
|
223643
|
+
def input_files(root="input"):
|
|
223644
|
+
base = Path(root)
|
|
223645
|
+
if not base.exists():
|
|
223646
|
+
return []
|
|
223647
|
+
return [str(p) for p in base.rglob("*") if p.is_file()]
|
|
223648
|
+
|
|
223649
|
+
def load_tabular(path):
|
|
223650
|
+
p = Path(path)
|
|
223651
|
+
suffix = p.suffix.lower()
|
|
223652
|
+
if suffix in {".csv", ".tsv"}:
|
|
223653
|
+
try:
|
|
223654
|
+
import pandas as pd
|
|
223655
|
+
return pd.read_csv(p, sep="\\t" if suffix == ".tsv" else ",")
|
|
223656
|
+
except Exception:
|
|
223657
|
+
with p.open(newline="", encoding="utf-8-sig") as fh:
|
|
223658
|
+
return list(csv.DictReader(fh, delimiter="\\t" if suffix == ".tsv" else ","))
|
|
223659
|
+
if suffix in {".xlsx", ".xls"}:
|
|
223660
|
+
try:
|
|
223661
|
+
import pandas as pd
|
|
223662
|
+
return pd.read_excel(p)
|
|
223663
|
+
except Exception as exc:
|
|
223664
|
+
raise RuntimeError("Excel loading requires pandas/openpyxl in the local Python environment") from exc
|
|
223665
|
+
raise ValueError(f"Unsupported tabular file type: {p.suffix}")
|
|
223666
|
+
|
|
223667
|
+
def extract_pdf_tables(path):
|
|
223668
|
+
try:
|
|
223669
|
+
import pdfplumber
|
|
223670
|
+
except Exception as exc:
|
|
223671
|
+
raise RuntimeError("PDF table extraction requires pdfplumber in the local Python environment") from exc
|
|
223672
|
+
rows = []
|
|
223673
|
+
with pdfplumber.open(path) as pdf:
|
|
223674
|
+
for page_index, page in enumerate(pdf.pages, start=1):
|
|
223675
|
+
for table in page.extract_tables() or []:
|
|
223676
|
+
rows.append({"page": page_index, "table": table})
|
|
223677
|
+
return rows
|
|
223678
|
+
|
|
223679
|
+
def _pdf_literal_unescape(value):
|
|
223680
|
+
out = []
|
|
223681
|
+
i = 0
|
|
223682
|
+
while i < len(value):
|
|
223683
|
+
ch = value[i]
|
|
223684
|
+
if ch != "\\\\":
|
|
223685
|
+
out.append(ch)
|
|
223686
|
+
i += 1
|
|
223687
|
+
continue
|
|
223688
|
+
i += 1
|
|
223689
|
+
if i >= len(value):
|
|
223690
|
+
break
|
|
223691
|
+
esc = value[i]
|
|
223692
|
+
i += 1
|
|
223693
|
+
mapping = {"n": "\\n", "r": "\\r", "t": "\\t", "b": "\\b", "f": "\\f", "\\\\": "\\\\", "(": "(", ")": ")"}
|
|
223694
|
+
if esc in mapping:
|
|
223695
|
+
out.append(mapping[esc])
|
|
223696
|
+
elif esc in "01234567":
|
|
223697
|
+
octal = esc
|
|
223698
|
+
for _ in range(2):
|
|
223699
|
+
if i < len(value) and value[i] in "01234567":
|
|
223700
|
+
octal += value[i]
|
|
223701
|
+
i += 1
|
|
223702
|
+
else:
|
|
223703
|
+
break
|
|
223704
|
+
try:
|
|
223705
|
+
out.append(chr(int(octal, 8)))
|
|
223706
|
+
except Exception:
|
|
223707
|
+
pass
|
|
223708
|
+
else:
|
|
223709
|
+
out.append(esc)
|
|
223710
|
+
return "".join(out)
|
|
223711
|
+
|
|
223712
|
+
def _extract_pdf_text_raw(path):
|
|
223713
|
+
data = Path(path).read_bytes()
|
|
223714
|
+
chunks = []
|
|
223715
|
+
for match in re.finditer(rb"stream\\r?\\n(.*?)\\r?\\nendstream", data, re.S):
|
|
223716
|
+
raw = match.group(1)
|
|
223717
|
+
candidates = [raw]
|
|
223718
|
+
try:
|
|
223719
|
+
candidates.insert(0, zlib.decompress(raw))
|
|
223720
|
+
except Exception:
|
|
223721
|
+
pass
|
|
223722
|
+
for candidate in candidates:
|
|
223723
|
+
try:
|
|
223724
|
+
decoded = candidate.decode("latin-1", errors="ignore")
|
|
223725
|
+
except Exception:
|
|
223726
|
+
continue
|
|
223727
|
+
literals = [_pdf_literal_unescape(x) for x in re.findall(r"\\((.*?)\\)", decoded, re.S)]
|
|
223728
|
+
if literals:
|
|
223729
|
+
chunks.extend(literals)
|
|
223730
|
+
break
|
|
223731
|
+
return " ".join(part.strip() for part in chunks if part and part.strip())
|
|
223732
|
+
|
|
223733
|
+
def extract_pdf_text(path):
|
|
223734
|
+
p = Path(path)
|
|
223735
|
+
if not p.exists():
|
|
223736
|
+
raise FileNotFoundError(str(p))
|
|
223737
|
+
errors = []
|
|
223738
|
+
for module_name in ("pypdf", "PyPDF2"):
|
|
223739
|
+
try:
|
|
223740
|
+
module = __import__(module_name)
|
|
223741
|
+
reader_cls = getattr(module, "PdfReader")
|
|
223742
|
+
reader = reader_cls(str(p))
|
|
223743
|
+
text = "\\n".join((page.extract_text() or "") for page in reader.pages)
|
|
223744
|
+
if text.strip():
|
|
223745
|
+
return text
|
|
223746
|
+
except Exception as exc:
|
|
223747
|
+
errors.append(f"{module_name}: {exc}")
|
|
223748
|
+
try:
|
|
223749
|
+
from pdfminer.high_level import extract_text
|
|
223750
|
+
text = extract_text(str(p))
|
|
223751
|
+
if text.strip():
|
|
223752
|
+
return text
|
|
223753
|
+
except Exception as exc:
|
|
223754
|
+
errors.append(f"pdfminer: {exc}")
|
|
223755
|
+
raw = _extract_pdf_text_raw(p)
|
|
223756
|
+
if raw.strip():
|
|
223757
|
+
return raw
|
|
223758
|
+
raise RuntimeError("No extractable PDF text found; tried pypdf, PyPDF2, pdfminer, and raw PDF streams. " + "; ".join(errors))
|
|
223759
|
+
|
|
223760
|
+
def extract_invoice_fields(path):
|
|
223761
|
+
text = extract_pdf_text(path)
|
|
223762
|
+
def find(pattern):
|
|
223763
|
+
m = re.search(pattern, text, re.I)
|
|
223764
|
+
return m.group(1).strip() if m else None
|
|
223765
|
+
amount = find(r"Amount\\s+Due:\\s*(?:USD\\s*)?([0-9,]+(?:\\.\\d+)?)")
|
|
223766
|
+
return {
|
|
223767
|
+
"file": str(path),
|
|
223768
|
+
"text": text,
|
|
223769
|
+
"vendor_name": text.split(" EIN")[0].strip() if " EIN" in text else None,
|
|
223770
|
+
"ein": find(r"EIN:\\s*([0-9-]+)"),
|
|
223771
|
+
"invoice_number": find(r"Invoice\\s+Number:\\s*(INV-[0-9]+)"),
|
|
223772
|
+
"invoice_date": find(r"Date:\\s*([0-9]{4}-[0-9]{2}-[0-9]{2})"),
|
|
223773
|
+
"po_number": find(r"Purchase\\s+Order:\\s*(PO-[0-9]+)"),
|
|
223774
|
+
"amount_due": float(amount.replace(",", "")) if amount else None,
|
|
223775
|
+
}
|
|
223776
|
+
|
|
223777
|
+
def find_duplicates(rows, keys):
|
|
223778
|
+
if hasattr(rows, "to_dict"):
|
|
223779
|
+
records = rows.to_dict("records")
|
|
223780
|
+
else:
|
|
223781
|
+
records = list(rows)
|
|
223782
|
+
counts = Counter(tuple(str(row.get(k, "")).strip().lower() for k in keys) for row in records)
|
|
223783
|
+
return [row for row in records if counts[tuple(str(row.get(k, "")).strip().lower() for k in keys)] > 1]
|
|
223784
|
+
|
|
223785
|
+
def write_report(report, path="output/report.json"):
|
|
223786
|
+
out = Path(path)
|
|
223787
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
223788
|
+
out.write_text(json.dumps(report, indent=2, default=str), encoding="utf-8")
|
|
223789
|
+
return str(out)
|
|
223790
|
+
`.trim();
|
|
223791
|
+
}
|
|
223792
|
+
});
|
|
223793
|
+
|
|
223794
|
+
// features/perchTerminal/runtime/cliHost/nodeLocalBridge.ts
|
|
223795
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
222676
223796
|
import fs9 from "node:fs";
|
|
222677
223797
|
import fsp from "node:fs/promises";
|
|
222678
223798
|
import os from "node:os";
|
|
@@ -222692,6 +223812,12 @@ function installCliNodeLocalBridge(input) {
|
|
|
222692
223812
|
function createCliNodeLocalBridge(input) {
|
|
222693
223813
|
const workspaceRoot = path10.resolve(input.workspaceRoot);
|
|
222694
223814
|
const now13 = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
223815
|
+
const sandboxHandlers = /* @__PURE__ */ new Map();
|
|
223816
|
+
const emitSandboxEvent = (event) => {
|
|
223817
|
+
const handlers = sandboxHandlers.get(event.runId);
|
|
223818
|
+
if (!handlers) return;
|
|
223819
|
+
for (const handler of handlers) handler(event);
|
|
223820
|
+
};
|
|
222695
223821
|
const terminalSession = () => ({
|
|
222696
223822
|
sessionId: "cli-terminal",
|
|
222697
223823
|
title: "Perch CLI",
|
|
@@ -222726,17 +223852,9 @@ function createCliNodeLocalBridge(input) {
|
|
|
222726
223852
|
}),
|
|
222727
223853
|
checkFsAccess: async (request) => {
|
|
222728
223854
|
const absolutePath = path10.resolve(expandHome4(request.absolutePath));
|
|
222729
|
-
if (request.fsAccessOverride === "allow_once" || isInside(workspaceRoot, absolutePath)) {
|
|
222730
|
-
return {
|
|
222731
|
-
decision: "allow",
|
|
222732
|
-
reason: "Allowed by Perch CLI local workspace.",
|
|
222733
|
-
absolutePath,
|
|
222734
|
-
approvalPath: absolutePath
|
|
222735
|
-
};
|
|
222736
|
-
}
|
|
222737
223855
|
return {
|
|
222738
|
-
decision: "
|
|
222739
|
-
reason:
|
|
223856
|
+
decision: "allow",
|
|
223857
|
+
reason: "Allowed by Perch CLI local filesystem access.",
|
|
222740
223858
|
absolutePath,
|
|
222741
223859
|
approvalPath: absolutePath
|
|
222742
223860
|
};
|
|
@@ -222762,7 +223880,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
222762
223880
|
executionHost: "electron_desktop"
|
|
222763
223881
|
}),
|
|
222764
223882
|
runLocalBash: async (request) => runShellCommand({
|
|
222765
|
-
workspaceRoot,
|
|
223883
|
+
workspaceRoot: resolveRequestRoot(workspaceRoot, request.workspaceRoot),
|
|
222766
223884
|
command: request.command,
|
|
222767
223885
|
cwd: request.cwd,
|
|
222768
223886
|
timeoutMs: request.timeoutMs
|
|
@@ -222798,45 +223916,45 @@ function createCliNodeLocalBridge(input) {
|
|
|
222798
223916
|
offBashTerminalEvent: () => {
|
|
222799
223917
|
},
|
|
222800
223918
|
readWorkspaceFile: async (request) => {
|
|
222801
|
-
const
|
|
222802
|
-
|
|
222803
|
-
const
|
|
222804
|
-
if (!
|
|
222805
|
-
if (
|
|
222806
|
-
return { ok: false, error: `File is too large for direct text read (${
|
|
223919
|
+
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
223920
|
+
const target = resolveReadPath(baseRoot, request.relativePath);
|
|
223921
|
+
const stat2 = await safeStat(target);
|
|
223922
|
+
if (!stat2?.isFile()) return { ok: false, error: `File does not exist: ${target}` };
|
|
223923
|
+
if (stat2.size > MAX_READ_BYTES && request.encoding !== "base64") {
|
|
223924
|
+
return { ok: false, error: `File is too large for direct text read (${stat2.size} bytes). Use grep or a narrower file.` };
|
|
222807
223925
|
}
|
|
222808
223926
|
const buffer = await fsp.readFile(target);
|
|
222809
223927
|
return {
|
|
222810
223928
|
ok: true,
|
|
222811
|
-
relativePath:
|
|
223929
|
+
relativePath: displayPath(baseRoot, target, request.relativePath),
|
|
222812
223930
|
content: request.encoding === "base64" ? buffer.toString("base64") : buffer.toString("utf8"),
|
|
222813
|
-
sizeBytes:
|
|
223931
|
+
sizeBytes: stat2.size,
|
|
222814
223932
|
...request.encoding === "base64" ? { encoding: "base64" } : {}
|
|
222815
223933
|
};
|
|
222816
223934
|
},
|
|
222817
223935
|
writeWorkspaceFile: async (request) => {
|
|
222818
|
-
const
|
|
222819
|
-
|
|
223936
|
+
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
223937
|
+
const target = resolveWritePath(baseRoot, request.relativePath);
|
|
222820
223938
|
await fsp.mkdir(path10.dirname(target), { recursive: true });
|
|
222821
223939
|
const flag = request.overwrite === true ? "w" : "wx";
|
|
223940
|
+
const payload = request.encoding === "base64" && typeof request.contentBase64 === "string" ? Buffer.from(request.contentBase64, "base64") : request.content ?? "";
|
|
222822
223941
|
try {
|
|
222823
|
-
await fsp.writeFile(target,
|
|
223942
|
+
await fsp.writeFile(target, payload, typeof payload === "string" ? { encoding: "utf8", flag } : { flag });
|
|
222824
223943
|
} catch (error) {
|
|
222825
223944
|
if (error.code === "EEXIST") {
|
|
222826
|
-
return { ok: false, error: `File already exists: ${
|
|
223945
|
+
return { ok: false, error: `File already exists: ${displayPath(baseRoot, target, request.relativePath)}. Pass overwrite=true to replace it.` };
|
|
222827
223946
|
}
|
|
222828
223947
|
throw error;
|
|
222829
223948
|
}
|
|
222830
223949
|
return {
|
|
222831
223950
|
ok: true,
|
|
222832
|
-
relativePath:
|
|
222833
|
-
bytesWritten: Buffer.byteLength(
|
|
223951
|
+
relativePath: displayPath(baseRoot, target, request.relativePath),
|
|
223952
|
+
bytesWritten: Buffer.byteLength(payload)
|
|
222834
223953
|
};
|
|
222835
223954
|
},
|
|
222836
223955
|
moveLocalFile: async (request) => {
|
|
222837
223956
|
const src = resolveReadPath(workspaceRoot, request.src);
|
|
222838
223957
|
const dest = resolveWritePath(workspaceRoot, request.dest);
|
|
222839
|
-
if (!isInside(workspaceRoot, src) || !isInside(workspaceRoot, dest)) return { ok: false, error: "Move paths must stay inside the CLI workspace." };
|
|
222840
223958
|
await fsp.mkdir(path10.dirname(dest), { recursive: true });
|
|
222841
223959
|
await fsp.rename(src, dest);
|
|
222842
223960
|
return { ok: true, fromPath: src, toPath: dest };
|
|
@@ -222844,37 +223962,32 @@ function createCliNodeLocalBridge(input) {
|
|
|
222844
223962
|
copyLocalFile: async (request) => {
|
|
222845
223963
|
const src = resolveReadPath(workspaceRoot, request.src);
|
|
222846
223964
|
const dest = resolveWritePath(workspaceRoot, request.dest);
|
|
222847
|
-
if (!isInside(workspaceRoot, src) || !isInside(workspaceRoot, dest)) return { ok: false, error: "Copy paths must stay inside the CLI workspace." };
|
|
222848
223965
|
await fsp.mkdir(path10.dirname(dest), { recursive: true });
|
|
222849
223966
|
await fsp.copyFile(src, dest);
|
|
222850
223967
|
return { ok: true, fromPath: src, toPath: dest };
|
|
222851
223968
|
},
|
|
222852
223969
|
createDirectory: async (request) => {
|
|
222853
223970
|
const target = resolveWritePath(workspaceRoot, request.path);
|
|
222854
|
-
if (!isInside(workspaceRoot, target)) return { ok: false, error: `Refusing to create directory outside CLI workspace: ${target}` };
|
|
222855
223971
|
await fsp.mkdir(target, { recursive: true });
|
|
222856
223972
|
return { ok: true, path: target };
|
|
222857
223973
|
},
|
|
222858
223974
|
deleteLocalFile: async (request) => {
|
|
222859
223975
|
const target = resolveWritePath(workspaceRoot, request.path);
|
|
222860
|
-
|
|
222861
|
-
|
|
222862
|
-
if (!
|
|
222863
|
-
if (!stat.isFile() && !stat.isSymbolicLink()) return { ok: false, error: "deleteLocalFile only deletes files, not directories." };
|
|
223976
|
+
const stat2 = await safeStat(target);
|
|
223977
|
+
if (!stat2) return { ok: false, error: `File does not exist: ${target}` };
|
|
223978
|
+
if (!stat2.isFile() && !stat2.isSymbolicLink()) return { ok: false, error: "deleteLocalFile only deletes files, not directories." };
|
|
222864
223979
|
await fsp.rm(target);
|
|
222865
223980
|
return { ok: true, path: target };
|
|
222866
223981
|
},
|
|
222867
223982
|
printFile: async () => ({ ok: false, error: "Printing is not supported from Perch CLI local mode." }),
|
|
222868
223983
|
listWorkspaceFilesGlob: async (request) => {
|
|
222869
|
-
const
|
|
222870
|
-
|
|
222871
|
-
return { ok: false, matches: [], totalFound: 0, truncated: false, resolvedRoot: workspaceRoot, executionHost: "electron_desktop", errorCode: "path_outside_workspace", errorMessage: `Path is outside CLI workspace: ${root2}` };
|
|
222872
|
-
}
|
|
223984
|
+
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
223985
|
+
const root2 = request.path ? resolveReadPath(baseRoot, request.path) : baseRoot;
|
|
222873
223986
|
const maxResults = sanitizeMaxResults(request.maxResults);
|
|
222874
223987
|
const pattern = request.pattern?.trim() || "**/*";
|
|
222875
223988
|
const regex2 = globToRegex(pattern);
|
|
222876
223989
|
const files = await collectFiles(root2, { maxVisits: Math.max(maxResults * 20, 1e3) });
|
|
222877
|
-
const matches = files.map((file) => path10.relative(root2, file).replace(/\\/g, "/")).filter((
|
|
223990
|
+
const matches = files.map((file) => path10.relative(root2, file).replace(/\\/g, "/")).filter((relative2) => regex2.test(relative2)).slice(0, maxResults);
|
|
222878
223991
|
return {
|
|
222879
223992
|
ok: true,
|
|
222880
223993
|
matches,
|
|
@@ -222884,23 +223997,21 @@ function createCliNodeLocalBridge(input) {
|
|
|
222884
223997
|
dirsVisited: 0,
|
|
222885
223998
|
pattern,
|
|
222886
223999
|
searchPath: root2,
|
|
222887
|
-
resolvedRoot:
|
|
224000
|
+
resolvedRoot: root2,
|
|
222888
224001
|
executionHost: "electron_desktop"
|
|
222889
224002
|
};
|
|
222890
224003
|
},
|
|
222891
224004
|
searchWorkspaceFilesGrep: async (request) => {
|
|
222892
|
-
const
|
|
222893
|
-
|
|
222894
|
-
return { ok: false, matches: [], totalMatches: 0, truncated: false, resolvedRoot: workspaceRoot, executionHost: "electron_desktop", errorCode: "path_outside_workspace", errorMessage: `Path is outside CLI workspace: ${root2}` };
|
|
222895
|
-
}
|
|
224005
|
+
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
224006
|
+
const root2 = request.path ? resolveReadPath(baseRoot, request.path) : baseRoot;
|
|
222896
224007
|
const maxResults = sanitizeMaxResults(request.maxResults);
|
|
222897
224008
|
const includeRegex = request.include ? globToRegex(request.include) : null;
|
|
222898
224009
|
const queryRegex = compileQueryRegex(request.query, request.caseSensitive !== false);
|
|
222899
224010
|
const files = await collectFiles(root2, { maxVisits: 5e3 });
|
|
222900
224011
|
const matches = [];
|
|
222901
224012
|
for (const file of files) {
|
|
222902
|
-
const
|
|
222903
|
-
if (includeRegex && !includeRegex.test(
|
|
224013
|
+
const relative2 = path10.relative(root2, file).replace(/\\/g, "/");
|
|
224014
|
+
if (includeRegex && !includeRegex.test(relative2)) continue;
|
|
222904
224015
|
const text = await readTextFileIfReasonable(file);
|
|
222905
224016
|
if (text === null) continue;
|
|
222906
224017
|
const lines = text.split(/\r?\n/);
|
|
@@ -222910,7 +224021,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
222910
224021
|
queryRegex.lastIndex = 0;
|
|
222911
224022
|
if (!match) continue;
|
|
222912
224023
|
matches.push({
|
|
222913
|
-
file:
|
|
224024
|
+
file: relative2,
|
|
222914
224025
|
line: index + 1,
|
|
222915
224026
|
column: match.index + 1,
|
|
222916
224027
|
match: match[0],
|
|
@@ -222928,35 +224039,34 @@ function createCliNodeLocalBridge(input) {
|
|
|
222928
224039
|
filesSearched: files.length,
|
|
222929
224040
|
query: request.query,
|
|
222930
224041
|
searchPath: root2,
|
|
222931
|
-
resolvedRoot:
|
|
224042
|
+
resolvedRoot: root2,
|
|
222932
224043
|
executionHost: "electron_desktop"
|
|
222933
224044
|
};
|
|
222934
224045
|
},
|
|
222935
224046
|
statWorkspacePath: async (request) => {
|
|
222936
|
-
const
|
|
222937
|
-
|
|
222938
|
-
|
|
222939
|
-
}
|
|
222940
|
-
const stat = await safeStat(target);
|
|
224047
|
+
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
224048
|
+
const target = resolveReadPath(baseRoot, request.relativePath);
|
|
224049
|
+
const stat2 = await safeStat(target);
|
|
222941
224050
|
return {
|
|
222942
224051
|
ok: true,
|
|
222943
|
-
relativePath: path10.relative(
|
|
222944
|
-
exists: Boolean(
|
|
222945
|
-
isFile:
|
|
222946
|
-
isDirectory:
|
|
222947
|
-
sizeBytes:
|
|
222948
|
-
modifiedAt:
|
|
224052
|
+
relativePath: path10.isAbsolute(request.relativePath) || request.relativePath.startsWith("~") ? target : path10.relative(baseRoot, target) || ".",
|
|
224053
|
+
exists: Boolean(stat2),
|
|
224054
|
+
isFile: stat2?.isFile() ?? false,
|
|
224055
|
+
isDirectory: stat2?.isDirectory() ?? false,
|
|
224056
|
+
sizeBytes: stat2?.size,
|
|
224057
|
+
modifiedAt: stat2?.mtime.toISOString(),
|
|
222949
224058
|
executionHost: "electron_desktop"
|
|
222950
224059
|
};
|
|
222951
224060
|
},
|
|
222952
224061
|
listLocalSources: async (request) => {
|
|
222953
224062
|
const query = typeof request === "object" && request ? request.query?.toLowerCase().trim() ?? "" : "";
|
|
222954
224063
|
const maxResults = typeof request === "object" && request ? sanitizeMaxResults(request.maxResults) : DEFAULT_MAX_RESULTS;
|
|
222955
|
-
const
|
|
222956
|
-
const
|
|
224064
|
+
const root2 = typeof request === "object" && request?.path ? resolveReadPath(workspaceRoot, request.path) : workspaceRoot;
|
|
224065
|
+
const files = await collectFiles(root2, { maxVisits: Math.max(maxResults * 20, 1e3) });
|
|
224066
|
+
const entries = files.map((file) => localSourceEntry(root2, file, root2 !== workspaceRoot)).filter((entry) => !query || entry.relativePath.toLowerCase().includes(query) || entry.fileName.toLowerCase().includes(query)).slice(0, maxResults);
|
|
222957
224067
|
return {
|
|
222958
224068
|
ok: true,
|
|
222959
|
-
rootId: CLI_ROOT_ID,
|
|
224069
|
+
rootId: root2 === workspaceRoot ? CLI_ROOT_ID : "cli-absolute-root",
|
|
222960
224070
|
entries,
|
|
222961
224071
|
totalFound: files.length,
|
|
222962
224072
|
truncated: files.length > maxResults,
|
|
@@ -222967,59 +224077,306 @@ function createCliNodeLocalBridge(input) {
|
|
|
222967
224077
|
},
|
|
222968
224078
|
readLocalFile: async (localSourceId) => {
|
|
222969
224079
|
const target = resolveLocalSourceId(workspaceRoot, localSourceId);
|
|
222970
|
-
|
|
222971
|
-
|
|
222972
|
-
if (!stat?.isFile()) return { ok: false, error: `File does not exist: ${target}` };
|
|
224080
|
+
const stat2 = await safeStat(target);
|
|
224081
|
+
if (!stat2?.isFile()) return { ok: false, error: `File does not exist: ${target}` };
|
|
222973
224082
|
const buffer = await fsp.readFile(target);
|
|
222974
224083
|
return {
|
|
222975
224084
|
ok: true,
|
|
222976
224085
|
data: buffer.toString("base64"),
|
|
222977
224086
|
fileName: path10.relative(workspaceRoot, target) || path10.basename(target),
|
|
222978
224087
|
mimeType: inferMimeType(target),
|
|
222979
|
-
sizeBytes:
|
|
224088
|
+
sizeBytes: stat2.size,
|
|
222980
224089
|
encoding: "base64"
|
|
222981
224090
|
};
|
|
222982
224091
|
},
|
|
222983
224092
|
getProjectRules: async () => [],
|
|
222984
|
-
readProjectMemory: async () => ({ ok: false, error: "Project memory is
|
|
222985
|
-
writeProjectMemory: async () => ({ ok: false, error: "Project memory
|
|
222986
|
-
writeMemoryFile: async () => ({ ok: false, error: "Project memory
|
|
222987
|
-
writeRule: async () => ({ ok: false, error: "Project
|
|
222988
|
-
writePerchMd: async () => ({ ok: false, error: "PERCH.md writes are
|
|
222989
|
-
readGlobalPerchMd: async () => ({ ok: false, error: "Global PERCH.md is
|
|
222990
|
-
writeGlobalPerchMd: async () => ({ ok: false, error: "Global PERCH.md
|
|
224093
|
+
readProjectMemory: async () => ({ ok: false, error: "Project memory is not available in this CLI package yet." }),
|
|
224094
|
+
writeProjectMemory: async () => ({ ok: false, error: "Project memory writes are not available in this CLI package yet." }),
|
|
224095
|
+
writeMemoryFile: async () => ({ ok: false, error: "Project memory files are not available in this CLI package yet." }),
|
|
224096
|
+
writeRule: async () => ({ ok: false, error: "Project rule writes are not available in this CLI package yet." }),
|
|
224097
|
+
writePerchMd: async () => ({ ok: false, error: "PERCH.md writes are not available in this CLI package yet." }),
|
|
224098
|
+
readGlobalPerchMd: async () => ({ ok: false, error: "Global PERCH.md is not available in this CLI package yet." }),
|
|
224099
|
+
writeGlobalPerchMd: async () => ({ ok: false, error: "Global PERCH.md writes are not available in this CLI package yet." }),
|
|
222991
224100
|
getMcpStatus: async () => [],
|
|
222992
224101
|
listMcpTools: async () => [],
|
|
222993
224102
|
callMcpTool: async () => ({ ok: false, error: "MCP tools are not available in CLI local mode." }),
|
|
222994
224103
|
reconnectMcp: async () => ({ ok: false, error: "MCP tools are not available in CLI local mode." }),
|
|
222995
|
-
|
|
222996
|
-
|
|
224104
|
+
runLocalAPAuditPacket: async (request) => runCliAPAuditPacket(workspaceRoot, request),
|
|
224105
|
+
runLocalPrepareAPEvidence: async (request) => runCliPrepareAPEvidence(workspaceRoot, request),
|
|
224106
|
+
runLocalQueryAPCases: async (request) => runCliQueryAPCases(workspaceRoot, request),
|
|
224107
|
+
runLocalRenderAPControlGraph: async (request) => runCliRenderAPControlGraph(workspaceRoot, request),
|
|
224108
|
+
prepareSandboxInputs: async (request) => prepareCliSandboxInputs(workspaceRoot, request),
|
|
224109
|
+
runSandboxCodeJob: async (request) => runCliSandboxCodeJob(workspaceRoot, request, emitSandboxEvent),
|
|
224110
|
+
onSandboxEvent: (runId, handler) => {
|
|
224111
|
+
const handlers = sandboxHandlers.get(runId) ?? /* @__PURE__ */ new Set();
|
|
224112
|
+
handlers.add(handler);
|
|
224113
|
+
sandboxHandlers.set(runId, handlers);
|
|
224114
|
+
return () => {
|
|
224115
|
+
handlers.delete(handler);
|
|
224116
|
+
if (handlers.size === 0) sandboxHandlers.delete(runId);
|
|
224117
|
+
};
|
|
222997
224118
|
},
|
|
222998
224119
|
offSandboxEvent: () => {
|
|
222999
224120
|
}
|
|
223000
224121
|
};
|
|
223001
224122
|
}
|
|
223002
|
-
async function
|
|
223003
|
-
const
|
|
223004
|
-
|
|
223005
|
-
|
|
224123
|
+
async function runCliAPAuditPacket(workspaceRoot, request) {
|
|
224124
|
+
const startMs = Date.now();
|
|
224125
|
+
try {
|
|
224126
|
+
const result2 = await generateAPCorePacket({
|
|
224127
|
+
folderPath: resolveReadPath(workspaceRoot, request.folderPath),
|
|
224128
|
+
outputRoot: request.outputRoot ? resolveWritePath(workspaceRoot, request.outputRoot) : void 0,
|
|
224129
|
+
timestamp: request.timestamp,
|
|
224130
|
+
writingStudioNarrativeHtml: request.writingStudioNarrativeHtml,
|
|
224131
|
+
writingStudioNarrativeText: request.writingStudioNarrativeText,
|
|
224132
|
+
writingStudioNarrativeDiagnostic: request.writingStudioNarrativeDiagnostic,
|
|
224133
|
+
requireWritingStudioNarrative: request.requireWritingStudioNarrative
|
|
224134
|
+
});
|
|
223006
224135
|
return {
|
|
223007
|
-
ok:
|
|
223008
|
-
|
|
223009
|
-
|
|
223010
|
-
|
|
223011
|
-
|
|
223012
|
-
|
|
223013
|
-
|
|
223014
|
-
cwd: cwd2,
|
|
224136
|
+
ok: true,
|
|
224137
|
+
data: {
|
|
224138
|
+
packet: result2.payload.packet,
|
|
224139
|
+
outputDir: result2.run.outputDir,
|
|
224140
|
+
outputFiles: result2.payload.packet.outputFiles,
|
|
224141
|
+
summary: result2.summary
|
|
224142
|
+
},
|
|
223015
224143
|
executionHost: "electron_desktop",
|
|
223016
|
-
|
|
223017
|
-
errorMessage: `Command cwd is outside CLI workspace: ${cwd2}`
|
|
224144
|
+
durationMs: Date.now() - startMs
|
|
223018
224145
|
};
|
|
224146
|
+
} catch (error) {
|
|
224147
|
+
return cliAPAuditError(startMs, error);
|
|
223019
224148
|
}
|
|
224149
|
+
}
|
|
224150
|
+
async function runCliPrepareAPEvidence(workspaceRoot, request) {
|
|
224151
|
+
const startMs = Date.now();
|
|
224152
|
+
try {
|
|
224153
|
+
const result2 = await prepareAPCoreEvidence({
|
|
224154
|
+
folderPath: resolveReadPath(workspaceRoot, request.folderPath),
|
|
224155
|
+
artifactRoot: request.artifactRoot ? resolveWritePath(workspaceRoot, request.artifactRoot) : void 0,
|
|
224156
|
+
timestamp: request.timestamp,
|
|
224157
|
+
mode: request.mode
|
|
224158
|
+
});
|
|
224159
|
+
const artifact = result2.payload.artifact;
|
|
224160
|
+
return {
|
|
224161
|
+
ok: true,
|
|
224162
|
+
data: {
|
|
224163
|
+
artifactId: artifact.artifactId,
|
|
224164
|
+
outputDir: artifact.outputDir,
|
|
224165
|
+
outputFiles: artifact.outputFiles,
|
|
224166
|
+
coverage: artifact.coverage,
|
|
224167
|
+
metrics: artifact.metrics,
|
|
224168
|
+
caseSummary: summarizeCliCases(artifact.cases ?? []),
|
|
224169
|
+
topCases: (artifact.cases ?? []).slice(0, 12),
|
|
224170
|
+
duplicateCases: result2.payload.duplicateCases,
|
|
224171
|
+
controlGraph: result2.payload.controlGraph,
|
|
224172
|
+
relativeOutputDir: typeof artifact.outputDir === "string" ? path10.basename(artifact.outputDir) : null,
|
|
224173
|
+
approvedRootMatch: true
|
|
224174
|
+
},
|
|
224175
|
+
executionHost: "electron_desktop",
|
|
224176
|
+
durationMs: Date.now() - startMs
|
|
224177
|
+
};
|
|
224178
|
+
} catch (error) {
|
|
224179
|
+
return cliAPError(startMs, error);
|
|
224180
|
+
}
|
|
224181
|
+
}
|
|
224182
|
+
async function runCliQueryAPCases(workspaceRoot, request) {
|
|
224183
|
+
const startMs = Date.now();
|
|
224184
|
+
try {
|
|
224185
|
+
const result2 = await queryAPCases(
|
|
224186
|
+
normalizeCliArtifactRequest(workspaceRoot, request)
|
|
224187
|
+
);
|
|
224188
|
+
return {
|
|
224189
|
+
ok: result2.ok,
|
|
224190
|
+
data: result2,
|
|
224191
|
+
error: result2.ok ? void 0 : result2.error,
|
|
224192
|
+
errorCode: result2.ok ? void 0 : result2.errorCode,
|
|
224193
|
+
executionHost: "electron_desktop",
|
|
224194
|
+
durationMs: Date.now() - startMs
|
|
224195
|
+
};
|
|
224196
|
+
} catch (error) {
|
|
224197
|
+
return cliAPError(startMs, error);
|
|
224198
|
+
}
|
|
224199
|
+
}
|
|
224200
|
+
async function runCliRenderAPControlGraph(workspaceRoot, request) {
|
|
224201
|
+
const startMs = Date.now();
|
|
224202
|
+
try {
|
|
224203
|
+
const result2 = await renderAPControlGraph(normalizeCliArtifactRequest(workspaceRoot, request));
|
|
224204
|
+
return {
|
|
224205
|
+
ok: result2.ok,
|
|
224206
|
+
data: result2,
|
|
224207
|
+
error: result2.ok ? void 0 : result2.error,
|
|
224208
|
+
errorCode: result2.ok ? void 0 : result2.errorCode,
|
|
224209
|
+
executionHost: "electron_desktop",
|
|
224210
|
+
durationMs: Date.now() - startMs
|
|
224211
|
+
};
|
|
224212
|
+
} catch (error) {
|
|
224213
|
+
return cliAPError(startMs, error);
|
|
224214
|
+
}
|
|
224215
|
+
}
|
|
224216
|
+
function normalizeCliArtifactRequest(workspaceRoot, request) {
|
|
224217
|
+
return {
|
|
224218
|
+
...request,
|
|
224219
|
+
folderPath: request.folderPath ? resolveReadPath(workspaceRoot, request.folderPath) : void 0,
|
|
224220
|
+
artifactRoot: request.artifactRoot ? resolveWritePath(workspaceRoot, request.artifactRoot) : void 0
|
|
224221
|
+
};
|
|
224222
|
+
}
|
|
224223
|
+
function cliAPError(startMs, error) {
|
|
224224
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
224225
|
+
return {
|
|
224226
|
+
ok: false,
|
|
224227
|
+
error: message,
|
|
224228
|
+
errorCode: classifyCliAPError(message),
|
|
224229
|
+
executionHost: "electron_desktop",
|
|
224230
|
+
durationMs: Date.now() - startMs
|
|
224231
|
+
};
|
|
224232
|
+
}
|
|
224233
|
+
function cliAPAuditError(startMs, error) {
|
|
224234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
224235
|
+
return {
|
|
224236
|
+
ok: false,
|
|
224237
|
+
error: message,
|
|
224238
|
+
errorCode: classifyCliAPError(message),
|
|
224239
|
+
executionHost: "electron_desktop",
|
|
224240
|
+
durationMs: Date.now() - startMs
|
|
224241
|
+
};
|
|
224242
|
+
}
|
|
224243
|
+
function classifyCliAPError(message) {
|
|
224244
|
+
if (/folderPath is required|invalid/i.test(message)) return "invalid_input";
|
|
224245
|
+
if (/not a directory/i.test(message)) return "invalid_folder";
|
|
224246
|
+
if (/not found|ENOENT/i.test(message)) return "folder_not_found";
|
|
224247
|
+
return "execution_failed";
|
|
224248
|
+
}
|
|
224249
|
+
function summarizeCliCases(cases) {
|
|
224250
|
+
const counts = {};
|
|
224251
|
+
for (const item of cases) {
|
|
224252
|
+
const severity = item.severity ?? "unknown";
|
|
224253
|
+
counts[severity] = (counts[severity] ?? 0) + 1;
|
|
224254
|
+
}
|
|
224255
|
+
return counts;
|
|
224256
|
+
}
|
|
224257
|
+
async function prepareCliSandboxInputs(workspaceRoot, request) {
|
|
224258
|
+
const jobId = request.jobId?.trim() || `cli-sandbox-${Date.now()}`;
|
|
224259
|
+
const maxFiles = Math.max(1, Math.min(request.maxFiles ?? 20, 100));
|
|
224260
|
+
const maxBytesPerFile = Math.max(1, Math.min(request.maxBytesPerFile ?? 20 * 1024 * 1024, 50 * 1024 * 1024));
|
|
224261
|
+
const tempDir = await fsp.mkdtemp(path10.join(os.tmpdir(), `${jobId}-`));
|
|
224262
|
+
const entries = [];
|
|
224263
|
+
const skipped = [];
|
|
224264
|
+
for (const localSourceId of request.localSourceIds.slice(0, maxFiles)) {
|
|
224265
|
+
const sourcePath = resolveLocalSourceId(workspaceRoot, localSourceId);
|
|
224266
|
+
const stat2 = await safeStat(sourcePath);
|
|
224267
|
+
if (!stat2?.isFile()) {
|
|
224268
|
+
skipped.push({ localSourceId, reason: `File does not exist: ${sourcePath}` });
|
|
224269
|
+
continue;
|
|
224270
|
+
}
|
|
224271
|
+
if (stat2.size > maxBytesPerFile) {
|
|
224272
|
+
skipped.push({ localSourceId, reason: `File is too large: ${stat2.size} bytes.` });
|
|
224273
|
+
continue;
|
|
224274
|
+
}
|
|
224275
|
+
const relativePath = safeSandboxRelativePath(path10.isAbsolute(localSourceId) || localSourceId.startsWith("~") ? path10.basename(sourcePath) : path10.relative(workspaceRoot, sourcePath));
|
|
224276
|
+
const tempPath = path10.join(tempDir, relativePath);
|
|
224277
|
+
await fsp.mkdir(path10.dirname(tempPath), { recursive: true });
|
|
224278
|
+
await fsp.copyFile(sourcePath, tempPath);
|
|
224279
|
+
entries.push({
|
|
224280
|
+
localSourceId,
|
|
224281
|
+
fileName: path10.basename(sourcePath),
|
|
224282
|
+
relativePath,
|
|
224283
|
+
tempPath,
|
|
224284
|
+
sizeBytes: stat2.size,
|
|
224285
|
+
mimeType: inferMimeType(sourcePath),
|
|
224286
|
+
fileType: guessCliFileType(sourcePath)
|
|
224287
|
+
});
|
|
224288
|
+
}
|
|
224289
|
+
return { ok: true, jobId, tempDir, entries, skipped };
|
|
224290
|
+
}
|
|
224291
|
+
async function runCliSandboxCodeJob(workspaceRoot, request, onEvent) {
|
|
224292
|
+
const hasCommand = typeof request?.command === "string" && request.command.trim().length > 0;
|
|
224293
|
+
const hasCode = typeof request?.code === "string" && request.code.trim().length > 0;
|
|
224294
|
+
if (!request || !hasCommand && !hasCode) {
|
|
224295
|
+
return {
|
|
224296
|
+
ok: false,
|
|
224297
|
+
kind: "blocked",
|
|
224298
|
+
message: "run_sandbox_code requires either command or code.",
|
|
224299
|
+
error: "invalid_input",
|
|
224300
|
+
executionHost: "electron-main"
|
|
224301
|
+
};
|
|
224302
|
+
}
|
|
224303
|
+
const hostResult = await runDesktopSandboxCodeJob(
|
|
224304
|
+
{
|
|
224305
|
+
runId: request.runId,
|
|
224306
|
+
workspaceKey: request.workspaceKey ?? request.runId ?? null,
|
|
224307
|
+
command: request.command,
|
|
224308
|
+
language: request.language,
|
|
224309
|
+
code: request.code,
|
|
224310
|
+
label: request.label ?? null,
|
|
224311
|
+
sources: Array.isArray(request.sources) ? request.sources : [],
|
|
224312
|
+
timeoutMs: request.timeoutMs,
|
|
224313
|
+
networkPolicy: request.networkPolicy ?? "disabled"
|
|
224314
|
+
},
|
|
224315
|
+
{
|
|
224316
|
+
getApprovedRoot: (rootId) => rootId === CLI_ROOT_ID ? { id: CLI_ROOT_ID, path: workspaceRoot, approvedAt: (/* @__PURE__ */ new Date()).toISOString() } : null,
|
|
224317
|
+
isPathSafe: (_rootPath, targetPath) => !targetPath.split(/[\\/]+/).includes(".."),
|
|
224318
|
+
isInsideApprovedRoot: (filePath) => {
|
|
224319
|
+
const absolute = path10.resolve(expandHome4(filePath));
|
|
224320
|
+
if (isInside(workspaceRoot, absolute)) {
|
|
224321
|
+
return { id: CLI_ROOT_ID, path: workspaceRoot, approvedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
224322
|
+
}
|
|
224323
|
+
return { id: "cli-absolute-root", path: path10.dirname(absolute), approvedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
224324
|
+
},
|
|
224325
|
+
shouldIgnore: (fileName) => IGNORED_DIRS.has(fileName),
|
|
224326
|
+
guessMimeType: inferMimeType,
|
|
224327
|
+
onEvent
|
|
224328
|
+
}
|
|
224329
|
+
);
|
|
224330
|
+
const data = sandboxHostData(hostResult);
|
|
224331
|
+
return {
|
|
224332
|
+
ok: hostResult.ok,
|
|
224333
|
+
kind: hostResult.kind,
|
|
224334
|
+
message: hostResult.message,
|
|
224335
|
+
error: hostResult.ok ? void 0 : "execution_failed",
|
|
224336
|
+
executionHost: "electron-main",
|
|
224337
|
+
runId: hostResult.runId,
|
|
224338
|
+
data
|
|
224339
|
+
};
|
|
224340
|
+
}
|
|
224341
|
+
function sandboxHostData(result2) {
|
|
224342
|
+
return {
|
|
224343
|
+
status: result2.status,
|
|
224344
|
+
exitCode: result2.exitCode,
|
|
224345
|
+
durationMs: result2.durationMs,
|
|
224346
|
+
stdout: result2.stdout,
|
|
224347
|
+
stderr: result2.stderr,
|
|
224348
|
+
stdoutTruncated: result2.stdoutTruncated,
|
|
224349
|
+
stderrTruncated: result2.stderrTruncated,
|
|
224350
|
+
producedFiles: result2.producedFiles,
|
|
224351
|
+
inputManifest: result2.inputManifest,
|
|
224352
|
+
runtimeInfo: result2.runtimeInfo,
|
|
224353
|
+
structuredOutput: result2.structuredOutput,
|
|
224354
|
+
workspacePath: result2.workspacePath,
|
|
224355
|
+
language: result2.language,
|
|
224356
|
+
reportJsonPresent: result2.reportJsonPresent,
|
|
224357
|
+
codeSha256: result2.codeSha256,
|
|
224358
|
+
warnings: result2.warnings
|
|
224359
|
+
};
|
|
224360
|
+
}
|
|
224361
|
+
function safeSandboxRelativePath(value) {
|
|
224362
|
+
const clean = value.replace(/\\/g, "/").split("/").filter((part) => part && part !== "." && part !== "..").join("/");
|
|
224363
|
+
return clean || "input";
|
|
224364
|
+
}
|
|
224365
|
+
function guessCliFileType(filePath) {
|
|
224366
|
+
const ext = path10.extname(filePath).toLowerCase();
|
|
224367
|
+
if ([".xlsx", ".xls"].includes(ext)) return "spreadsheet";
|
|
224368
|
+
if (ext === ".csv" || ext === ".tsv") return "csv";
|
|
224369
|
+
if (ext === ".pdf") return "pdf";
|
|
224370
|
+
if ([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"].includes(ext)) return "image";
|
|
224371
|
+
if ([".doc", ".docx", ".txt", ".md", ".rtf"].includes(ext)) return "document";
|
|
224372
|
+
return "unknown";
|
|
224373
|
+
}
|
|
224374
|
+
async function runShellCommand(input) {
|
|
224375
|
+
const startedAt = Date.now();
|
|
224376
|
+
const cwd2 = input.cwd ? resolveReadPath(input.workspaceRoot, input.cwd) : input.workspaceRoot;
|
|
223020
224377
|
const timeoutMs = Math.max(1e3, Math.min(input.timeoutMs ?? 3e4, 12e4));
|
|
223021
|
-
return new Promise((
|
|
223022
|
-
const child =
|
|
224378
|
+
return new Promise((resolve5) => {
|
|
224379
|
+
const child = spawn2(process.env.SHELL || "/bin/zsh", ["-lc", input.command], {
|
|
223023
224380
|
cwd: cwd2,
|
|
223024
224381
|
env: process.env,
|
|
223025
224382
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -223039,7 +224396,7 @@ async function runShellCommand(input) {
|
|
|
223039
224396
|
});
|
|
223040
224397
|
child.on("error", (error) => {
|
|
223041
224398
|
clearTimeout(timer);
|
|
223042
|
-
|
|
224399
|
+
resolve5({
|
|
223043
224400
|
ok: false,
|
|
223044
224401
|
stdout,
|
|
223045
224402
|
stderr,
|
|
@@ -223056,7 +224413,7 @@ async function runShellCommand(input) {
|
|
|
223056
224413
|
child.on("close", (code, signal) => {
|
|
223057
224414
|
clearTimeout(timer);
|
|
223058
224415
|
const capped = capOutput(stdout, stderr);
|
|
223059
|
-
|
|
224416
|
+
resolve5({
|
|
223060
224417
|
ok: code === 0 && !timedOut,
|
|
223061
224418
|
stdout: capped.stdout,
|
|
223062
224419
|
stderr: capped.stderr,
|
|
@@ -223077,8 +224434,18 @@ function resolveReadPath(root2, inputPath) {
|
|
|
223077
224434
|
const expanded = expandHome4(inputPath || ".");
|
|
223078
224435
|
return path10.resolve(path10.isAbsolute(expanded) ? expanded : path10.join(root2, expanded));
|
|
223079
224436
|
}
|
|
224437
|
+
function resolveRequestRoot(defaultRoot, requestRoot) {
|
|
224438
|
+
const trimmed = requestRoot?.trim();
|
|
224439
|
+
return trimmed ? resolveReadPath(defaultRoot, trimmed) : defaultRoot;
|
|
224440
|
+
}
|
|
223080
224441
|
function resolveWritePath(root2, inputPath) {
|
|
223081
|
-
|
|
224442
|
+
const expanded = expandHome4(inputPath || ".");
|
|
224443
|
+
return path10.resolve(path10.isAbsolute(expanded) ? expanded : path10.join(root2, expanded));
|
|
224444
|
+
}
|
|
224445
|
+
function displayPath(root2, target, requestedPath) {
|
|
224446
|
+
const expanded = expandHome4(requestedPath || ".");
|
|
224447
|
+
if (path10.isAbsolute(expanded) || requestedPath.startsWith("~")) return target;
|
|
224448
|
+
return path10.relative(root2, target) || path10.basename(target);
|
|
223082
224449
|
}
|
|
223083
224450
|
function resolveLocalSourceId(root2, localSourceId) {
|
|
223084
224451
|
const raw = localSourceId.includes("::") ? localSourceId.split("::").slice(1).join("::") : localSourceId;
|
|
@@ -223090,8 +224457,8 @@ function expandHome4(inputPath) {
|
|
|
223090
224457
|
return inputPath;
|
|
223091
224458
|
}
|
|
223092
224459
|
function isInside(root2, candidate) {
|
|
223093
|
-
const
|
|
223094
|
-
return
|
|
224460
|
+
const relative2 = path10.relative(path10.resolve(root2), path10.resolve(candidate));
|
|
224461
|
+
return relative2 === "" || !relative2.startsWith("..") && !path10.isAbsolute(relative2);
|
|
223095
224462
|
}
|
|
223096
224463
|
async function safeStat(target) {
|
|
223097
224464
|
try {
|
|
@@ -223154,8 +224521,8 @@ function escapeRegex2(value) {
|
|
|
223154
224521
|
return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
|
|
223155
224522
|
}
|
|
223156
224523
|
async function readTextFileIfReasonable(file) {
|
|
223157
|
-
const
|
|
223158
|
-
if (!
|
|
224524
|
+
const stat2 = await safeStat(file);
|
|
224525
|
+
if (!stat2?.isFile() || stat2.size > 1e6) return null;
|
|
223159
224526
|
const buffer = await fsp.readFile(file);
|
|
223160
224527
|
if (buffer.includes(0)) return null;
|
|
223161
224528
|
return buffer.toString("utf8");
|
|
@@ -223163,18 +224530,18 @@ async function readTextFileIfReasonable(file) {
|
|
|
223163
224530
|
function sanitizeMaxResults(value) {
|
|
223164
224531
|
return Math.max(1, Math.min(typeof value === "number" ? Math.floor(value) : DEFAULT_MAX_RESULTS, 1e3));
|
|
223165
224532
|
}
|
|
223166
|
-
function localSourceEntry(root2, file) {
|
|
223167
|
-
const
|
|
224533
|
+
function localSourceEntry(root2, file, absoluteId = false) {
|
|
224534
|
+
const stat2 = fs9.statSync(file);
|
|
223168
224535
|
const relativePath = path10.relative(root2, file);
|
|
223169
224536
|
const extension2 = path10.extname(file).toLowerCase();
|
|
223170
224537
|
return {
|
|
223171
|
-
localSourceId: `${CLI_ROOT_ID}::${relativePath}`,
|
|
223172
|
-
rootId: CLI_ROOT_ID,
|
|
224538
|
+
localSourceId: absoluteId ? file : `${CLI_ROOT_ID}::${relativePath}`,
|
|
224539
|
+
rootId: absoluteId ? "cli-absolute-root" : CLI_ROOT_ID,
|
|
223173
224540
|
relativePath,
|
|
223174
224541
|
fileName: path10.basename(file),
|
|
223175
224542
|
extension: extension2,
|
|
223176
|
-
sizeBytes:
|
|
223177
|
-
modifiedAt:
|
|
224543
|
+
sizeBytes: stat2.size,
|
|
224544
|
+
modifiedAt: stat2.mtime.toISOString(),
|
|
223178
224545
|
mimeType: inferMimeType(file),
|
|
223179
224546
|
isDirectory: false
|
|
223180
224547
|
};
|
|
@@ -223214,6 +224581,9 @@ var CLI_ROOT_ID, DEFAULT_MAX_RESULTS, MAX_READ_BYTES, IGNORED_DIRS;
|
|
|
223214
224581
|
var init_nodeLocalBridge = __esm({
|
|
223215
224582
|
"features/perchTerminal/runtime/cliHost/nodeLocalBridge.ts"() {
|
|
223216
224583
|
"use strict";
|
|
224584
|
+
init_perchCore();
|
|
224585
|
+
init_perchBusinessTools();
|
|
224586
|
+
init_localSandboxHost();
|
|
223217
224587
|
CLI_ROOT_ID = "cli-root";
|
|
223218
224588
|
DEFAULT_MAX_RESULTS = 200;
|
|
223219
224589
|
MAX_READ_BYTES = 2e6;
|
|
@@ -223282,6 +224652,7 @@ function buildCliTurnInput(input, resolved) {
|
|
|
223282
224652
|
const userId = input.userId ?? null;
|
|
223283
224653
|
return {
|
|
223284
224654
|
trimmedInput: resolved.prompt,
|
|
224655
|
+
clientRunId: input.clientRunId ?? null,
|
|
223285
224656
|
chatMode: input.chatMode ?? "agents",
|
|
223286
224657
|
threadId: resolved.threadId,
|
|
223287
224658
|
personaId: input.personaId ?? DEFAULT_PERSONA_ID,
|
|
@@ -223867,8 +225238,8 @@ function createMemoryAuthStorage() {
|
|
|
223867
225238
|
}
|
|
223868
225239
|
async function createOAuthCallbackServer(input) {
|
|
223869
225240
|
let resolveResult = null;
|
|
223870
|
-
const resultPromise = new Promise((
|
|
223871
|
-
resolveResult =
|
|
225241
|
+
const resultPromise = new Promise((resolve5) => {
|
|
225242
|
+
resolveResult = resolve5;
|
|
223872
225243
|
});
|
|
223873
225244
|
const server = http.createServer((request, response) => {
|
|
223874
225245
|
const requestUrl = new URL(request.url ?? "/", `http://${input.host}`);
|
|
@@ -223895,11 +225266,11 @@ async function createOAuthCallbackServer(input) {
|
|
|
223895
225266
|
resolveResult?.({ ok: true, code });
|
|
223896
225267
|
resolveResult = null;
|
|
223897
225268
|
});
|
|
223898
|
-
await new Promise((
|
|
225269
|
+
await new Promise((resolve5, reject2) => {
|
|
223899
225270
|
server.once("error", reject2);
|
|
223900
225271
|
server.listen(0, input.host, () => {
|
|
223901
225272
|
server.off("error", reject2);
|
|
223902
|
-
|
|
225273
|
+
resolve5();
|
|
223903
225274
|
});
|
|
223904
225275
|
});
|
|
223905
225276
|
const address = server.address();
|
|
@@ -223917,7 +225288,7 @@ async function createOAuthCallbackServer(input) {
|
|
|
223917
225288
|
waitForCode: async () => resultPromise,
|
|
223918
225289
|
close: async () => {
|
|
223919
225290
|
clearTimeout(timeout);
|
|
223920
|
-
await new Promise((
|
|
225291
|
+
await new Promise((resolve5) => server.close(() => resolve5()));
|
|
223921
225292
|
}
|
|
223922
225293
|
};
|
|
223923
225294
|
}
|
|
@@ -224871,21 +226242,21 @@ var require_react_development = __commonJS({
|
|
|
224871
226242
|
);
|
|
224872
226243
|
actScopeDepth = prevActScopeDepth;
|
|
224873
226244
|
}
|
|
224874
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
226245
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve5, reject2) {
|
|
224875
226246
|
var queue2 = ReactSharedInternals.actQueue;
|
|
224876
226247
|
if (null !== queue2)
|
|
224877
226248
|
if (0 !== queue2.length)
|
|
224878
226249
|
try {
|
|
224879
226250
|
flushActQueue(queue2);
|
|
224880
226251
|
enqueueTask(function() {
|
|
224881
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
226252
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve5, reject2);
|
|
224882
226253
|
});
|
|
224883
226254
|
return;
|
|
224884
226255
|
} catch (error) {
|
|
224885
226256
|
ReactSharedInternals.thrownErrors.push(error);
|
|
224886
226257
|
}
|
|
224887
226258
|
else ReactSharedInternals.actQueue = null;
|
|
224888
|
-
0 < ReactSharedInternals.thrownErrors.length ? (queue2 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject2(queue2)) :
|
|
226259
|
+
0 < ReactSharedInternals.thrownErrors.length ? (queue2 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject2(queue2)) : resolve5(returnValue);
|
|
224889
226260
|
}
|
|
224890
226261
|
function flushActQueue(queue2) {
|
|
224891
226262
|
if (!isFlushing) {
|
|
@@ -225072,7 +226443,7 @@ var require_react_development = __commonJS({
|
|
|
225072
226443
|
));
|
|
225073
226444
|
});
|
|
225074
226445
|
return {
|
|
225075
|
-
then: function(
|
|
226446
|
+
then: function(resolve5, reject2) {
|
|
225076
226447
|
didAwaitActCall = true;
|
|
225077
226448
|
thenable.then(
|
|
225078
226449
|
function(returnValue) {
|
|
@@ -225082,7 +226453,7 @@ var require_react_development = __commonJS({
|
|
|
225082
226453
|
flushActQueue(queue2), enqueueTask(function() {
|
|
225083
226454
|
return recursivelyFlushAsyncActWork(
|
|
225084
226455
|
returnValue,
|
|
225085
|
-
|
|
226456
|
+
resolve5,
|
|
225086
226457
|
reject2
|
|
225087
226458
|
);
|
|
225088
226459
|
});
|
|
@@ -225096,7 +226467,7 @@ var require_react_development = __commonJS({
|
|
|
225096
226467
|
ReactSharedInternals.thrownErrors.length = 0;
|
|
225097
226468
|
reject2(_thrownError);
|
|
225098
226469
|
}
|
|
225099
|
-
} else
|
|
226470
|
+
} else resolve5(returnValue);
|
|
225100
226471
|
},
|
|
225101
226472
|
function(error) {
|
|
225102
226473
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
@@ -225118,15 +226489,15 @@ var require_react_development = __commonJS({
|
|
|
225118
226489
|
if (0 < ReactSharedInternals.thrownErrors.length)
|
|
225119
226490
|
throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
|
|
225120
226491
|
return {
|
|
225121
|
-
then: function(
|
|
226492
|
+
then: function(resolve5, reject2) {
|
|
225122
226493
|
didAwaitActCall = true;
|
|
225123
226494
|
0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue2, enqueueTask(function() {
|
|
225124
226495
|
return recursivelyFlushAsyncActWork(
|
|
225125
226496
|
returnValue$jscomp$0,
|
|
225126
|
-
|
|
226497
|
+
resolve5,
|
|
225127
226498
|
reject2
|
|
225128
226499
|
);
|
|
225129
|
-
})) :
|
|
226500
|
+
})) : resolve5(returnValue$jscomp$0);
|
|
225130
226501
|
}
|
|
225131
226502
|
};
|
|
225132
226503
|
};
|
|
@@ -225553,7 +226924,7 @@ var init_compat = __esm({
|
|
|
225553
226924
|
});
|
|
225554
226925
|
|
|
225555
226926
|
// node_modules/environment/index.js
|
|
225556
|
-
var isBrowser, isNode2, isBun, isDeno, isElectron, isJsDom, isWebWorker, isDedicatedWorker, isSharedWorker, isServiceWorker,
|
|
226927
|
+
var isBrowser, isNode2, isBun, isDeno, isElectron, isJsDom, isWebWorker, isDedicatedWorker, isSharedWorker, isServiceWorker, platform2, isMacOs, isWindows, isLinux, isIos, isAndroid;
|
|
225557
226928
|
var init_environment = __esm({
|
|
225558
226929
|
"node_modules/environment/index.js"() {
|
|
225559
226930
|
isBrowser = globalThis.window?.document !== void 0;
|
|
@@ -225566,12 +226937,12 @@ var init_environment = __esm({
|
|
|
225566
226937
|
isDedicatedWorker = typeof DedicatedWorkerGlobalScope !== "undefined" && globalThis instanceof DedicatedWorkerGlobalScope;
|
|
225567
226938
|
isSharedWorker = typeof SharedWorkerGlobalScope !== "undefined" && globalThis instanceof SharedWorkerGlobalScope;
|
|
225568
226939
|
isServiceWorker = typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope;
|
|
225569
|
-
|
|
225570
|
-
isMacOs =
|
|
225571
|
-
isWindows =
|
|
225572
|
-
isLinux =
|
|
225573
|
-
isIos =
|
|
225574
|
-
isAndroid =
|
|
226940
|
+
platform2 = globalThis.navigator?.userAgentData?.platform;
|
|
226941
|
+
isMacOs = platform2 === "macOS" || globalThis.navigator?.platform === "MacIntel" || globalThis.navigator?.userAgent?.includes(" Mac ") === true || globalThis.process?.platform === "darwin";
|
|
226942
|
+
isWindows = platform2 === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
|
|
226943
|
+
isLinux = platform2 === "Linux" || globalThis.navigator?.platform?.startsWith("Linux") === true || globalThis.navigator?.userAgent?.includes(" Linux ") === true || globalThis.process?.platform === "linux";
|
|
226944
|
+
isIos = platform2 === "iOS" || globalThis.navigator?.platform === "MacIntel" && globalThis.navigator?.maxTouchPoints > 1 || /iPad|iPhone|iPod/.test(globalThis.navigator?.platform);
|
|
226945
|
+
isAndroid = platform2 === "Android" || globalThis.navigator?.platform === "Android" || globalThis.navigator?.userAgent?.includes(" Android ") === true || globalThis.process?.platform === "android";
|
|
225575
226946
|
}
|
|
225576
226947
|
});
|
|
225577
226948
|
|
|
@@ -229888,8 +231259,8 @@ var require_react_reconciler_production = __commonJS({
|
|
|
229888
231259
|
currentEntangledActionThenable = {
|
|
229889
231260
|
status: "pending",
|
|
229890
231261
|
value: void 0,
|
|
229891
|
-
then: function(
|
|
229892
|
-
entangledListeners.push(
|
|
231262
|
+
then: function(resolve5) {
|
|
231263
|
+
entangledListeners.push(resolve5);
|
|
229893
231264
|
}
|
|
229894
231265
|
};
|
|
229895
231266
|
}
|
|
@@ -229912,8 +231283,8 @@ var require_react_reconciler_production = __commonJS({
|
|
|
229912
231283
|
status: "pending",
|
|
229913
231284
|
value: null,
|
|
229914
231285
|
reason: null,
|
|
229915
|
-
then: function(
|
|
229916
|
-
listeners.push(
|
|
231286
|
+
then: function(resolve5) {
|
|
231287
|
+
listeners.push(resolve5);
|
|
229917
231288
|
}
|
|
229918
231289
|
};
|
|
229919
231290
|
thenable.then(
|
|
@@ -239512,8 +240883,8 @@ var require_react_reconciler_development = __commonJS({
|
|
|
239512
240883
|
currentEntangledActionThenable = {
|
|
239513
240884
|
status: "pending",
|
|
239514
240885
|
value: void 0,
|
|
239515
|
-
then: function(
|
|
239516
|
-
entangledListeners.push(
|
|
240886
|
+
then: function(resolve5) {
|
|
240887
|
+
entangledListeners.push(resolve5);
|
|
239517
240888
|
}
|
|
239518
240889
|
};
|
|
239519
240890
|
}
|
|
@@ -239536,8 +240907,8 @@ var require_react_reconciler_development = __commonJS({
|
|
|
239536
240907
|
status: "pending",
|
|
239537
240908
|
value: null,
|
|
239538
240909
|
reason: null,
|
|
239539
|
-
then: function(
|
|
239540
|
-
listeners.push(
|
|
240910
|
+
then: function(resolve5) {
|
|
240911
|
+
listeners.push(resolve5);
|
|
239541
240912
|
}
|
|
239542
240913
|
};
|
|
239543
240914
|
thenable.then(
|
|
@@ -254995,7 +256366,7 @@ var require_websocket = __commonJS({
|
|
|
254995
256366
|
var http2 = __require("http");
|
|
254996
256367
|
var net = __require("net");
|
|
254997
256368
|
var tls = __require("tls");
|
|
254998
|
-
var { randomBytes, createHash:
|
|
256369
|
+
var { randomBytes, createHash: createHash3 } = __require("crypto");
|
|
254999
256370
|
var { Duplex, Readable } = __require("stream");
|
|
255000
256371
|
var { URL: URL2 } = __require("url");
|
|
255001
256372
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -255663,7 +257034,7 @@ var require_websocket = __commonJS({
|
|
|
255663
257034
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
255664
257035
|
return;
|
|
255665
257036
|
}
|
|
255666
|
-
const digest =
|
|
257037
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
255667
257038
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
255668
257039
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
255669
257040
|
return;
|
|
@@ -256032,7 +257403,7 @@ var require_websocket_server = __commonJS({
|
|
|
256032
257403
|
var EventEmitter3 = __require("events");
|
|
256033
257404
|
var http2 = __require("http");
|
|
256034
257405
|
var { Duplex } = __require("stream");
|
|
256035
|
-
var { createHash:
|
|
257406
|
+
var { createHash: createHash3 } = __require("crypto");
|
|
256036
257407
|
var extension2 = require_extension();
|
|
256037
257408
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
256038
257409
|
var subprotocol2 = require_subprotocol();
|
|
@@ -256339,7 +257710,7 @@ var require_websocket_server = __commonJS({
|
|
|
256339
257710
|
);
|
|
256340
257711
|
}
|
|
256341
257712
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
256342
|
-
const digest =
|
|
257713
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
256343
257714
|
const headers = [
|
|
256344
257715
|
"HTTP/1.1 101 Switching Protocols",
|
|
256345
257716
|
"Upgrade: websocket",
|
|
@@ -277257,8 +278628,8 @@ var init_ink = __esm({
|
|
|
277257
278628
|
}
|
|
277258
278629
|
}
|
|
277259
278630
|
async waitUntilExit() {
|
|
277260
|
-
this.exitPromise ||= new Promise((
|
|
277261
|
-
this.resolveExitPromise =
|
|
278631
|
+
this.exitPromise ||= new Promise((resolve5, reject2) => {
|
|
278632
|
+
this.resolveExitPromise = resolve5;
|
|
277262
278633
|
this.rejectExitPromise = reject2;
|
|
277263
278634
|
});
|
|
277264
278635
|
if (!this.beforeExitHandler) {
|
|
@@ -278731,6 +280102,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
278731
280102
|
const [pulse, setPulse] = React11.useState(0);
|
|
278732
280103
|
const [, refresh] = React11.useState(0);
|
|
278733
280104
|
const liveTextRef = React11.useRef("");
|
|
280105
|
+
const activeRunRef = React11.useRef(null);
|
|
278734
280106
|
React11.useEffect(() => {
|
|
278735
280107
|
if (!working) return void 0;
|
|
278736
280108
|
const timer = setInterval(() => setPulse((value) => value + 1), 120);
|
|
@@ -278799,6 +280171,15 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
278799
280171
|
setLiveText("");
|
|
278800
280172
|
liveTextRef.current = "";
|
|
278801
280173
|
const toolNamesById = /* @__PURE__ */ new Map();
|
|
280174
|
+
const clientRunId = createCliRunId();
|
|
280175
|
+
const externalController = new AbortController();
|
|
280176
|
+
const runtimeRun = registerRuntimeRun({
|
|
280177
|
+
runId: clientRunId,
|
|
280178
|
+
kind: "turn",
|
|
280179
|
+
threadId: state.threadId,
|
|
280180
|
+
parentSignal: externalController.signal
|
|
280181
|
+
});
|
|
280182
|
+
activeRunRef.current = { runId: clientRunId, threadId: state.threadId };
|
|
278802
280183
|
try {
|
|
278803
280184
|
if (!isCliModelConnectionReady(connection)) {
|
|
278804
280185
|
addItem({
|
|
@@ -278824,8 +280205,10 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
278824
280205
|
workspaceId: hostedContext.workspaceId,
|
|
278825
280206
|
permanentMemories: hostedContext.permanentMemories,
|
|
278826
280207
|
founderModelSelection: connection.founderModelSelection,
|
|
280208
|
+
clientRunId,
|
|
278827
280209
|
desktopConnected: state.desktopConnected,
|
|
278828
280210
|
cliLocalTools: state.cliLocalTools,
|
|
280211
|
+
signal: runtimeRun.controller.signal,
|
|
278829
280212
|
onEvent: (event) => {
|
|
278830
280213
|
switch (event.type) {
|
|
278831
280214
|
case "content_delta":
|
|
@@ -278919,6 +280302,11 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
278919
280302
|
} catch (error) {
|
|
278920
280303
|
addItem({ label: "stop", text: humanizeCliError(errorMessage(error)), tone: "danger" });
|
|
278921
280304
|
} finally {
|
|
280305
|
+
finishRuntimeRun(clientRunId, runtimeRun.controller.signal.aborted ? "cancelled" : "completed");
|
|
280306
|
+
externalController.abort();
|
|
280307
|
+
if (activeRunRef.current?.runId === clientRunId) {
|
|
280308
|
+
activeRunRef.current = null;
|
|
280309
|
+
}
|
|
278922
280310
|
setWorking(false);
|
|
278923
280311
|
setWorkingText("ready");
|
|
278924
280312
|
setLiveText("");
|
|
@@ -278926,7 +280314,44 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
278926
280314
|
}
|
|
278927
280315
|
}, [addItem, app, reconnect, runTurn, updateToolItem, working]);
|
|
278928
280316
|
Ink2.useInput((input, key) => {
|
|
278929
|
-
if (working)
|
|
280317
|
+
if (working) {
|
|
280318
|
+
if (key.ctrl && input === "c") {
|
|
280319
|
+
const active = activeRunRef.current;
|
|
280320
|
+
if (active && abortRuntimeRun(active.runId, "Stopped from CLI.")) {
|
|
280321
|
+
addItem({ label: "stop", text: "stop requested", tone: "danger" });
|
|
280322
|
+
setWorkingText("stopping");
|
|
280323
|
+
}
|
|
280324
|
+
return;
|
|
280325
|
+
}
|
|
280326
|
+
if (key.return) {
|
|
280327
|
+
const steerText = draft.trim();
|
|
280328
|
+
const active = activeRunRef.current;
|
|
280329
|
+
if (steerText && active) {
|
|
280330
|
+
const result2 = submitRuntimeSteer({
|
|
280331
|
+
runId: active.runId,
|
|
280332
|
+
expectedRunId: active.runId,
|
|
280333
|
+
threadId: active.threadId,
|
|
280334
|
+
text: steerText,
|
|
280335
|
+
mode: "append",
|
|
280336
|
+
clientMessageId: `cli-steer-${Date.now()}`
|
|
280337
|
+
});
|
|
280338
|
+
if (result2.ok) {
|
|
280339
|
+
addItem({ label: "you", text: steerText, tone: "touch" });
|
|
280340
|
+
addItem({ label: "system", text: "steer queued", tone: "muted" });
|
|
280341
|
+
setDraft("");
|
|
280342
|
+
} else {
|
|
280343
|
+
addItem({ label: "need", text: result2.error, tone: "danger" });
|
|
280344
|
+
}
|
|
280345
|
+
}
|
|
280346
|
+
return;
|
|
280347
|
+
}
|
|
280348
|
+
if (key.backspace || key.delete) {
|
|
280349
|
+
setDraft((value) => value.slice(0, -1));
|
|
280350
|
+
return;
|
|
280351
|
+
}
|
|
280352
|
+
if (input && !key.escape) setDraft((value) => value + input);
|
|
280353
|
+
return;
|
|
280354
|
+
}
|
|
278930
280355
|
if (key.return) {
|
|
278931
280356
|
void submitPrompt(draft);
|
|
278932
280357
|
return;
|
|
@@ -279073,7 +280498,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
279073
280498
|
)
|
|
279074
280499
|
);
|
|
279075
280500
|
}),
|
|
279076
|
-
{ exitOnCtrlC:
|
|
280501
|
+
{ exitOnCtrlC: false }
|
|
279077
280502
|
);
|
|
279078
280503
|
await instance.waitUntilExit();
|
|
279079
280504
|
connection.restore();
|
|
@@ -279601,6 +281026,9 @@ function trimRecentMessages(messages) {
|
|
|
279601
281026
|
messages.splice(0, messages.length - 30);
|
|
279602
281027
|
}
|
|
279603
281028
|
}
|
|
281029
|
+
function createCliRunId() {
|
|
281030
|
+
return `cli-turn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
281031
|
+
}
|
|
279604
281032
|
async function runAuthCommand(parsed, writer) {
|
|
279605
281033
|
if (parsed.action === "logout") {
|
|
279606
281034
|
await clearStoredCliAuthSession();
|
|
@@ -279641,7 +281069,7 @@ async function runAuthCommand(parsed, writer) {
|
|
|
279641
281069
|
`);
|
|
279642
281070
|
return 0;
|
|
279643
281071
|
}
|
|
279644
|
-
await new Promise((
|
|
281072
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1500));
|
|
279645
281073
|
}
|
|
279646
281074
|
writer.stderr("No CLI session arrived. Try `perch login` again after confirming the browser sign-in completed.\n");
|
|
279647
281075
|
return 2;
|
|
@@ -279774,14 +281202,14 @@ function writeAPScenarioResult(result2, json, writer) {
|
|
|
279774
281202
|
}
|
|
279775
281203
|
function resolveFolderPath(input) {
|
|
279776
281204
|
const resolved = resolvePath(input);
|
|
279777
|
-
const
|
|
279778
|
-
if (!
|
|
281205
|
+
const stat2 = fs13.existsSync(resolved) ? fs13.statSync(resolved) : null;
|
|
281206
|
+
if (!stat2?.isDirectory()) throw new Error(`Folder does not exist: ${resolved}`);
|
|
279779
281207
|
return resolved;
|
|
279780
281208
|
}
|
|
279781
281209
|
function resolveExistingDirectory(input) {
|
|
279782
281210
|
const resolved = resolvePath(input);
|
|
279783
|
-
const
|
|
279784
|
-
if (!
|
|
281211
|
+
const stat2 = fs13.existsSync(resolved) ? fs13.statSync(resolved) : null;
|
|
281212
|
+
if (!stat2?.isDirectory()) throw new Error(`Directory does not exist: ${resolved}`);
|
|
279785
281213
|
return resolved;
|
|
279786
281214
|
}
|
|
279787
281215
|
function resolvePath(input) {
|
|
@@ -279871,6 +281299,7 @@ var init_perch_cli = __esm({
|
|
|
279871
281299
|
init_cliStandaloneOAuth();
|
|
279872
281300
|
init_contextMeterDisplay();
|
|
279873
281301
|
init_threadSession();
|
|
281302
|
+
init_runRegistry();
|
|
279874
281303
|
execFileAsync3 = promisify3(execFile3);
|
|
279875
281304
|
DEFAULT_CLI_LOGIN_APP_URL = "https://app.perchai.app";
|
|
279876
281305
|
CLI_PACKAGE_VERSION = readCliPackageVersion();
|