@vinihcrosa/lumem-os 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -5
- package/bin/lumem.mjs +379 -166
- package/dist/server/main.mjs +1638 -483
- package/dist/web/assets/{codemirror-setup-Csmyc9rQ.js → codemirror-setup-qkhLO-HV.js} +1 -1
- package/dist/web/assets/index-BkIky5Mw.css +32 -0
- package/dist/web/assets/index-CKedNrvw.js +101 -0
- package/dist/web/index.html +2 -2
- package/drizzle/0012_modo_do_lumem.sql +55 -0
- package/drizzle/meta/0012_snapshot.json +1681 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/dist/web/assets/index-BlWx0v0O.js +0 -101
- package/dist/web/assets/index-jS7lSqBc.css +0 -32
package/dist/server/main.mjs
CHANGED
|
@@ -7629,41 +7629,41 @@ var require_queue = __commonJS({
|
|
|
7629
7629
|
queue.drained = drained;
|
|
7630
7630
|
return queue;
|
|
7631
7631
|
function push(value) {
|
|
7632
|
-
var p = new Promise(function(
|
|
7632
|
+
var p = new Promise(function(resolve6, reject) {
|
|
7633
7633
|
pushCb(value, function(err, result) {
|
|
7634
7634
|
if (err) {
|
|
7635
7635
|
reject(err);
|
|
7636
7636
|
return;
|
|
7637
7637
|
}
|
|
7638
|
-
|
|
7638
|
+
resolve6(result);
|
|
7639
7639
|
});
|
|
7640
7640
|
});
|
|
7641
7641
|
p.catch(noop2);
|
|
7642
7642
|
return p;
|
|
7643
7643
|
}
|
|
7644
7644
|
function unshift(value) {
|
|
7645
|
-
var p = new Promise(function(
|
|
7645
|
+
var p = new Promise(function(resolve6, reject) {
|
|
7646
7646
|
unshiftCb(value, function(err, result) {
|
|
7647
7647
|
if (err) {
|
|
7648
7648
|
reject(err);
|
|
7649
7649
|
return;
|
|
7650
7650
|
}
|
|
7651
|
-
|
|
7651
|
+
resolve6(result);
|
|
7652
7652
|
});
|
|
7653
7653
|
});
|
|
7654
7654
|
p.catch(noop2);
|
|
7655
7655
|
return p;
|
|
7656
7656
|
}
|
|
7657
7657
|
function drained() {
|
|
7658
|
-
var p = new Promise(function(
|
|
7658
|
+
var p = new Promise(function(resolve6) {
|
|
7659
7659
|
process.nextTick(function() {
|
|
7660
7660
|
if (queue.idle()) {
|
|
7661
|
-
|
|
7661
|
+
resolve6();
|
|
7662
7662
|
} else {
|
|
7663
7663
|
var previousDrain = queue.drain;
|
|
7664
7664
|
queue.drain = function() {
|
|
7665
7665
|
if (typeof previousDrain === "function") previousDrain();
|
|
7666
|
-
|
|
7666
|
+
resolve6();
|
|
7667
7667
|
queue.drain = previousDrain;
|
|
7668
7668
|
};
|
|
7669
7669
|
}
|
|
@@ -8006,8 +8006,8 @@ var require_create_promise = __commonJS({
|
|
|
8006
8006
|
reject: null,
|
|
8007
8007
|
promise: null
|
|
8008
8008
|
};
|
|
8009
|
-
obj.promise = new Promise((
|
|
8010
|
-
obj.resolve =
|
|
8009
|
+
obj.promise = new Promise((resolve6, reject) => {
|
|
8010
|
+
obj.resolve = resolve6;
|
|
8011
8011
|
obj.reject = reject;
|
|
8012
8012
|
});
|
|
8013
8013
|
return obj;
|
|
@@ -8276,11 +8276,11 @@ var require_thenify = __commonJS({
|
|
|
8276
8276
|
return;
|
|
8277
8277
|
}
|
|
8278
8278
|
debug("thenify");
|
|
8279
|
-
return (
|
|
8279
|
+
return (resolve6, reject) => {
|
|
8280
8280
|
const p = this._loadRegistered();
|
|
8281
8281
|
return p.then(() => {
|
|
8282
8282
|
this[kThenifyDoNotWrap] = true;
|
|
8283
|
-
return
|
|
8283
|
+
return resolve6(this._server);
|
|
8284
8284
|
}, reject);
|
|
8285
8285
|
};
|
|
8286
8286
|
}
|
|
@@ -8417,12 +8417,12 @@ var require_avvio = __commonJS({
|
|
|
8417
8417
|
inherits(Boot, EE);
|
|
8418
8418
|
if ("asyncDispose" in Symbol) {
|
|
8419
8419
|
Boot.prototype[Symbol.asyncDispose] = function() {
|
|
8420
|
-
return new Promise((
|
|
8420
|
+
return new Promise((resolve6, reject) => {
|
|
8421
8421
|
this.close((err) => {
|
|
8422
8422
|
if (err) {
|
|
8423
8423
|
return reject(err);
|
|
8424
8424
|
}
|
|
8425
|
-
|
|
8425
|
+
resolve6();
|
|
8426
8426
|
});
|
|
8427
8427
|
});
|
|
8428
8428
|
};
|
|
@@ -8569,12 +8569,12 @@ var require_avvio = __commonJS({
|
|
|
8569
8569
|
throw new AVV_ERR_CALLBACK_NOT_FN("close", typeof func);
|
|
8570
8570
|
}
|
|
8571
8571
|
} else {
|
|
8572
|
-
promise2 = new Promise(function(
|
|
8572
|
+
promise2 = new Promise(function(resolve6, reject) {
|
|
8573
8573
|
func = function(err) {
|
|
8574
8574
|
if (err) {
|
|
8575
8575
|
return reject(err);
|
|
8576
8576
|
}
|
|
8577
|
-
|
|
8577
|
+
resolve6();
|
|
8578
8578
|
};
|
|
8579
8579
|
});
|
|
8580
8580
|
}
|
|
@@ -8594,7 +8594,7 @@ var require_avvio = __commonJS({
|
|
|
8594
8594
|
queueMicrotask(this.start.bind(this));
|
|
8595
8595
|
return;
|
|
8596
8596
|
}
|
|
8597
|
-
return new Promise((
|
|
8597
|
+
return new Promise((resolve6, reject) => {
|
|
8598
8598
|
this._readyQ.push(readyPromiseCB);
|
|
8599
8599
|
this.start();
|
|
8600
8600
|
const relativeContext = this._current[0].server;
|
|
@@ -8602,7 +8602,7 @@ var require_avvio = __commonJS({
|
|
|
8602
8602
|
if (err) {
|
|
8603
8603
|
reject(err);
|
|
8604
8604
|
} else {
|
|
8605
|
-
|
|
8605
|
+
resolve6(relativeContext);
|
|
8606
8606
|
}
|
|
8607
8607
|
process.nextTick(done);
|
|
8608
8608
|
}
|
|
@@ -9982,8 +9982,8 @@ var require_promise = __commonJS({
|
|
|
9982
9982
|
var { kTestInternals } = require_symbols2();
|
|
9983
9983
|
function withResolvers2() {
|
|
9984
9984
|
let res, rej;
|
|
9985
|
-
const promise2 = new Promise((
|
|
9986
|
-
res =
|
|
9985
|
+
const promise2 = new Promise((resolve6, reject) => {
|
|
9986
|
+
res = resolve6;
|
|
9987
9987
|
rej = reject;
|
|
9988
9988
|
});
|
|
9989
9989
|
return { promise: promise2, resolve: res, reject: rej };
|
|
@@ -10082,15 +10082,15 @@ var require_server = __commonJS({
|
|
|
10082
10082
|
if (cb === void 0) {
|
|
10083
10083
|
const listening = listenPromise.call(this, server, listenOptions);
|
|
10084
10084
|
return listening.then((address) => {
|
|
10085
|
-
const { promise: promise2, resolve:
|
|
10085
|
+
const { promise: promise2, resolve: resolve6 } = PonyPromise.withResolvers();
|
|
10086
10086
|
if (host === "localhost") {
|
|
10087
10087
|
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
10088
10088
|
this[kState].listening = true;
|
|
10089
|
-
|
|
10089
|
+
resolve6(address);
|
|
10090
10090
|
onListenHookRunner(this);
|
|
10091
10091
|
});
|
|
10092
10092
|
} else {
|
|
10093
|
-
|
|
10093
|
+
resolve6(address);
|
|
10094
10094
|
onListenHookRunner(this);
|
|
10095
10095
|
}
|
|
10096
10096
|
return promise2;
|
|
@@ -10217,7 +10217,7 @@ var require_server = __commonJS({
|
|
|
10217
10217
|
}
|
|
10218
10218
|
return this.ready().then(() => {
|
|
10219
10219
|
if (this[kState].aborted) return;
|
|
10220
|
-
const { promise: promise2, resolve:
|
|
10220
|
+
const { promise: promise2, resolve: resolve6, reject } = PonyPromise.withResolvers();
|
|
10221
10221
|
const errEventHandler = (err) => {
|
|
10222
10222
|
cleanup();
|
|
10223
10223
|
this[kState].listening = false;
|
|
@@ -10226,7 +10226,7 @@ var require_server = __commonJS({
|
|
|
10226
10226
|
const listeningEventHandler = () => {
|
|
10227
10227
|
cleanup();
|
|
10228
10228
|
this[kState].listening = true;
|
|
10229
|
-
|
|
10229
|
+
resolve6(logServerAddress.call(
|
|
10230
10230
|
this,
|
|
10231
10231
|
server,
|
|
10232
10232
|
listenOptions.listenTextResolver || defaultResolveServerListeningText
|
|
@@ -15181,7 +15181,7 @@ var require_thread_stream = __commonJS({
|
|
|
15181
15181
|
var { version: version3 } = require_package();
|
|
15182
15182
|
var { EventEmitter: EventEmitter2 } = __require("events");
|
|
15183
15183
|
var { Worker } = __require("worker_threads");
|
|
15184
|
-
var { join:
|
|
15184
|
+
var { join: join21 } = __require("path");
|
|
15185
15185
|
var { pathToFileURL } = __require("url");
|
|
15186
15186
|
var { wait } = require_wait();
|
|
15187
15187
|
var {
|
|
@@ -15232,7 +15232,7 @@ var require_thread_stream = __commonJS({
|
|
|
15232
15232
|
function createWorker(stream, opts) {
|
|
15233
15233
|
const { filename, workerData } = opts;
|
|
15234
15234
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
15235
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
15235
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join21(__dirname, "lib", "worker.js");
|
|
15236
15236
|
const worker = new Worker(toExecute, {
|
|
15237
15237
|
...opts.workerOpts,
|
|
15238
15238
|
name: opts.workerOpts?.name || "thread-stream",
|
|
@@ -15700,7 +15700,7 @@ var require_transport = __commonJS({
|
|
|
15700
15700
|
var { createRequire } = __require("module");
|
|
15701
15701
|
var { existsSync: existsSync10 } = __require("node:fs");
|
|
15702
15702
|
var getCallers = require_caller();
|
|
15703
|
-
var { join:
|
|
15703
|
+
var { join: join21, isAbsolute: isAbsolute8, sep: sep6 } = __require("node:path");
|
|
15704
15704
|
var { fileURLToPath: fileURLToPath3 } = __require("node:url");
|
|
15705
15705
|
var sleep = require_atomic_sleep();
|
|
15706
15706
|
var onExit = require_on_exit_leak_free();
|
|
@@ -15772,7 +15772,7 @@ var require_transport = __commonJS({
|
|
|
15772
15772
|
return false;
|
|
15773
15773
|
}
|
|
15774
15774
|
}
|
|
15775
|
-
return
|
|
15775
|
+
return isAbsolute8(path) && !existsSync10(path);
|
|
15776
15776
|
}
|
|
15777
15777
|
function stripQuotes(value) {
|
|
15778
15778
|
const first = value[0];
|
|
@@ -15853,7 +15853,7 @@ var require_transport = __commonJS({
|
|
|
15853
15853
|
throw new Error("only one of target or targets can be specified");
|
|
15854
15854
|
}
|
|
15855
15855
|
if (targets) {
|
|
15856
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
15856
|
+
target = bundlerOverrides["pino-worker"] || join21(__dirname, "worker.js");
|
|
15857
15857
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
15858
15858
|
return {
|
|
15859
15859
|
...dest,
|
|
@@ -15871,7 +15871,7 @@ var require_transport = __commonJS({
|
|
|
15871
15871
|
});
|
|
15872
15872
|
});
|
|
15873
15873
|
} else if (pipeline) {
|
|
15874
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
15874
|
+
target = bundlerOverrides["pino-worker"] || join21(__dirname, "worker.js");
|
|
15875
15875
|
options.pipelines = [pipeline.map((dest) => {
|
|
15876
15876
|
return {
|
|
15877
15877
|
...dest,
|
|
@@ -15890,11 +15890,11 @@ var require_transport = __commonJS({
|
|
|
15890
15890
|
return buildStream(fixTarget(target), options, worker, sync, name);
|
|
15891
15891
|
function fixTarget(origin) {
|
|
15892
15892
|
origin = bundlerOverrides[origin] || origin;
|
|
15893
|
-
if (
|
|
15893
|
+
if (isAbsolute8(origin) || origin.indexOf("file://") === 0) {
|
|
15894
15894
|
return origin;
|
|
15895
15895
|
}
|
|
15896
15896
|
if (origin === "pino/file") {
|
|
15897
|
-
return
|
|
15897
|
+
return join21(__dirname, "..", "file.js");
|
|
15898
15898
|
}
|
|
15899
15899
|
let fixTarget2;
|
|
15900
15900
|
for (const filePath of callers) {
|
|
@@ -16874,7 +16874,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
16874
16874
|
return circularValue;
|
|
16875
16875
|
}
|
|
16876
16876
|
let res = "";
|
|
16877
|
-
let
|
|
16877
|
+
let join21 = ",";
|
|
16878
16878
|
const originalIndentation = indentation;
|
|
16879
16879
|
if (Array.isArray(value)) {
|
|
16880
16880
|
if (value.length === 0) {
|
|
@@ -16888,7 +16888,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
16888
16888
|
indentation += spacer;
|
|
16889
16889
|
res += `
|
|
16890
16890
|
${indentation}`;
|
|
16891
|
-
|
|
16891
|
+
join21 = `,
|
|
16892
16892
|
${indentation}`;
|
|
16893
16893
|
}
|
|
16894
16894
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -16896,13 +16896,13 @@ ${indentation}`;
|
|
|
16896
16896
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
16897
16897
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
16898
16898
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
16899
|
-
res +=
|
|
16899
|
+
res += join21;
|
|
16900
16900
|
}
|
|
16901
16901
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
16902
16902
|
res += tmp !== void 0 ? tmp : "null";
|
|
16903
16903
|
if (value.length - 1 > maximumBreadth) {
|
|
16904
16904
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
16905
|
-
res += `${
|
|
16905
|
+
res += `${join21}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
16906
16906
|
}
|
|
16907
16907
|
if (spacer !== "") {
|
|
16908
16908
|
res += `
|
|
@@ -16923,7 +16923,7 @@ ${originalIndentation}`;
|
|
|
16923
16923
|
let separator = "";
|
|
16924
16924
|
if (spacer !== "") {
|
|
16925
16925
|
indentation += spacer;
|
|
16926
|
-
|
|
16926
|
+
join21 = `,
|
|
16927
16927
|
${indentation}`;
|
|
16928
16928
|
whitespace = " ";
|
|
16929
16929
|
}
|
|
@@ -16937,13 +16937,13 @@ ${indentation}`;
|
|
|
16937
16937
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
16938
16938
|
if (tmp !== void 0) {
|
|
16939
16939
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
16940
|
-
separator =
|
|
16940
|
+
separator = join21;
|
|
16941
16941
|
}
|
|
16942
16942
|
}
|
|
16943
16943
|
if (keyLength > maximumBreadth) {
|
|
16944
16944
|
const removedKeys = keyLength - maximumBreadth;
|
|
16945
16945
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
16946
|
-
separator =
|
|
16946
|
+
separator = join21;
|
|
16947
16947
|
}
|
|
16948
16948
|
if (spacer !== "" && separator.length > 1) {
|
|
16949
16949
|
res = `
|
|
@@ -16984,7 +16984,7 @@ ${originalIndentation}`;
|
|
|
16984
16984
|
}
|
|
16985
16985
|
const originalIndentation = indentation;
|
|
16986
16986
|
let res = "";
|
|
16987
|
-
let
|
|
16987
|
+
let join21 = ",";
|
|
16988
16988
|
if (Array.isArray(value)) {
|
|
16989
16989
|
if (value.length === 0) {
|
|
16990
16990
|
return "[]";
|
|
@@ -16997,7 +16997,7 @@ ${originalIndentation}`;
|
|
|
16997
16997
|
indentation += spacer;
|
|
16998
16998
|
res += `
|
|
16999
16999
|
${indentation}`;
|
|
17000
|
-
|
|
17000
|
+
join21 = `,
|
|
17001
17001
|
${indentation}`;
|
|
17002
17002
|
}
|
|
17003
17003
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -17005,13 +17005,13 @@ ${indentation}`;
|
|
|
17005
17005
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
17006
17006
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
17007
17007
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
17008
|
-
res +=
|
|
17008
|
+
res += join21;
|
|
17009
17009
|
}
|
|
17010
17010
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
17011
17011
|
res += tmp !== void 0 ? tmp : "null";
|
|
17012
17012
|
if (value.length - 1 > maximumBreadth) {
|
|
17013
17013
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
17014
|
-
res += `${
|
|
17014
|
+
res += `${join21}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
17015
17015
|
}
|
|
17016
17016
|
if (spacer !== "") {
|
|
17017
17017
|
res += `
|
|
@@ -17024,7 +17024,7 @@ ${originalIndentation}`;
|
|
|
17024
17024
|
let whitespace = "";
|
|
17025
17025
|
if (spacer !== "") {
|
|
17026
17026
|
indentation += spacer;
|
|
17027
|
-
|
|
17027
|
+
join21 = `,
|
|
17028
17028
|
${indentation}`;
|
|
17029
17029
|
whitespace = " ";
|
|
17030
17030
|
}
|
|
@@ -17033,7 +17033,7 @@ ${indentation}`;
|
|
|
17033
17033
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
17034
17034
|
if (tmp !== void 0) {
|
|
17035
17035
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
17036
|
-
separator =
|
|
17036
|
+
separator = join21;
|
|
17037
17037
|
}
|
|
17038
17038
|
}
|
|
17039
17039
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -17091,20 +17091,20 @@ ${originalIndentation}`;
|
|
|
17091
17091
|
indentation += spacer;
|
|
17092
17092
|
let res2 = `
|
|
17093
17093
|
${indentation}`;
|
|
17094
|
-
const
|
|
17094
|
+
const join22 = `,
|
|
17095
17095
|
${indentation}`;
|
|
17096
17096
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
17097
17097
|
let i = 0;
|
|
17098
17098
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
17099
17099
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
17100
17100
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
17101
|
-
res2 +=
|
|
17101
|
+
res2 += join22;
|
|
17102
17102
|
}
|
|
17103
17103
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
17104
17104
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
17105
17105
|
if (value.length - 1 > maximumBreadth) {
|
|
17106
17106
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
17107
|
-
res2 += `${
|
|
17107
|
+
res2 += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
17108
17108
|
}
|
|
17109
17109
|
res2 += `
|
|
17110
17110
|
${originalIndentation}`;
|
|
@@ -17120,16 +17120,16 @@ ${originalIndentation}`;
|
|
|
17120
17120
|
return '"[Object]"';
|
|
17121
17121
|
}
|
|
17122
17122
|
indentation += spacer;
|
|
17123
|
-
const
|
|
17123
|
+
const join21 = `,
|
|
17124
17124
|
${indentation}`;
|
|
17125
17125
|
let res = "";
|
|
17126
17126
|
let separator = "";
|
|
17127
17127
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
17128
17128
|
if (isTypedArrayWithEntries(value)) {
|
|
17129
|
-
res += stringifyTypedArray(value,
|
|
17129
|
+
res += stringifyTypedArray(value, join21, maximumBreadth);
|
|
17130
17130
|
keys = keys.slice(value.length);
|
|
17131
17131
|
maximumPropertiesToStringify -= value.length;
|
|
17132
|
-
separator =
|
|
17132
|
+
separator = join21;
|
|
17133
17133
|
}
|
|
17134
17134
|
if (deterministic) {
|
|
17135
17135
|
keys = sort(keys, comparator);
|
|
@@ -17140,13 +17140,13 @@ ${indentation}`;
|
|
|
17140
17140
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
17141
17141
|
if (tmp !== void 0) {
|
|
17142
17142
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
17143
|
-
separator =
|
|
17143
|
+
separator = join21;
|
|
17144
17144
|
}
|
|
17145
17145
|
}
|
|
17146
17146
|
if (keyLength > maximumBreadth) {
|
|
17147
17147
|
const removedKeys = keyLength - maximumBreadth;
|
|
17148
17148
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
17149
|
-
separator =
|
|
17149
|
+
separator = join21;
|
|
17150
17150
|
}
|
|
17151
17151
|
if (separator !== "") {
|
|
17152
17152
|
res = `
|
|
@@ -24203,7 +24203,7 @@ var require_compile = __commonJS({
|
|
|
24203
24203
|
const schOrFunc = root.refs[ref];
|
|
24204
24204
|
if (schOrFunc)
|
|
24205
24205
|
return schOrFunc;
|
|
24206
|
-
let _sch =
|
|
24206
|
+
let _sch = resolve6.call(this, root, ref);
|
|
24207
24207
|
if (_sch === void 0) {
|
|
24208
24208
|
const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
24209
24209
|
const { schemaId } = this.opts;
|
|
@@ -24230,7 +24230,7 @@ var require_compile = __commonJS({
|
|
|
24230
24230
|
function sameSchemaEnv(s1, s2) {
|
|
24231
24231
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
24232
24232
|
}
|
|
24233
|
-
function
|
|
24233
|
+
function resolve6(root, ref) {
|
|
24234
24234
|
let sch;
|
|
24235
24235
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
24236
24236
|
ref = sch;
|
|
@@ -24861,7 +24861,7 @@ var require_fast_uri = __commonJS({
|
|
|
24861
24861
|
}
|
|
24862
24862
|
return uri;
|
|
24863
24863
|
}
|
|
24864
|
-
function
|
|
24864
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
24865
24865
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
24866
24866
|
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
24867
24867
|
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
@@ -24872,49 +24872,49 @@ var require_fast_uri = __commonJS({
|
|
|
24872
24872
|
schemelessOptions.skipEscape = true;
|
|
24873
24873
|
return serialize(resolved, schemelessOptions);
|
|
24874
24874
|
}
|
|
24875
|
-
function resolveComponent(base,
|
|
24875
|
+
function resolveComponent(base, relative5, options, skipNormalization) {
|
|
24876
24876
|
const target = {};
|
|
24877
24877
|
if (!skipNormalization) {
|
|
24878
24878
|
base = parse5(serialize(base, options), options);
|
|
24879
|
-
|
|
24879
|
+
relative5 = parse5(serialize(relative5, options), options);
|
|
24880
24880
|
}
|
|
24881
24881
|
options = options || {};
|
|
24882
|
-
if (!options.tolerant &&
|
|
24883
|
-
target.scheme =
|
|
24884
|
-
target.userinfo =
|
|
24885
|
-
target.host =
|
|
24886
|
-
target.port =
|
|
24887
|
-
target.path = removeDotSegments(
|
|
24888
|
-
target.query =
|
|
24882
|
+
if (!options.tolerant && relative5.scheme) {
|
|
24883
|
+
target.scheme = relative5.scheme;
|
|
24884
|
+
target.userinfo = relative5.userinfo;
|
|
24885
|
+
target.host = relative5.host;
|
|
24886
|
+
target.port = relative5.port;
|
|
24887
|
+
target.path = removeDotSegments(relative5.path || "");
|
|
24888
|
+
target.query = relative5.query;
|
|
24889
24889
|
} else {
|
|
24890
|
-
if (
|
|
24891
|
-
target.userinfo =
|
|
24892
|
-
target.host =
|
|
24893
|
-
target.port =
|
|
24894
|
-
target.path = removeDotSegments(
|
|
24895
|
-
target.query =
|
|
24890
|
+
if (relative5.userinfo !== void 0 || relative5.host !== void 0 || relative5.port !== void 0) {
|
|
24891
|
+
target.userinfo = relative5.userinfo;
|
|
24892
|
+
target.host = relative5.host;
|
|
24893
|
+
target.port = relative5.port;
|
|
24894
|
+
target.path = removeDotSegments(relative5.path || "");
|
|
24895
|
+
target.query = relative5.query;
|
|
24896
24896
|
} else {
|
|
24897
|
-
if (!
|
|
24897
|
+
if (!relative5.path) {
|
|
24898
24898
|
target.path = base.path;
|
|
24899
|
-
if (
|
|
24900
|
-
target.query =
|
|
24899
|
+
if (relative5.query !== void 0) {
|
|
24900
|
+
target.query = relative5.query;
|
|
24901
24901
|
} else {
|
|
24902
24902
|
target.query = base.query;
|
|
24903
24903
|
}
|
|
24904
24904
|
} else {
|
|
24905
|
-
if (
|
|
24906
|
-
target.path = removeDotSegments(
|
|
24905
|
+
if (relative5.path[0] === "/") {
|
|
24906
|
+
target.path = removeDotSegments(relative5.path);
|
|
24907
24907
|
} else {
|
|
24908
24908
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
24909
|
-
target.path = "/" +
|
|
24909
|
+
target.path = "/" + relative5.path;
|
|
24910
24910
|
} else if (!base.path) {
|
|
24911
|
-
target.path =
|
|
24911
|
+
target.path = relative5.path;
|
|
24912
24912
|
} else {
|
|
24913
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
24913
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative5.path;
|
|
24914
24914
|
}
|
|
24915
24915
|
target.path = removeDotSegments(target.path);
|
|
24916
24916
|
}
|
|
24917
|
-
target.query =
|
|
24917
|
+
target.query = relative5.query;
|
|
24918
24918
|
}
|
|
24919
24919
|
target.userinfo = base.userinfo;
|
|
24920
24920
|
target.host = base.host;
|
|
@@ -24922,7 +24922,7 @@ var require_fast_uri = __commonJS({
|
|
|
24922
24922
|
}
|
|
24923
24923
|
target.scheme = base.scheme;
|
|
24924
24924
|
}
|
|
24925
|
-
target.fragment =
|
|
24925
|
+
target.fragment = relative5.fragment;
|
|
24926
24926
|
return target;
|
|
24927
24927
|
}
|
|
24928
24928
|
function equal(uriA, uriB, options) {
|
|
@@ -25145,7 +25145,7 @@ var require_fast_uri = __commonJS({
|
|
|
25145
25145
|
var fastUri = {
|
|
25146
25146
|
SCHEMES,
|
|
25147
25147
|
normalize: normalize5,
|
|
25148
|
-
resolve:
|
|
25148
|
+
resolve: resolve6,
|
|
25149
25149
|
resolveComponent,
|
|
25150
25150
|
equal,
|
|
25151
25151
|
serialize,
|
|
@@ -28901,37 +28901,37 @@ var require_parseJson = __commonJS({
|
|
|
28901
28901
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28902
28902
|
exports.parseJsonString = exports.parseJsonNumber = exports.parseJson = void 0;
|
|
28903
28903
|
var rxParseJson = /position\s(\d+)(?: \(line \d+ column \d+\))?$/;
|
|
28904
|
-
function
|
|
28904
|
+
function parseJson2(s, pos) {
|
|
28905
28905
|
let endPos;
|
|
28906
|
-
|
|
28906
|
+
parseJson2.message = void 0;
|
|
28907
28907
|
let matches;
|
|
28908
28908
|
if (pos)
|
|
28909
28909
|
s = s.slice(pos);
|
|
28910
28910
|
try {
|
|
28911
|
-
|
|
28911
|
+
parseJson2.position = pos + s.length;
|
|
28912
28912
|
return JSON.parse(s);
|
|
28913
28913
|
} catch (e) {
|
|
28914
28914
|
matches = rxParseJson.exec(e.message);
|
|
28915
28915
|
if (!matches) {
|
|
28916
|
-
|
|
28916
|
+
parseJson2.message = "unexpected end";
|
|
28917
28917
|
return void 0;
|
|
28918
28918
|
}
|
|
28919
28919
|
endPos = +matches[1];
|
|
28920
28920
|
const c = s[endPos];
|
|
28921
28921
|
s = s.slice(0, endPos);
|
|
28922
|
-
|
|
28922
|
+
parseJson2.position = pos + endPos;
|
|
28923
28923
|
try {
|
|
28924
28924
|
return JSON.parse(s);
|
|
28925
28925
|
} catch (e1) {
|
|
28926
|
-
|
|
28926
|
+
parseJson2.message = `unexpected token ${c}`;
|
|
28927
28927
|
return void 0;
|
|
28928
28928
|
}
|
|
28929
28929
|
}
|
|
28930
28930
|
}
|
|
28931
|
-
exports.parseJson =
|
|
28932
|
-
|
|
28933
|
-
|
|
28934
|
-
|
|
28931
|
+
exports.parseJson = parseJson2;
|
|
28932
|
+
parseJson2.message = void 0;
|
|
28933
|
+
parseJson2.position = 0;
|
|
28934
|
+
parseJson2.code = 'require("ajv/dist/runtime/parseJson").parseJson';
|
|
28935
28935
|
function parseJsonNumber(s, pos, maxDigits) {
|
|
28936
28936
|
let numStr = "";
|
|
28937
28937
|
let c;
|
|
@@ -30145,7 +30145,7 @@ var require_fast_uri2 = __commonJS({
|
|
|
30145
30145
|
}
|
|
30146
30146
|
return uri;
|
|
30147
30147
|
}
|
|
30148
|
-
function
|
|
30148
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
30149
30149
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
30150
30150
|
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
30151
30151
|
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
@@ -30156,49 +30156,49 @@ var require_fast_uri2 = __commonJS({
|
|
|
30156
30156
|
schemelessOptions.skipEscape = true;
|
|
30157
30157
|
return serialize(resolved, schemelessOptions);
|
|
30158
30158
|
}
|
|
30159
|
-
function resolveComponent(base,
|
|
30159
|
+
function resolveComponent(base, relative5, options, skipNormalization) {
|
|
30160
30160
|
const target = {};
|
|
30161
30161
|
if (!skipNormalization) {
|
|
30162
30162
|
base = parse5(serialize(base, options), options);
|
|
30163
|
-
|
|
30163
|
+
relative5 = parse5(serialize(relative5, options), options);
|
|
30164
30164
|
}
|
|
30165
30165
|
options = options || {};
|
|
30166
|
-
if (!options.tolerant &&
|
|
30167
|
-
target.scheme =
|
|
30168
|
-
target.userinfo =
|
|
30169
|
-
target.host =
|
|
30170
|
-
target.port =
|
|
30171
|
-
target.path = removeDotSegments(
|
|
30172
|
-
target.query =
|
|
30166
|
+
if (!options.tolerant && relative5.scheme) {
|
|
30167
|
+
target.scheme = relative5.scheme;
|
|
30168
|
+
target.userinfo = relative5.userinfo;
|
|
30169
|
+
target.host = relative5.host;
|
|
30170
|
+
target.port = relative5.port;
|
|
30171
|
+
target.path = removeDotSegments(relative5.path || "");
|
|
30172
|
+
target.query = relative5.query;
|
|
30173
30173
|
} else {
|
|
30174
|
-
if (
|
|
30175
|
-
target.userinfo =
|
|
30176
|
-
target.host =
|
|
30177
|
-
target.port =
|
|
30178
|
-
target.path = removeDotSegments(
|
|
30179
|
-
target.query =
|
|
30174
|
+
if (relative5.userinfo !== void 0 || relative5.host !== void 0 || relative5.port !== void 0) {
|
|
30175
|
+
target.userinfo = relative5.userinfo;
|
|
30176
|
+
target.host = relative5.host;
|
|
30177
|
+
target.port = relative5.port;
|
|
30178
|
+
target.path = removeDotSegments(relative5.path || "");
|
|
30179
|
+
target.query = relative5.query;
|
|
30180
30180
|
} else {
|
|
30181
|
-
if (!
|
|
30181
|
+
if (!relative5.path) {
|
|
30182
30182
|
target.path = base.path;
|
|
30183
|
-
if (
|
|
30184
|
-
target.query =
|
|
30183
|
+
if (relative5.query !== void 0) {
|
|
30184
|
+
target.query = relative5.query;
|
|
30185
30185
|
} else {
|
|
30186
30186
|
target.query = base.query;
|
|
30187
30187
|
}
|
|
30188
30188
|
} else {
|
|
30189
|
-
if (
|
|
30190
|
-
target.path = removeDotSegments(
|
|
30189
|
+
if (relative5.path[0] === "/") {
|
|
30190
|
+
target.path = removeDotSegments(relative5.path);
|
|
30191
30191
|
} else {
|
|
30192
30192
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
30193
|
-
target.path = "/" +
|
|
30193
|
+
target.path = "/" + relative5.path;
|
|
30194
30194
|
} else if (!base.path) {
|
|
30195
|
-
target.path =
|
|
30195
|
+
target.path = relative5.path;
|
|
30196
30196
|
} else {
|
|
30197
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
30197
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative5.path;
|
|
30198
30198
|
}
|
|
30199
30199
|
target.path = removeDotSegments(target.path);
|
|
30200
30200
|
}
|
|
30201
|
-
target.query =
|
|
30201
|
+
target.query = relative5.query;
|
|
30202
30202
|
}
|
|
30203
30203
|
target.userinfo = base.userinfo;
|
|
30204
30204
|
target.host = base.host;
|
|
@@ -30206,7 +30206,7 @@ var require_fast_uri2 = __commonJS({
|
|
|
30206
30206
|
}
|
|
30207
30207
|
target.scheme = base.scheme;
|
|
30208
30208
|
}
|
|
30209
|
-
target.fragment =
|
|
30209
|
+
target.fragment = relative5.fragment;
|
|
30210
30210
|
return target;
|
|
30211
30211
|
}
|
|
30212
30212
|
function equal(uriA, uriB, options) {
|
|
@@ -30428,7 +30428,7 @@ var require_fast_uri2 = __commonJS({
|
|
|
30428
30428
|
var fastUri = {
|
|
30429
30429
|
SCHEMES,
|
|
30430
30430
|
normalize: normalize5,
|
|
30431
|
-
resolve:
|
|
30431
|
+
resolve: resolve6,
|
|
30432
30432
|
resolveComponent,
|
|
30433
30433
|
equal,
|
|
30434
30434
|
serialize,
|
|
@@ -42289,9 +42289,9 @@ var require_light_my_request = __commonJS({
|
|
|
42289
42289
|
const res = new Response2(req, callback);
|
|
42290
42290
|
return makeRequest(dispatchFunc, server, req, res);
|
|
42291
42291
|
} else {
|
|
42292
|
-
return new Promise((
|
|
42292
|
+
return new Promise((resolve6, reject) => {
|
|
42293
42293
|
const req = new RequestConstructor(options);
|
|
42294
|
-
const res = new Response2(req,
|
|
42294
|
+
const res = new Response2(req, resolve6, reject);
|
|
42295
42295
|
makeRequest(dispatchFunc, server, req, res);
|
|
42296
42296
|
});
|
|
42297
42297
|
}
|
|
@@ -49470,7 +49470,7 @@ var require_commonjs4 = __commonJS({
|
|
|
49470
49470
|
var EMITTING_END = Symbol("emittingEnd");
|
|
49471
49471
|
var EMITTED_ERROR = Symbol("emittedError");
|
|
49472
49472
|
var CLOSED = Symbol("closed");
|
|
49473
|
-
var
|
|
49473
|
+
var READ2 = Symbol("read");
|
|
49474
49474
|
var FLUSH = Symbol("flush");
|
|
49475
49475
|
var FLUSHCHUNK = Symbol("flushChunk");
|
|
49476
49476
|
var ENCODING = Symbol("encoding");
|
|
@@ -49775,11 +49775,11 @@ var require_commonjs4 = __commonJS({
|
|
|
49775
49775
|
this[ENCODING] ? this[BUFFER].join("") : Buffer.concat(this[BUFFER], this[BUFFERLENGTH])
|
|
49776
49776
|
];
|
|
49777
49777
|
}
|
|
49778
|
-
const ret = this[
|
|
49778
|
+
const ret = this[READ2](n || null, this[BUFFER][0]);
|
|
49779
49779
|
this[MAYBE_EMIT_END]();
|
|
49780
49780
|
return ret;
|
|
49781
49781
|
}
|
|
49782
|
-
[
|
|
49782
|
+
[READ2](n, chunk) {
|
|
49783
49783
|
if (this[OBJECTMODE])
|
|
49784
49784
|
this[BUFFERSHIFT]();
|
|
49785
49785
|
else {
|
|
@@ -50181,10 +50181,10 @@ var require_commonjs4 = __commonJS({
|
|
|
50181
50181
|
* Return a void Promise that resolves once the stream ends.
|
|
50182
50182
|
*/
|
|
50183
50183
|
async promise() {
|
|
50184
|
-
return new Promise((
|
|
50184
|
+
return new Promise((resolve6, reject) => {
|
|
50185
50185
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
50186
50186
|
this.on("error", (er) => reject(er));
|
|
50187
|
-
this.on("end", () =>
|
|
50187
|
+
this.on("end", () => resolve6());
|
|
50188
50188
|
});
|
|
50189
50189
|
}
|
|
50190
50190
|
/**
|
|
@@ -50208,7 +50208,7 @@ var require_commonjs4 = __commonJS({
|
|
|
50208
50208
|
return Promise.resolve({ done: false, value: res });
|
|
50209
50209
|
if (this[EOF])
|
|
50210
50210
|
return stop();
|
|
50211
|
-
let
|
|
50211
|
+
let resolve6;
|
|
50212
50212
|
let reject;
|
|
50213
50213
|
const onerr = (er) => {
|
|
50214
50214
|
this.off("data", ondata);
|
|
@@ -50222,19 +50222,19 @@ var require_commonjs4 = __commonJS({
|
|
|
50222
50222
|
this.off("end", onend);
|
|
50223
50223
|
this.off(DESTROYED, ondestroy);
|
|
50224
50224
|
this.pause();
|
|
50225
|
-
|
|
50225
|
+
resolve6({ value, done: !!this[EOF] });
|
|
50226
50226
|
};
|
|
50227
50227
|
const onend = () => {
|
|
50228
50228
|
this.off("error", onerr);
|
|
50229
50229
|
this.off("data", ondata);
|
|
50230
50230
|
this.off(DESTROYED, ondestroy);
|
|
50231
50231
|
stop();
|
|
50232
|
-
|
|
50232
|
+
resolve6({ done: true, value: void 0 });
|
|
50233
50233
|
};
|
|
50234
50234
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
50235
50235
|
return new Promise((res2, rej) => {
|
|
50236
50236
|
reject = rej;
|
|
50237
|
-
|
|
50237
|
+
resolve6 = res2;
|
|
50238
50238
|
this.once(DESTROYED, ondestroy);
|
|
50239
50239
|
this.once("error", onerr);
|
|
50240
50240
|
this.once("end", onend);
|
|
@@ -51254,9 +51254,9 @@ var require_commonjs5 = __commonJS({
|
|
|
51254
51254
|
if (this.#asyncReaddirInFlight) {
|
|
51255
51255
|
await this.#asyncReaddirInFlight;
|
|
51256
51256
|
} else {
|
|
51257
|
-
let
|
|
51257
|
+
let resolve6 = () => {
|
|
51258
51258
|
};
|
|
51259
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
51259
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve6 = res);
|
|
51260
51260
|
try {
|
|
51261
51261
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
51262
51262
|
withFileTypes: true
|
|
@@ -51269,7 +51269,7 @@ var require_commonjs5 = __commonJS({
|
|
|
51269
51269
|
children.provisional = 0;
|
|
51270
51270
|
}
|
|
51271
51271
|
this.#asyncReaddirInFlight = void 0;
|
|
51272
|
-
|
|
51272
|
+
resolve6();
|
|
51273
51273
|
}
|
|
51274
51274
|
return children.slice(0, children.provisional);
|
|
51275
51275
|
}
|
|
@@ -52356,10 +52356,10 @@ var require_ignore = __commonJS({
|
|
|
52356
52356
|
ignored(p) {
|
|
52357
52357
|
const fullpath = p.fullpath();
|
|
52358
52358
|
const fullpaths = `${fullpath}/`;
|
|
52359
|
-
const
|
|
52360
|
-
const relatives = `${
|
|
52359
|
+
const relative5 = p.relative() || ".";
|
|
52360
|
+
const relatives = `${relative5}/`;
|
|
52361
52361
|
for (const m of this.relative) {
|
|
52362
|
-
if (m.match(
|
|
52362
|
+
if (m.match(relative5) || m.match(relatives))
|
|
52363
52363
|
return true;
|
|
52364
52364
|
}
|
|
52365
52365
|
for (const m of this.absolute) {
|
|
@@ -52370,9 +52370,9 @@ var require_ignore = __commonJS({
|
|
|
52370
52370
|
}
|
|
52371
52371
|
childrenIgnored(p) {
|
|
52372
52372
|
const fullpath = p.fullpath() + "/";
|
|
52373
|
-
const
|
|
52373
|
+
const relative5 = (p.relative() || ".") + "/";
|
|
52374
52374
|
for (const m of this.relativeChildren) {
|
|
52375
|
-
if (m.match(
|
|
52375
|
+
if (m.match(relative5))
|
|
52376
52376
|
return true;
|
|
52377
52377
|
}
|
|
52378
52378
|
for (const m of this.absoluteChildren) {
|
|
@@ -53741,7 +53741,7 @@ var require_parseTokenList = __commonJS({
|
|
|
53741
53741
|
// ../../node_modules/.pnpm/depd@2.0.0/node_modules/depd/index.js
|
|
53742
53742
|
var require_depd = __commonJS({
|
|
53743
53743
|
"../../node_modules/.pnpm/depd@2.0.0/node_modules/depd/index.js"(exports, module) {
|
|
53744
|
-
var
|
|
53744
|
+
var relative5 = __require("path").relative;
|
|
53745
53745
|
module.exports = depd;
|
|
53746
53746
|
var basePath = process.cwd();
|
|
53747
53747
|
function containsNamespace(str, namespace) {
|
|
@@ -53933,7 +53933,7 @@ var require_depd = __commonJS({
|
|
|
53933
53933
|
return formatted;
|
|
53934
53934
|
}
|
|
53935
53935
|
function formatLocation(callSite) {
|
|
53936
|
-
return
|
|
53936
|
+
return relative5(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
|
|
53937
53937
|
}
|
|
53938
53938
|
function getStack() {
|
|
53939
53939
|
var limit = Error.stackTraceLimit;
|
|
@@ -54466,9 +54466,9 @@ var require_send = __commonJS({
|
|
|
54466
54466
|
var { parseTokenList } = require_parseTokenList();
|
|
54467
54467
|
var { createHttpError } = require_createHttpError();
|
|
54468
54468
|
var extname = path.extname;
|
|
54469
|
-
var
|
|
54469
|
+
var join21 = path.join;
|
|
54470
54470
|
var normalize5 = path.normalize;
|
|
54471
|
-
var
|
|
54471
|
+
var resolve6 = path.resolve;
|
|
54472
54472
|
var sep6 = path.sep;
|
|
54473
54473
|
var Readable2 = stream.Readable;
|
|
54474
54474
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
@@ -54515,7 +54515,7 @@ var require_send = __commonJS({
|
|
|
54515
54515
|
const lastModified = options.lastModified !== void 0 ? Boolean(options.lastModified) : true;
|
|
54516
54516
|
const maxage = normalizeMaxAge(options.maxAge ?? options.maxage);
|
|
54517
54517
|
const maxContentRangeChunkSize = options.maxContentRangeChunkSize !== void 0 ? Number(options.maxContentRangeChunkSize) : null;
|
|
54518
|
-
const root = options.root ?
|
|
54518
|
+
const root = options.root ? resolve6(options.root) : null;
|
|
54519
54519
|
const highWaterMark = Number.isSafeInteger(options.highWaterMark) && options.highWaterMark > 0 ? options.highWaterMark : null;
|
|
54520
54520
|
return {
|
|
54521
54521
|
acceptRanges,
|
|
@@ -54553,14 +54553,14 @@ var require_send = __commonJS({
|
|
|
54553
54553
|
return { statusCode: 403 };
|
|
54554
54554
|
}
|
|
54555
54555
|
parts = path2.split(sep6);
|
|
54556
|
-
path2 = normalize5(
|
|
54556
|
+
path2 = normalize5(join21(root, path2));
|
|
54557
54557
|
} else {
|
|
54558
54558
|
if (UP_PATH_REGEXP.test(path2)) {
|
|
54559
54559
|
debug('malicious path "%s"', path2);
|
|
54560
54560
|
return { statusCode: 403 };
|
|
54561
54561
|
}
|
|
54562
54562
|
parts = normalize5(path2).split(sep6);
|
|
54563
|
-
path2 =
|
|
54563
|
+
path2 = resolve6(path2);
|
|
54564
54564
|
}
|
|
54565
54565
|
return { path: path2, parts };
|
|
54566
54566
|
}
|
|
@@ -54656,9 +54656,9 @@ var require_send = __commonJS({
|
|
|
54656
54656
|
);
|
|
54657
54657
|
}
|
|
54658
54658
|
function tryStat(path2) {
|
|
54659
|
-
return new Promise((
|
|
54659
|
+
return new Promise((resolve7) => {
|
|
54660
54660
|
fs2.stat(path2, function onstat(error40, stat3) {
|
|
54661
|
-
|
|
54661
|
+
resolve7({ error: error40, stat: stat3 });
|
|
54662
54662
|
});
|
|
54663
54663
|
});
|
|
54664
54664
|
}
|
|
@@ -54836,7 +54836,7 @@ var require_send = __commonJS({
|
|
|
54836
54836
|
let err;
|
|
54837
54837
|
for (let i = 0; i < options.index.length; i++) {
|
|
54838
54838
|
const index2 = options.index[i];
|
|
54839
|
-
const p =
|
|
54839
|
+
const p = join21(path2, index2);
|
|
54840
54840
|
const { error: error40, stat: stat3 } = await tryStat(p);
|
|
54841
54841
|
if (error40) {
|
|
54842
54842
|
err = error40;
|
|
@@ -60013,6 +60013,9 @@ var acpPermissionOptionKindSchema = external_exports.enum([
|
|
|
60013
60013
|
"reject_once",
|
|
60014
60014
|
"reject_always"
|
|
60015
60015
|
]);
|
|
60016
|
+
var lumemModeSchema = external_exports.enum(["ask", "auto", "free"]);
|
|
60017
|
+
var lumemModeDefaultSchema = external_exports.enum(["ask", "auto"]);
|
|
60018
|
+
var acpModeOwnerSchema = external_exports.enum(["agent", "lumem"]);
|
|
60016
60019
|
var acpPermissionOptionSchema = external_exports.object({
|
|
60017
60020
|
optionId: external_exports.string(),
|
|
60018
60021
|
/** The agent's own label, shown verbatim (A13). */
|
|
@@ -60116,13 +60119,40 @@ var acpEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
60116
60119
|
title: external_exports.string(),
|
|
60117
60120
|
command: external_exports.string().nullish(),
|
|
60118
60121
|
cwd: external_exports.string(),
|
|
60119
|
-
options: external_exports.array(acpPermissionOptionSchema).min(1)
|
|
60122
|
+
options: external_exports.array(acpPermissionOptionSchema).min(1),
|
|
60123
|
+
/**
|
|
60124
|
+
* Why the Lumem policy did not answer this one (`session-mode`, T7).
|
|
60125
|
+
*
|
|
60126
|
+
* Null under `ask`, and under an agent that owns its own modes: there is
|
|
60127
|
+
* nothing to explain when asking *is* the rule. Set when a policy that would
|
|
60128
|
+
* normally answer did not — `auto` facing a write, or an agent that offered
|
|
60129
|
+
* no way to allow (Q6) — because "why am I being asked in auto mode?" is
|
|
60130
|
+
* otherwise a question the screen cannot answer.
|
|
60131
|
+
*/
|
|
60132
|
+
policyReason: external_exports.string().nullable().default(null)
|
|
60120
60133
|
}),
|
|
60121
60134
|
external_exports.object({
|
|
60122
60135
|
type: external_exports.literal("permission_resolved"),
|
|
60123
60136
|
requestId: external_exports.string(),
|
|
60124
60137
|
/** `"cancelled"` is the agent giving up on the ask, not the user denying. */
|
|
60125
|
-
outcome: external_exports.union([external_exports.literal("cancelled"), external_exports.object({ optionId: external_exports.string() })])
|
|
60138
|
+
outcome: external_exports.union([external_exports.literal("cancelled"), external_exports.object({ optionId: external_exports.string() })]),
|
|
60139
|
+
/**
|
|
60140
|
+
* Who signed it (F1.6).
|
|
60141
|
+
*
|
|
60142
|
+
* `default` and not `optional`, for two reasons that point the same way: a
|
|
60143
|
+
* transcript recorded before this feature has no field and must still open,
|
|
60144
|
+
* and `"user"` is the truthful answer for every one of them — nothing but a
|
|
60145
|
+
* person could answer a permission request back then.
|
|
60146
|
+
*/
|
|
60147
|
+
by: external_exports.enum(["user", "lumem"]).default("user"),
|
|
60148
|
+
/**
|
|
60149
|
+
* Why the policy answered, in the words the card shows.
|
|
60150
|
+
*
|
|
60151
|
+
* Only ever set when `by` is `"lumem"`: a person clicking a button is its
|
|
60152
|
+
* own reason, and inventing prose for it would be the daemon narrating the
|
|
60153
|
+
* user's intent.
|
|
60154
|
+
*/
|
|
60155
|
+
reason: external_exports.string().nullable().default(null)
|
|
60126
60156
|
}),
|
|
60127
60157
|
/**
|
|
60128
60158
|
* The plan, whole (F2.5).
|
|
@@ -60167,7 +60197,24 @@ var acpEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
60167
60197
|
* sending this. So the client replaces rather than merging, and there is exactly
|
|
60168
60198
|
* one place that has to get the merge right.
|
|
60169
60199
|
*/
|
|
60170
|
-
options: external_exports.array(acpConfigOptionSchema)
|
|
60200
|
+
options: external_exports.array(acpConfigOptionSchema),
|
|
60201
|
+
/**
|
|
60202
|
+
* Which of the two authorities is in charge right now (A1).
|
|
60203
|
+
*
|
|
60204
|
+
* Defaults to `"agent"` so a transcript recorded before `session-mode` reads
|
|
60205
|
+
* as what it was: a conversation where only the agent could offer a mode.
|
|
60206
|
+
*/
|
|
60207
|
+
modeOwner: acpModeOwnerSchema.default("agent"),
|
|
60208
|
+
/**
|
|
60209
|
+
* The policy value, whoever owns the selector.
|
|
60210
|
+
*
|
|
60211
|
+
* Sent even while the agent owns the mode, and that is on purpose: the value
|
|
60212
|
+
* is *kept*, not erased, so an agent that stops reporting modes hands the
|
|
60213
|
+
* conversation back to the policy it already had (T12).
|
|
60214
|
+
*/
|
|
60215
|
+
lumemMode: lumemModeSchema.default("ask"),
|
|
60216
|
+
/** What a new session in this workspace would start at — the menu's footer (Q5). */
|
|
60217
|
+
lumemModeDefault: lumemModeDefaultSchema.default("ask")
|
|
60171
60218
|
}),
|
|
60172
60219
|
/** What `/` offers (F2.8). An empty list means the agent offers none. */
|
|
60173
60220
|
external_exports.object({ type: external_exports.literal("commands"), commands: external_exports.array(acpCommandSchema) }),
|
|
@@ -60265,7 +60312,17 @@ var acpClientMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
60265
60312
|
type: external_exports.literal("set_config"),
|
|
60266
60313
|
optionId: external_exports.string().min(1),
|
|
60267
60314
|
value: external_exports.string().min(1)
|
|
60268
|
-
})
|
|
60315
|
+
}),
|
|
60316
|
+
/**
|
|
60317
|
+
* Switch the policy Lumem applies when the agent offers no modes (F1.1).
|
|
60318
|
+
*
|
|
60319
|
+
* A message of its own rather than a `set_config` with `optionId: "mode"`,
|
|
60320
|
+
* because it is not the same act: `set_config` forwards a value to the agent
|
|
60321
|
+
* and this one never leaves the daemon. Sharing the message would put two
|
|
60322
|
+
* destinations behind one name, and the first bug would be a policy change
|
|
60323
|
+
* quietly forwarded to an agent that does not have the option.
|
|
60324
|
+
*/
|
|
60325
|
+
external_exports.object({ type: external_exports.literal("set_lumem_mode"), mode: lumemModeSchema })
|
|
60269
60326
|
]);
|
|
60270
60327
|
var acpServerMessageSchema = external_exports.discriminatedUnion("type", [
|
|
60271
60328
|
/**
|
|
@@ -60288,6 +60345,23 @@ var acpServerMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
60288
60345
|
* broken for as long as nothing changed.
|
|
60289
60346
|
*/
|
|
60290
60347
|
configOptions: external_exports.array(acpConfigOptionSchema).default([]),
|
|
60348
|
+
/**
|
|
60349
|
+
* The mode state, on attach, for the same reason `configOptions` is here: a
|
|
60350
|
+
* composer whose mode pill appeared only once something changed would look
|
|
60351
|
+
* broken for as long as nothing did.
|
|
60352
|
+
*/
|
|
60353
|
+
modeOwner: acpModeOwnerSchema.default("agent"),
|
|
60354
|
+
lumemMode: lumemModeSchema.default("ask"),
|
|
60355
|
+
lumemModeDefault: lumemModeDefaultSchema.default("ask"),
|
|
60356
|
+
/**
|
|
60357
|
+
* The checkout this conversation runs in.
|
|
60358
|
+
*
|
|
60359
|
+
* Here because the `free` gate has to name what it is opening, and it names
|
|
60360
|
+
* it as a **path on disk** rather than as "the worktree": the path is what
|
|
60361
|
+
* says the size of the damage (Q4). A gate that could not say it would be
|
|
60362
|
+
* asking for a decision without stating its scope.
|
|
60363
|
+
*/
|
|
60364
|
+
cwd: external_exports.string().default(""),
|
|
60291
60365
|
transcript: external_exports.array(acpTranscriptEntrySchema)
|
|
60292
60366
|
}),
|
|
60293
60367
|
external_exports.object({
|
|
@@ -60331,7 +60405,7 @@ function encodeAcpServerMessage(message) {
|
|
|
60331
60405
|
}
|
|
60332
60406
|
|
|
60333
60407
|
// ../shared/src/constants.ts
|
|
60334
|
-
var LUMEM_VERSION = "0.
|
|
60408
|
+
var LUMEM_VERSION = "0.2.0";
|
|
60335
60409
|
var DEFAULT_SERVER_PORT = 4317;
|
|
60336
60410
|
var ACP_ADAPTER_COMMAND = "claude-agent-acp";
|
|
60337
60411
|
var ACP_ADAPTER_PACKAGE = "@agentclientprotocol/claude-agent-acp";
|
|
@@ -60794,6 +60868,32 @@ function createGitService({ exec = execGit } = {}) {
|
|
|
60794
60868
|
const [behind, ahead] = stdout.trim().split(/\s+/).map(Number);
|
|
60795
60869
|
return { ahead: ahead ?? 0, behind: behind ?? 0 };
|
|
60796
60870
|
},
|
|
60871
|
+
async getRemoteUrl(path) {
|
|
60872
|
+
const { stdout } = await exec(["remote", "get-url", "origin"], { cwd: path }).catch(() => ({
|
|
60873
|
+
stdout: "",
|
|
60874
|
+
stderr: ""
|
|
60875
|
+
}));
|
|
60876
|
+
const url2 = stdout.trim();
|
|
60877
|
+
return url2 === "" ? null : url2;
|
|
60878
|
+
},
|
|
60879
|
+
async getSubject(path) {
|
|
60880
|
+
const { stdout } = await exec(["log", "-1", "--format=%s"], { cwd: path }).catch(() => ({
|
|
60881
|
+
stdout: "",
|
|
60882
|
+
stderr: ""
|
|
60883
|
+
}));
|
|
60884
|
+
const subject = stdout.trim();
|
|
60885
|
+
return subject === "" ? null : subject;
|
|
60886
|
+
},
|
|
60887
|
+
async hasRemoteBranch(path, branch) {
|
|
60888
|
+
const { stdout } = await exec(["for-each-ref", "--format=%(refname)", "refs/remotes/"], {
|
|
60889
|
+
cwd: path
|
|
60890
|
+
}).catch(() => ({ stdout: "", stderr: "" }));
|
|
60891
|
+
return stdout.split("\n").map((line) => line.trim()).filter((line) => line !== "").some((ref) => {
|
|
60892
|
+
const rest = ref.slice("refs/remotes/".length);
|
|
60893
|
+
const slash = rest.indexOf("/");
|
|
60894
|
+
return slash !== -1 && rest.slice(slash + 1) === branch;
|
|
60895
|
+
});
|
|
60896
|
+
},
|
|
60797
60897
|
async listChanges(path, input) {
|
|
60798
60898
|
const comparedTo = await resolveComparison(path, input);
|
|
60799
60899
|
const tracked2 = comparedTo === null ? [] : await trackedChanges(path, comparedTo);
|
|
@@ -62026,7 +62126,7 @@ function sql(strings, ...params) {
|
|
|
62026
62126
|
return new SQL([new StringChunk(str)]);
|
|
62027
62127
|
}
|
|
62028
62128
|
sql2.raw = raw;
|
|
62029
|
-
function
|
|
62129
|
+
function join21(chunks, separator) {
|
|
62030
62130
|
const result = [];
|
|
62031
62131
|
for (const [i, chunk] of chunks.entries()) {
|
|
62032
62132
|
if (i > 0 && separator !== void 0) {
|
|
@@ -62036,7 +62136,7 @@ function sql(strings, ...params) {
|
|
|
62036
62136
|
}
|
|
62037
62137
|
return new SQL(result);
|
|
62038
62138
|
}
|
|
62039
|
-
sql2.join =
|
|
62139
|
+
sql2.join = join21;
|
|
62040
62140
|
function identifier(value) {
|
|
62041
62141
|
return new Name(value);
|
|
62042
62142
|
}
|
|
@@ -64603,7 +64703,7 @@ var SQLiteSelectQueryBuilderBase = class extends TypedQueryBuilder {
|
|
|
64603
64703
|
const baseTableName = this.tableName;
|
|
64604
64704
|
const tableName = getTableLikeName(table);
|
|
64605
64705
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
64606
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
64706
|
+
if (typeof tableName === "string" && this.config.joins?.some((join21) => join21.alias === tableName)) {
|
|
64607
64707
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
64608
64708
|
}
|
|
64609
64709
|
if (!this.isPartialSelect) {
|
|
@@ -65462,7 +65562,7 @@ var SQLiteUpdateBase = class extends QueryPromise {
|
|
|
65462
65562
|
createJoin(joinType) {
|
|
65463
65563
|
return (table, on2) => {
|
|
65464
65564
|
const tableName = getTableLikeName(table);
|
|
65465
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
65565
|
+
if (typeof tableName === "string" && this.config.joins.some((join21) => join21.alias === tableName)) {
|
|
65466
65566
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
65467
65567
|
}
|
|
65468
65568
|
if (typeof on2 === "function") {
|
|
@@ -66328,11 +66428,26 @@ var timestamps = {
|
|
|
66328
66428
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(NOW),
|
|
66329
66429
|
updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull().default(NOW)
|
|
66330
66430
|
};
|
|
66331
|
-
var workspace = sqliteTable(
|
|
66332
|
-
|
|
66333
|
-
|
|
66334
|
-
|
|
66335
|
-
|
|
66431
|
+
var workspace = sqliteTable(
|
|
66432
|
+
"workspace",
|
|
66433
|
+
{
|
|
66434
|
+
id: text("id").primaryKey(),
|
|
66435
|
+
name: text("name").notNull().unique(),
|
|
66436
|
+
/**
|
|
66437
|
+
* O modo do Lumem que uma sessão nova deste workspace herda (`session-mode`, Q5).
|
|
66438
|
+
*
|
|
66439
|
+
* Sem `'free'` no CHECK, e isso é a decisão inteira em uma linha: o portão do
|
|
66440
|
+
* `liberado` é **por sessão**, e um padrão que o atravessasse sozinho o
|
|
66441
|
+
* anularia. Recusar na ESCRITA, e não silenciar na leitura — silenciar é o
|
|
66442
|
+
* modo de falha que ninguém percebe.
|
|
66443
|
+
*/
|
|
66444
|
+
defaultLumemMode: text("default_lumem_mode").notNull().default("ask"),
|
|
66445
|
+
...timestamps
|
|
66446
|
+
},
|
|
66447
|
+
(table) => [
|
|
66448
|
+
check("workspace_default_lumem_mode", sql`${table.defaultLumemMode} IN ('ask', 'auto')`)
|
|
66449
|
+
]
|
|
66450
|
+
);
|
|
66336
66451
|
var project = sqliteTable(
|
|
66337
66452
|
"project",
|
|
66338
66453
|
{
|
|
@@ -66479,6 +66594,18 @@ var session = sqliteTable(
|
|
|
66479
66594
|
/** Current permission mode and model, as the protocol reports them. */
|
|
66480
66595
|
mode: text("mode"),
|
|
66481
66596
|
model: text("model"),
|
|
66597
|
+
/**
|
|
66598
|
+
* A política do Lumem desta conversa (`session-mode`, F1.4).
|
|
66599
|
+
*
|
|
66600
|
+
* Coluna própria, e **não** reaproveitamento do `mode` acima: aquele é o modo
|
|
66601
|
+
* do protocolo, relatado pelo agente, e este é o que o daemon responde a um
|
|
66602
|
+
* pedido de permissão. Guardar os dois no mesmo lugar seria perder a única
|
|
66603
|
+
* informação que separa "o agente tentou" de "o Lumem deixou passar".
|
|
66604
|
+
*
|
|
66605
|
+
* `NOT NULL DEFAULT 'ask'` faz toda sessão gravada antes desta feature
|
|
66606
|
+
* acordar perguntando — nenhuma acorda liberada.
|
|
66607
|
+
*/
|
|
66608
|
+
lumemMode: text("lumem_mode").notNull().default("ask"),
|
|
66482
66609
|
/**
|
|
66483
66610
|
* The session this one continues (F5.2, D12).
|
|
66484
66611
|
*
|
|
@@ -66539,7 +66666,10 @@ var session = sqliteTable(
|
|
|
66539
66666
|
"session_acp_id",
|
|
66540
66667
|
sql`(${table.transport} = 'acp' AND ${table.acpSessionId} IS NOT NULL)
|
|
66541
66668
|
OR (${table.transport} = 'pty' AND ${table.acpSessionId} IS NULL)`
|
|
66542
|
-
)
|
|
66669
|
+
),
|
|
66670
|
+
// Os três valores da política, e o `free` entra aqui — o que o workspace não
|
|
66671
|
+
// pode é *herdar* liberado; uma sessão pode chegar lá pelo portão.
|
|
66672
|
+
check("session_lumem_mode", sql`${table.lumemMode} IN ('ask', 'auto', 'free')`)
|
|
66543
66673
|
]
|
|
66544
66674
|
);
|
|
66545
66675
|
var checkoutPort = sqliteTable(
|
|
@@ -67063,11 +67193,9 @@ function createProjectRepository(db) {
|
|
|
67063
67193
|
},
|
|
67064
67194
|
async remove(id) {
|
|
67065
67195
|
await require_(id);
|
|
67066
|
-
|
|
67067
|
-
|
|
67068
|
-
|
|
67069
|
-
message: "o projeto ainda tem worktrees registradas; remova-as antes"
|
|
67070
|
-
}
|
|
67196
|
+
db.transaction((tx) => {
|
|
67197
|
+
tx.delete(worktree).where(eq(worktree.projectId, id)).run();
|
|
67198
|
+
tx.delete(project).where(eq(project.id, id)).run();
|
|
67071
67199
|
});
|
|
67072
67200
|
}
|
|
67073
67201
|
};
|
|
@@ -67131,6 +67259,10 @@ function createSessionRepository(db) {
|
|
|
67131
67259
|
await db.update(session).set({
|
|
67132
67260
|
...config2.mode === void 0 ? {} : { mode: config2.mode },
|
|
67133
67261
|
...config2.model === void 0 ? {} : { model: config2.model },
|
|
67262
|
+
// A política do Lumem entra pelo mesmo caminho do modo do protocolo,
|
|
67263
|
+
// e em coluna diferente: uma é o que o agente relatou, a outra é o que
|
|
67264
|
+
// o daemon responde. Guardar as duas juntas apagaria a diferença.
|
|
67265
|
+
...config2.lumemMode === void 0 ? {} : { lumemMode: config2.lumemMode },
|
|
67134
67266
|
updatedAt: /* @__PURE__ */ new Date()
|
|
67135
67267
|
}).where(and(eq(session.id, id), eq(session.state, "running")));
|
|
67136
67268
|
},
|
|
@@ -81018,11 +81150,11 @@ var Connection = class {
|
|
|
81018
81150
|
const id = this.nextRequestId++;
|
|
81019
81151
|
let cancel = () => {
|
|
81020
81152
|
};
|
|
81021
|
-
const response = new Promise((
|
|
81153
|
+
const response = new Promise((resolve6, reject) => {
|
|
81022
81154
|
const pendingResponse = {
|
|
81023
81155
|
resolve: (value) => {
|
|
81024
81156
|
try {
|
|
81025
|
-
|
|
81157
|
+
resolve6(mapResponse ? mapResponse(value) : value);
|
|
81026
81158
|
} catch (error40) {
|
|
81027
81159
|
reject(error40);
|
|
81028
81160
|
}
|
|
@@ -81079,8 +81211,8 @@ var Connection = class {
|
|
|
81079
81211
|
this.stream = stream;
|
|
81080
81212
|
this.staticHandlers = handlers2;
|
|
81081
81213
|
this.allowBatches = options?.allowBatches ?? true;
|
|
81082
|
-
this.closedPromise = new Promise((
|
|
81083
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
81214
|
+
this.closedPromise = new Promise((resolve6) => {
|
|
81215
|
+
this.abortController.signal.addEventListener("abort", () => resolve6());
|
|
81084
81216
|
});
|
|
81085
81217
|
void this.receive();
|
|
81086
81218
|
}
|
|
@@ -81961,8 +82093,8 @@ var AsyncQueue = class {
|
|
|
81961
82093
|
if (this.failed) {
|
|
81962
82094
|
return Promise.reject(this.failure);
|
|
81963
82095
|
}
|
|
81964
|
-
return new Promise((
|
|
81965
|
-
this.waiters.push({ resolve:
|
|
82096
|
+
return new Promise((resolve6, reject) => {
|
|
82097
|
+
this.waiters.push({ resolve: resolve6, reject });
|
|
81966
82098
|
});
|
|
81967
82099
|
}
|
|
81968
82100
|
};
|
|
@@ -82654,27 +82786,27 @@ function touchesGit(candidate) {
|
|
|
82654
82786
|
return candidate.split(sep2).includes(GIT_DIR);
|
|
82655
82787
|
}
|
|
82656
82788
|
async function resolveInsideRoot(root, requested) {
|
|
82657
|
-
const
|
|
82789
|
+
const relative5 = normalizeRelative(requested);
|
|
82658
82790
|
const realRoot = await realRootOf(root);
|
|
82659
|
-
const target = join6(realRoot,
|
|
82791
|
+
const target = join6(realRoot, relative5);
|
|
82660
82792
|
let absolute;
|
|
82661
82793
|
try {
|
|
82662
82794
|
absolute = await realpath3(target);
|
|
82663
82795
|
} catch (error40) {
|
|
82664
82796
|
const code = error40.code;
|
|
82665
82797
|
if (code === "EACCES" || code === "EPERM") {
|
|
82666
|
-
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${
|
|
82798
|
+
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${relative5 || "."}`);
|
|
82667
82799
|
}
|
|
82668
|
-
throw new DomainError("NOT_FOUND", `${
|
|
82800
|
+
throw new DomainError("NOT_FOUND", `${relative5 || "."} n\xE3o existe no checkout`);
|
|
82669
82801
|
}
|
|
82670
82802
|
if (!inside(realRoot, absolute)) {
|
|
82671
82803
|
throw new DomainError(
|
|
82672
82804
|
"BLOCKED",
|
|
82673
|
-
target === absolute ? `${
|
|
82805
|
+
target === absolute ? `${relative5} est\xE1 fora do checkout` : `${relative5} aponta para fora do checkout`
|
|
82674
82806
|
);
|
|
82675
82807
|
}
|
|
82676
|
-
const insideGit = touchesGit(
|
|
82677
|
-
return { absolute, relative:
|
|
82808
|
+
const insideGit = touchesGit(relative5) || touchesGit(relativeTo(realRoot, absolute));
|
|
82809
|
+
return { absolute, relative: relative5, insideGit };
|
|
82678
82810
|
}
|
|
82679
82811
|
function refuseWritingIntoGit(shown, candidate) {
|
|
82680
82812
|
if (!touchesGit(candidate)) return;
|
|
@@ -82690,13 +82822,13 @@ async function diskNameOf(parent, requested) {
|
|
|
82690
82822
|
return names.find((name) => name.toLowerCase() === folded) ?? requested;
|
|
82691
82823
|
}
|
|
82692
82824
|
async function resolveForWrite(root, requested) {
|
|
82693
|
-
const
|
|
82694
|
-
if (
|
|
82825
|
+
const relative5 = normalizeRelative(requested);
|
|
82826
|
+
if (relative5 === "") {
|
|
82695
82827
|
throw new DomainError("INVALID_ARGUMENT", "a raiz do checkout n\xE3o aceita escrita");
|
|
82696
82828
|
}
|
|
82697
|
-
refuseWritingIntoGit(
|
|
82829
|
+
refuseWritingIntoGit(relative5, relative5);
|
|
82698
82830
|
const realRoot = await realRootOf(root);
|
|
82699
|
-
const parentRelative = dirname4(
|
|
82831
|
+
const parentRelative = dirname4(relative5) === "." ? "" : dirname4(relative5);
|
|
82700
82832
|
const literalParent = join6(realRoot, parentRelative);
|
|
82701
82833
|
let parent;
|
|
82702
82834
|
try {
|
|
@@ -82717,7 +82849,7 @@ async function resolveForWrite(root, requested) {
|
|
|
82717
82849
|
literalParent === parent ? `${parentRelative} est\xE1 fora do checkout` : `${parentRelative} aponta para fora do checkout`
|
|
82718
82850
|
);
|
|
82719
82851
|
}
|
|
82720
|
-
const literalTarget = join6(parent, basename(
|
|
82852
|
+
const literalTarget = join6(parent, basename(relative5));
|
|
82721
82853
|
let entry = literalTarget;
|
|
82722
82854
|
let target = literalTarget;
|
|
82723
82855
|
let targetless = null;
|
|
@@ -82728,7 +82860,7 @@ async function resolveForWrite(root, requested) {
|
|
|
82728
82860
|
entry = await realpath3(literalTarget);
|
|
82729
82861
|
target = entry;
|
|
82730
82862
|
} else {
|
|
82731
|
-
entry = join6(parent, await diskNameOf(parent, basename(
|
|
82863
|
+
entry = join6(parent, await diskNameOf(parent, basename(relative5)));
|
|
82732
82864
|
const destination = await realpath3(literalTarget).catch(() => null);
|
|
82733
82865
|
if (destination === null) {
|
|
82734
82866
|
target = null;
|
|
@@ -82747,16 +82879,16 @@ async function resolveForWrite(root, requested) {
|
|
|
82747
82879
|
throw new DomainError("INVALID_ARGUMENT", `${parentRelative || "."} n\xE3o \xE9 um diret\xF3rio`);
|
|
82748
82880
|
}
|
|
82749
82881
|
if (code !== "ENOENT") {
|
|
82750
|
-
throw new DomainError("BLOCKED", `sem acesso a ${
|
|
82882
|
+
throw new DomainError("BLOCKED", `sem acesso a ${relative5}`);
|
|
82751
82883
|
}
|
|
82752
82884
|
exists2 = false;
|
|
82753
82885
|
}
|
|
82754
|
-
refuseWritingIntoGit(
|
|
82755
|
-
if (target !== null) refuseWritingIntoGit(
|
|
82886
|
+
refuseWritingIntoGit(relative5, relativeTo(realRoot, entry));
|
|
82887
|
+
if (target !== null) refuseWritingIntoGit(relative5, relativeTo(realRoot, target));
|
|
82756
82888
|
if (target === realRoot) {
|
|
82757
82889
|
throw new DomainError("INVALID_ARGUMENT", "a raiz do checkout n\xE3o aceita escrita");
|
|
82758
82890
|
}
|
|
82759
|
-
return { relative:
|
|
82891
|
+
return { relative: relative5, entry, target, targetless, exists: exists2 };
|
|
82760
82892
|
}
|
|
82761
82893
|
|
|
82762
82894
|
// src/files/FileService.ts
|
|
@@ -82808,11 +82940,11 @@ async function writeAtomically(target, content, mode) {
|
|
|
82808
82940
|
throw error40;
|
|
82809
82941
|
}
|
|
82810
82942
|
}
|
|
82811
|
-
function asCreationFailure(error40,
|
|
82943
|
+
function asCreationFailure(error40, relative5) {
|
|
82812
82944
|
const code = error40.code;
|
|
82813
|
-
const parent = dirname5(
|
|
82945
|
+
const parent = dirname5(relative5) === "." ? "." : dirname5(relative5);
|
|
82814
82946
|
if (code === "EEXIST") {
|
|
82815
|
-
return new DomainError("DUPLICATE", `j\xE1 existe alguma coisa em ${
|
|
82947
|
+
return new DomainError("DUPLICATE", `j\xE1 existe alguma coisa em ${relative5}`);
|
|
82816
82948
|
}
|
|
82817
82949
|
if (code === "ENOENT") {
|
|
82818
82950
|
return new DomainError("NOT_FOUND", `o diret\xF3rio ${parent} n\xE3o existe no checkout`);
|
|
@@ -82847,16 +82979,16 @@ function asRenameFailure(error40, from, to) {
|
|
|
82847
82979
|
}
|
|
82848
82980
|
return error40;
|
|
82849
82981
|
}
|
|
82850
|
-
function asRemovalFailure(error40,
|
|
82982
|
+
function asRemovalFailure(error40, relative5) {
|
|
82851
82983
|
const code = error40.code;
|
|
82852
82984
|
if (code === "ENOENT") {
|
|
82853
|
-
return new DomainError("NOT_FOUND", `${
|
|
82985
|
+
return new DomainError("NOT_FOUND", `${relative5} n\xE3o est\xE1 mais no checkout`);
|
|
82854
82986
|
}
|
|
82855
82987
|
if (code === "ENOTEMPTY") {
|
|
82856
|
-
return new DomainError("BLOCKED", `${
|
|
82988
|
+
return new DomainError("BLOCKED", `${relative5} deixou de estar vazia`);
|
|
82857
82989
|
}
|
|
82858
82990
|
if (code === "EACCES" || code === "EPERM") {
|
|
82859
|
-
return new DomainError("BLOCKED", `sem permiss\xE3o para apagar ${
|
|
82991
|
+
return new DomainError("BLOCKED", `sem permiss\xE3o para apagar ${relative5}`);
|
|
82860
82992
|
}
|
|
82861
82993
|
return error40;
|
|
82862
82994
|
}
|
|
@@ -82922,10 +83054,10 @@ function createFileService({
|
|
|
82922
83054
|
} = {}) {
|
|
82923
83055
|
return {
|
|
82924
83056
|
async listDir(root, path, options = {}) {
|
|
82925
|
-
const { absolute, relative:
|
|
83057
|
+
const { absolute, relative: relative5 } = await resolveInsideRoot(root, path);
|
|
82926
83058
|
const info = await stat2(absolute);
|
|
82927
83059
|
if (!info.isDirectory()) {
|
|
82928
|
-
throw new DomainError("INVALID_ARGUMENT", `${
|
|
83060
|
+
throw new DomainError("INVALID_ARGUMENT", `${relative5} n\xE3o \xE9 um diret\xF3rio`);
|
|
82929
83061
|
}
|
|
82930
83062
|
let dirents;
|
|
82931
83063
|
try {
|
|
@@ -82933,7 +83065,7 @@ function createFileService({
|
|
|
82933
83065
|
} catch (error40) {
|
|
82934
83066
|
const code = error40.code;
|
|
82935
83067
|
if (code === "EACCES" || code === "EPERM") {
|
|
82936
|
-
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${
|
|
83068
|
+
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${relative5 || "."}`);
|
|
82937
83069
|
}
|
|
82938
83070
|
throw error40;
|
|
82939
83071
|
}
|
|
@@ -82957,16 +83089,16 @@ function createFileService({
|
|
|
82957
83089
|
})
|
|
82958
83090
|
);
|
|
82959
83091
|
entries.sort(compareEntries);
|
|
82960
|
-
return { path:
|
|
83092
|
+
return { path: relative5, entries, total, truncated: total > kept.length };
|
|
82961
83093
|
},
|
|
82962
83094
|
async readFile(root, path) {
|
|
82963
|
-
const { absolute, relative:
|
|
83095
|
+
const { absolute, relative: relative5, insideGit } = await resolveInsideRoot(root, path);
|
|
82964
83096
|
const info = await stat2(absolute);
|
|
82965
83097
|
if (info.isDirectory()) {
|
|
82966
|
-
throw new DomainError("INVALID_ARGUMENT", `${
|
|
83098
|
+
throw new DomainError("INVALID_ARGUMENT", `${relative5} \xE9 um diret\xF3rio`);
|
|
82967
83099
|
}
|
|
82968
83100
|
if (info.size > maxBytes) {
|
|
82969
|
-
return { kind: "too-large", path:
|
|
83101
|
+
return { kind: "too-large", path: relative5, bytes: info.size, limit: maxBytes };
|
|
82970
83102
|
}
|
|
82971
83103
|
let buffer;
|
|
82972
83104
|
try {
|
|
@@ -82974,16 +83106,16 @@ function createFileService({
|
|
|
82974
83106
|
} catch (error40) {
|
|
82975
83107
|
const code = error40.code;
|
|
82976
83108
|
if (code === "EACCES" || code === "EPERM") {
|
|
82977
|
-
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${
|
|
83109
|
+
throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${relative5}`);
|
|
82978
83110
|
}
|
|
82979
83111
|
throw error40;
|
|
82980
83112
|
}
|
|
82981
|
-
if (isBinary(buffer)) return { kind: "binary", path:
|
|
83113
|
+
if (isBinary(buffer)) return { kind: "binary", path: relative5, bytes: buffer.length };
|
|
82982
83114
|
const text2 = buffer.toString("utf8");
|
|
82983
83115
|
const readOnly = await readOnlyReasonFor(absolute, buffer, text2, insideGit);
|
|
82984
83116
|
return {
|
|
82985
83117
|
kind: "text",
|
|
82986
|
-
path:
|
|
83118
|
+
path: relative5,
|
|
82987
83119
|
bytes: buffer.length,
|
|
82988
83120
|
lines: countLines(text2),
|
|
82989
83121
|
text: text2,
|
|
@@ -82992,15 +83124,15 @@ function createFileService({
|
|
|
82992
83124
|
};
|
|
82993
83125
|
},
|
|
82994
83126
|
async writeFile(root, path, { text: text2, baseRevision }) {
|
|
82995
|
-
const { relative:
|
|
83127
|
+
const { relative: relative5, target, targetless, exists: exists2 } = await resolveForWrite(root, path);
|
|
82996
83128
|
if (target === null) {
|
|
82997
83129
|
throw new DomainError(
|
|
82998
83130
|
"BLOCKED",
|
|
82999
|
-
targetless === "outside" ? `escrita recusada em ${
|
|
83131
|
+
targetless === "outside" ? `escrita recusada em ${relative5}: o link aponta para fora do checkout` : `escrita recusada em ${relative5}: o link est\xE1 pendurado, e nada prova onde a grava\xE7\xE3o cairia`
|
|
83000
83132
|
);
|
|
83001
83133
|
}
|
|
83002
83134
|
if (!exists2) {
|
|
83003
|
-
throw new DomainError("NOT_FOUND", `${
|
|
83135
|
+
throw new DomainError("NOT_FOUND", `${relative5} n\xE3o existe no checkout`);
|
|
83004
83136
|
}
|
|
83005
83137
|
const buffer = Buffer.from(text2, "utf8");
|
|
83006
83138
|
if (buffer.length > maxBytes) {
|
|
@@ -83012,22 +83144,22 @@ function createFileService({
|
|
|
83012
83144
|
const info = await stat2(target).catch((error40) => {
|
|
83013
83145
|
throw new DomainError(
|
|
83014
83146
|
error40.code === "EACCES" || error40.code === "EPERM" ? "BLOCKED" : "NOT_FOUND",
|
|
83015
|
-
`${
|
|
83147
|
+
`${relative5} n\xE3o est\xE1 mais no checkout`
|
|
83016
83148
|
);
|
|
83017
83149
|
});
|
|
83018
83150
|
if (info.isDirectory()) {
|
|
83019
|
-
throw new DomainError("INVALID_ARGUMENT", `${
|
|
83151
|
+
throw new DomainError("INVALID_ARGUMENT", `${relative5} \xE9 um diret\xF3rio`);
|
|
83020
83152
|
}
|
|
83021
83153
|
if (info.size > maxBytes) {
|
|
83022
83154
|
throw new DomainError(
|
|
83023
83155
|
"BLOCKED",
|
|
83024
|
-
`${
|
|
83156
|
+
`${relative5} tem ${info.size} bytes no disco, acima do limite de ${maxBytes}`
|
|
83025
83157
|
);
|
|
83026
83158
|
}
|
|
83027
83159
|
if (!await isWritable(target)) {
|
|
83028
83160
|
throw new DomainError(
|
|
83029
83161
|
"BLOCKED",
|
|
83030
|
-
`escrita recusada em ${
|
|
83162
|
+
`escrita recusada em ${relative5}: o arquivo \xE9 somente leitura no disco`
|
|
83031
83163
|
);
|
|
83032
83164
|
}
|
|
83033
83165
|
let current;
|
|
@@ -83036,14 +83168,14 @@ function createFileService({
|
|
|
83036
83168
|
} catch (error40) {
|
|
83037
83169
|
const code = error40.code;
|
|
83038
83170
|
if (code === "EACCES" || code === "EPERM") {
|
|
83039
|
-
throw new DomainError("BLOCKED", `sem permiss\xE3o de escrita em ${
|
|
83171
|
+
throw new DomainError("BLOCKED", `sem permiss\xE3o de escrita em ${relative5}`);
|
|
83040
83172
|
}
|
|
83041
83173
|
throw error40;
|
|
83042
83174
|
}
|
|
83043
83175
|
if (!survivesUtf8(current, current.toString("utf8"))) {
|
|
83044
83176
|
throw new DomainError(
|
|
83045
83177
|
"BLOCKED",
|
|
83046
|
-
`escrita recusada em ${
|
|
83178
|
+
`escrita recusada em ${relative5}: o conte\xFAdo no disco n\xE3o sobrevive a uma ida e volta em UTF-8, e gravar destruiria bytes`
|
|
83047
83179
|
);
|
|
83048
83180
|
}
|
|
83049
83181
|
const revision = revisionOf(current);
|
|
@@ -83055,29 +83187,29 @@ function createFileService({
|
|
|
83055
83187
|
} catch (error40) {
|
|
83056
83188
|
const code = error40.code;
|
|
83057
83189
|
if (code === "EACCES" || code === "EPERM") {
|
|
83058
|
-
throw new DomainError("BLOCKED", `sem permiss\xE3o de escrita em ${
|
|
83190
|
+
throw new DomainError("BLOCKED", `sem permiss\xE3o de escrita em ${relative5}`);
|
|
83059
83191
|
}
|
|
83060
83192
|
throw error40;
|
|
83061
83193
|
}
|
|
83062
83194
|
return { ok: true, revision: revisionOf(buffer) };
|
|
83063
83195
|
},
|
|
83064
83196
|
async createFile(root, path) {
|
|
83065
|
-
const { relative:
|
|
83197
|
+
const { relative: relative5, entry } = await resolveForWrite(root, path);
|
|
83066
83198
|
try {
|
|
83067
83199
|
await writeFile(entry, "", { flag: "wx" });
|
|
83068
83200
|
} catch (error40) {
|
|
83069
|
-
throw asCreationFailure(error40,
|
|
83201
|
+
throw asCreationFailure(error40, relative5);
|
|
83070
83202
|
}
|
|
83071
|
-
return { path:
|
|
83203
|
+
return { path: relative5 };
|
|
83072
83204
|
},
|
|
83073
83205
|
async createDir(root, path) {
|
|
83074
|
-
const { relative:
|
|
83206
|
+
const { relative: relative5, entry } = await resolveForWrite(root, path);
|
|
83075
83207
|
try {
|
|
83076
83208
|
await mkdir3(entry);
|
|
83077
83209
|
} catch (error40) {
|
|
83078
|
-
throw asCreationFailure(error40,
|
|
83210
|
+
throw asCreationFailure(error40, relative5);
|
|
83079
83211
|
}
|
|
83080
|
-
return { path:
|
|
83212
|
+
return { path: relative5 };
|
|
83081
83213
|
},
|
|
83082
83214
|
async rename(root, from, to) {
|
|
83083
83215
|
const source = await resolveForWrite(root, from);
|
|
@@ -83102,50 +83234,50 @@ function createFileService({
|
|
|
83102
83234
|
return { path: destination.relative };
|
|
83103
83235
|
},
|
|
83104
83236
|
async remove(root, path, { recursive = false } = {}) {
|
|
83105
|
-
const { relative:
|
|
83237
|
+
const { relative: relative5, entry, exists: exists2 } = await resolveForWrite(root, path);
|
|
83106
83238
|
if (!exists2) {
|
|
83107
|
-
throw new DomainError("NOT_FOUND", `${
|
|
83239
|
+
throw new DomainError("NOT_FOUND", `${relative5} n\xE3o existe no checkout`);
|
|
83108
83240
|
}
|
|
83109
83241
|
const info = await lstat3(entry).catch((error40) => {
|
|
83110
|
-
throw asRemovalFailure(error40,
|
|
83242
|
+
throw asRemovalFailure(error40, relative5);
|
|
83111
83243
|
});
|
|
83112
83244
|
if (!info.isDirectory()) {
|
|
83113
83245
|
await unlink(entry).catch((error40) => {
|
|
83114
|
-
throw asRemovalFailure(error40,
|
|
83246
|
+
throw asRemovalFailure(error40, relative5);
|
|
83115
83247
|
});
|
|
83116
83248
|
return;
|
|
83117
83249
|
}
|
|
83118
83250
|
if (recursive) {
|
|
83119
83251
|
await rm2(entry, { recursive: true }).catch((error40) => {
|
|
83120
|
-
throw asRemovalFailure(error40,
|
|
83252
|
+
throw asRemovalFailure(error40, relative5);
|
|
83121
83253
|
});
|
|
83122
83254
|
return;
|
|
83123
83255
|
}
|
|
83124
|
-
const
|
|
83125
|
-
throw asRemovalFailure(error40,
|
|
83256
|
+
const inside3 = await readdir4(entry).catch((error40) => {
|
|
83257
|
+
throw asRemovalFailure(error40, relative5);
|
|
83126
83258
|
});
|
|
83127
|
-
if (
|
|
83259
|
+
if (inside3.length > 0) {
|
|
83128
83260
|
throw new DomainError(
|
|
83129
83261
|
"BLOCKED",
|
|
83130
|
-
`a pasta ${
|
|
83262
|
+
`a pasta ${relative5} tem ${inside3.length} ${inside3.length === 1 ? "entrada" : "entradas"} dentro; apagar assim mesmo exige recursive`
|
|
83131
83263
|
);
|
|
83132
83264
|
}
|
|
83133
83265
|
await rmdir(entry).catch((error40) => {
|
|
83134
|
-
throw asRemovalFailure(error40,
|
|
83266
|
+
throw asRemovalFailure(error40, relative5);
|
|
83135
83267
|
});
|
|
83136
83268
|
},
|
|
83137
83269
|
async deletePreview(root, path) {
|
|
83138
|
-
const { relative:
|
|
83270
|
+
const { relative: relative5, entry, exists: exists2 } = await resolveForWrite(root, path);
|
|
83139
83271
|
if (!exists2) {
|
|
83140
|
-
throw new DomainError("NOT_FOUND", `${
|
|
83272
|
+
throw new DomainError("NOT_FOUND", `${relative5} n\xE3o existe no checkout`);
|
|
83141
83273
|
}
|
|
83142
83274
|
const info = await lstat3(entry).catch((error40) => {
|
|
83143
|
-
throw asRemovalFailure(error40,
|
|
83275
|
+
throw asRemovalFailure(error40, relative5);
|
|
83144
83276
|
});
|
|
83145
83277
|
if (!info.isDirectory()) {
|
|
83146
|
-
return { kind: "file", path:
|
|
83278
|
+
return { kind: "file", path: relative5, tracked: await isTracked(entry) };
|
|
83147
83279
|
}
|
|
83148
|
-
return { kind: "dir", path:
|
|
83280
|
+
return { kind: "dir", path: relative5, ...await countTree(entry, maxPreviewEntries) };
|
|
83149
83281
|
}
|
|
83150
83282
|
};
|
|
83151
83283
|
}
|
|
@@ -83165,8 +83297,8 @@ function createFsBridge({ files: files2, root }) {
|
|
|
83165
83297
|
}
|
|
83166
83298
|
return candidate;
|
|
83167
83299
|
}
|
|
83168
|
-
async function ensureParents(
|
|
83169
|
-
const parts =
|
|
83300
|
+
async function ensureParents(relative5) {
|
|
83301
|
+
const parts = relative5.split(sep3).slice(0, -1);
|
|
83170
83302
|
let walked = "";
|
|
83171
83303
|
for (const part of parts) {
|
|
83172
83304
|
walked = walked === "" ? part : `${walked}${sep3}${part}`;
|
|
@@ -83196,16 +83328,16 @@ function createFsBridge({ files: files2, root }) {
|
|
|
83196
83328
|
return sliceWindow(content.text, window2);
|
|
83197
83329
|
},
|
|
83198
83330
|
async write(path, content) {
|
|
83199
|
-
const
|
|
83200
|
-
const existing = await files2.readFile(absoluteRoot,
|
|
83331
|
+
const relative5 = toRelative2(path);
|
|
83332
|
+
const existing = await files2.readFile(absoluteRoot, relative5).catch((error40) => {
|
|
83201
83333
|
if (error40 instanceof DomainError && error40.code === "NOT_FOUND") return null;
|
|
83202
83334
|
throw error40;
|
|
83203
83335
|
});
|
|
83204
83336
|
let before = existing;
|
|
83205
83337
|
if (before === null) {
|
|
83206
|
-
await ensureParents(
|
|
83207
|
-
await files2.createFile(absoluteRoot,
|
|
83208
|
-
before = await files2.readFile(absoluteRoot,
|
|
83338
|
+
await ensureParents(relative5);
|
|
83339
|
+
await files2.createFile(absoluteRoot, relative5);
|
|
83340
|
+
before = await files2.readFile(absoluteRoot, relative5);
|
|
83209
83341
|
}
|
|
83210
83342
|
if (before.kind !== "text") {
|
|
83211
83343
|
throw new DomainError(
|
|
@@ -83213,7 +83345,7 @@ function createFsBridge({ files: files2, root }) {
|
|
|
83213
83345
|
`escrita recusada em ${path}: o conte\xFAdo atual n\xE3o \xE9 texto`
|
|
83214
83346
|
);
|
|
83215
83347
|
}
|
|
83216
|
-
const result = await files2.writeFile(absoluteRoot,
|
|
83348
|
+
const result = await files2.writeFile(absoluteRoot, relative5, {
|
|
83217
83349
|
text: content,
|
|
83218
83350
|
baseRevision: before.revision
|
|
83219
83351
|
});
|
|
@@ -83271,11 +83403,11 @@ function createTerminalBridge({
|
|
|
83271
83403
|
const entry = {
|
|
83272
83404
|
ptySessionId: spawned.id,
|
|
83273
83405
|
settled: null,
|
|
83274
|
-
exited: new Promise((
|
|
83406
|
+
exited: new Promise((resolve6) => {
|
|
83275
83407
|
ptyManager.onExit(spawned.id, ({ exitCode, signal }) => {
|
|
83276
83408
|
const status = { exitCode, signal: signal === null ? null : String(signal) };
|
|
83277
83409
|
entry.settled = status;
|
|
83278
|
-
|
|
83410
|
+
resolve6(status);
|
|
83279
83411
|
});
|
|
83280
83412
|
})
|
|
83281
83413
|
};
|
|
@@ -83322,9 +83454,9 @@ function spawnAcpProcess({ command, args, cwd, env }) {
|
|
|
83322
83454
|
env: { ...process.env, ...env },
|
|
83323
83455
|
stdio: ["pipe", "pipe", "inherit"]
|
|
83324
83456
|
});
|
|
83325
|
-
const exited = new Promise((
|
|
83326
|
-
child.once("exit", (exitCode, signal) =>
|
|
83327
|
-
child.once("error", () =>
|
|
83457
|
+
const exited = new Promise((resolve6) => {
|
|
83458
|
+
child.once("exit", (exitCode, signal) => resolve6({ exitCode, signal }));
|
|
83459
|
+
child.once("error", () => resolve6({ exitCode: null, signal: null }));
|
|
83328
83460
|
});
|
|
83329
83461
|
if (!child.stdin || !child.stdout) {
|
|
83330
83462
|
throw new DomainError("SPAWN_FAILED", `${command} started without a usable stdio pipe`);
|
|
@@ -83339,6 +83471,54 @@ function spawnAcpProcess({ command, args, cwd, env }) {
|
|
|
83339
83471
|
};
|
|
83340
83472
|
}
|
|
83341
83473
|
|
|
83474
|
+
// src/acp/permission-policy.ts
|
|
83475
|
+
import { isAbsolute as isAbsolute4, relative, resolve as resolve3 } from "node:path";
|
|
83476
|
+
var READ = "read";
|
|
83477
|
+
var AUTO_ONLY_READS = true;
|
|
83478
|
+
function decidePermission(mode, cwd, call) {
|
|
83479
|
+
if (mode === "ask") {
|
|
83480
|
+
return { approve: false, reason: null };
|
|
83481
|
+
}
|
|
83482
|
+
if (mode === "auto" && !isReadInside(cwd, call)) {
|
|
83483
|
+
return { approve: false, reason: whyNotAuto(cwd, call) };
|
|
83484
|
+
}
|
|
83485
|
+
const allow = call.options.find((option) => option.kind === "allow_once");
|
|
83486
|
+
if (!allow) {
|
|
83487
|
+
return {
|
|
83488
|
+
approve: false,
|
|
83489
|
+
reason: "o modo do Lumem aprovaria isto, mas o agente n\xE3o ofereceu nenhuma op\xE7\xE3o de permitir uma vez"
|
|
83490
|
+
};
|
|
83491
|
+
}
|
|
83492
|
+
return {
|
|
83493
|
+
approve: true,
|
|
83494
|
+
optionId: allow.optionId,
|
|
83495
|
+
reason: mode === "free" ? "Modo Liberado: nada \xE9 perguntado dentro deste checkout." : "Modo Autom\xE1tico: leitura de arquivo, caminho dentro do checkout."
|
|
83496
|
+
};
|
|
83497
|
+
}
|
|
83498
|
+
function isReadInside(cwd, call) {
|
|
83499
|
+
if (AUTO_ONLY_READS && call.kind !== READ) return false;
|
|
83500
|
+
if (call.locations.length === 0) return false;
|
|
83501
|
+
return call.locations.every((location) => inside2(cwd, location.path));
|
|
83502
|
+
}
|
|
83503
|
+
function whyNotAuto(cwd, call) {
|
|
83504
|
+
if (call.kind !== READ) {
|
|
83505
|
+
return `O modo Autom\xE1tico do Lumem aprova sozinho s\xF3 leitura de arquivo. Esta chamada \xE9 "${call.kind}".`;
|
|
83506
|
+
}
|
|
83507
|
+
if (call.locations.length === 0) {
|
|
83508
|
+
return "O modo Autom\xE1tico do Lumem precisa saber qual arquivo: esta leitura n\xE3o disse nenhum caminho.";
|
|
83509
|
+
}
|
|
83510
|
+
const outside = call.locations.find((location) => !inside2(cwd, location.path));
|
|
83511
|
+
return `O modo Autom\xE1tico do Lumem aprova sozinho s\xF3 dentro do checkout, e "${outside?.path ?? ""}" est\xE1 fora.`;
|
|
83512
|
+
}
|
|
83513
|
+
function inside2(root, path) {
|
|
83514
|
+
if (root === "") return false;
|
|
83515
|
+
const from = resolve3(root);
|
|
83516
|
+
const to = resolve3(from, path);
|
|
83517
|
+
if (to === from) return true;
|
|
83518
|
+
const step = relative(from, to);
|
|
83519
|
+
return step !== "" && !step.startsWith("..") && !isAbsolute4(step);
|
|
83520
|
+
}
|
|
83521
|
+
|
|
83342
83522
|
// src/acp/translate.ts
|
|
83343
83523
|
var TOOL_STATUS = {
|
|
83344
83524
|
pending: "pending",
|
|
@@ -83653,6 +83833,10 @@ function sniffUnknownUpdates(source, { onUnknown }) {
|
|
|
83653
83833
|
var ACP_PROTOCOL_VERSION = 1;
|
|
83654
83834
|
var LUMEM_CLIENT_VERSION = "0.1.0";
|
|
83655
83835
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 15e3;
|
|
83836
|
+
function modeOwnerOf(info) {
|
|
83837
|
+
if (info.mode !== "") return "agent";
|
|
83838
|
+
return info.configOptions.some((option) => option.id === MODE_OPTION) ? "agent" : "lumem";
|
|
83839
|
+
}
|
|
83656
83840
|
var AcpManager = class {
|
|
83657
83841
|
sessions = /* @__PURE__ */ new Map();
|
|
83658
83842
|
exitWatchers = /* @__PURE__ */ new Set();
|
|
@@ -83854,7 +84038,17 @@ var AcpManager = class {
|
|
|
83854
84038
|
exitCode: null,
|
|
83855
84039
|
mode: "",
|
|
83856
84040
|
model: "",
|
|
83857
|
-
configOptions: []
|
|
84041
|
+
configOptions: [],
|
|
84042
|
+
/*
|
|
84043
|
+
* A session is born asking, always (F1.5).
|
|
84044
|
+
*
|
|
84045
|
+
* The workspace default is applied by the caller that knows which
|
|
84046
|
+
* workspace this is — the store — and even that one cannot make a
|
|
84047
|
+
* session start free: the gate for `free` is per session, and a default
|
|
84048
|
+
* that walked through it would annul it (Q5).
|
|
84049
|
+
*/
|
|
84050
|
+
lumemMode: options.lumemMode ?? "ask",
|
|
84051
|
+
lumemModeDefault: options.lumemModeDefault ?? "ask"
|
|
83858
84052
|
},
|
|
83859
84053
|
process: child,
|
|
83860
84054
|
connection: void 0,
|
|
@@ -83980,7 +84174,50 @@ var AcpManager = class {
|
|
|
83980
84174
|
}
|
|
83981
84175
|
session2.pendingPermissions.delete(requestId);
|
|
83982
84176
|
pending.resolve({ outcome: "selected", optionId });
|
|
83983
|
-
this.emit(session2, {
|
|
84177
|
+
this.emit(session2, {
|
|
84178
|
+
type: "permission_resolved",
|
|
84179
|
+
requestId,
|
|
84180
|
+
outcome: { optionId },
|
|
84181
|
+
by: "user",
|
|
84182
|
+
reason: null
|
|
84183
|
+
});
|
|
84184
|
+
}
|
|
84185
|
+
/**
|
|
84186
|
+
* Switch the policy Lumem applies to permission requests (F1.1).
|
|
84187
|
+
*
|
|
84188
|
+
* Synchronous, and that is the whole difference from `setConfig`: nothing
|
|
84189
|
+
* leaves the daemon. `setConfig` forwards a value to the agent and waits for it
|
|
84190
|
+
* to answer; this changes what *we* answer, and the agent never learns a policy
|
|
84191
|
+
* exists.
|
|
84192
|
+
*
|
|
84193
|
+
* Two refusals, and both are named rather than silent:
|
|
84194
|
+
*
|
|
84195
|
+
* - **the agent owns the selector** (A1). Accepting the switch and doing
|
|
84196
|
+
* nothing with it would leave a stored value that never applies — the tell
|
|
84197
|
+
* would be a pill that changes and a behaviour that does not.
|
|
84198
|
+
* - **a turn is running** (F1.7). Same reason `setConfig` refuses, and
|
|
84199
|
+
* deliberately the same message: from where the user stands it is the same
|
|
84200
|
+
* act, and two wordings for one rule teach that there are two rules.
|
|
84201
|
+
*/
|
|
84202
|
+
setLumemMode(id, mode) {
|
|
84203
|
+
const session2 = this.require(id);
|
|
84204
|
+
if (session2.info.state === "exited") {
|
|
84205
|
+
throw new DomainError("SESSION_EXITED", `session ${id} has exited`);
|
|
84206
|
+
}
|
|
84207
|
+
if (modeOwnerOf(session2.info) === "agent") {
|
|
84208
|
+
throw new DomainError(
|
|
84209
|
+
"BLOCKED",
|
|
84210
|
+
"este agente oferece modos pr\xF3prios: troque o modo dele, n\xE3o a pol\xEDtica do Lumem"
|
|
84211
|
+
);
|
|
84212
|
+
}
|
|
84213
|
+
if (session2.promptInFlight) {
|
|
84214
|
+
throw new DomainError(
|
|
84215
|
+
"BLOCKED",
|
|
84216
|
+
"n\xE3o d\xE1 para trocar de modo ou modelo no meio de um turno: interrompa ou espere ele acabar"
|
|
84217
|
+
);
|
|
84218
|
+
}
|
|
84219
|
+
session2.info.lumemMode = mode;
|
|
84220
|
+
this.emitConfig(session2);
|
|
83984
84221
|
}
|
|
83985
84222
|
/**
|
|
83986
84223
|
* Everything an attaching client needs to catch up, in one frame.
|
|
@@ -84057,18 +84294,18 @@ var AcpManager = class {
|
|
|
84057
84294
|
const running = [...this.sessions.values()].filter((s) => s.info.state === "running");
|
|
84058
84295
|
await Promise.all(
|
|
84059
84296
|
running.map(
|
|
84060
|
-
(session2) => new Promise((
|
|
84061
|
-
const timer = setTimeout(
|
|
84297
|
+
(session2) => new Promise((resolve6) => {
|
|
84298
|
+
const timer = setTimeout(resolve6, timeoutMs);
|
|
84062
84299
|
timer.unref?.();
|
|
84063
84300
|
void session2.process.exited.then(() => {
|
|
84064
84301
|
clearTimeout(timer);
|
|
84065
|
-
|
|
84302
|
+
resolve6();
|
|
84066
84303
|
});
|
|
84067
84304
|
try {
|
|
84068
84305
|
session2.process.kill();
|
|
84069
84306
|
} catch {
|
|
84070
84307
|
clearTimeout(timer);
|
|
84071
|
-
|
|
84308
|
+
resolve6();
|
|
84072
84309
|
}
|
|
84073
84310
|
})
|
|
84074
84311
|
)
|
|
@@ -84132,6 +84369,16 @@ var AcpManager = class {
|
|
|
84132
84369
|
return {};
|
|
84133
84370
|
}).onRequest("session/request_permission", ({ params }) => {
|
|
84134
84371
|
const requestId = newId();
|
|
84372
|
+
const options = params.options.map((option) => ({
|
|
84373
|
+
optionId: option.optionId,
|
|
84374
|
+
name: option.name,
|
|
84375
|
+
kind: option.kind
|
|
84376
|
+
}));
|
|
84377
|
+
const decision = modeOwnerOf(session2.info) === "lumem" ? decidePermission(session2.info.lumemMode, session2.info.cwd, {
|
|
84378
|
+
kind: kindOf(params.toolCall),
|
|
84379
|
+
locations: locationsOf(params.toolCall),
|
|
84380
|
+
options
|
|
84381
|
+
}) : { approve: false, reason: null };
|
|
84135
84382
|
this.emit(session2, {
|
|
84136
84383
|
type: "permission_request",
|
|
84137
84384
|
requestId,
|
|
@@ -84139,15 +84386,24 @@ var AcpManager = class {
|
|
|
84139
84386
|
title: params.toolCall.title ?? params.toolCall.toolCallId,
|
|
84140
84387
|
command: commandOf(params.toolCall),
|
|
84141
84388
|
cwd: session2.info.cwd,
|
|
84142
|
-
options
|
|
84143
|
-
|
|
84144
|
-
name: option.name,
|
|
84145
|
-
kind: option.kind
|
|
84146
|
-
}))
|
|
84389
|
+
options,
|
|
84390
|
+
policyReason: decision.approve ? null : decision.reason
|
|
84147
84391
|
});
|
|
84148
|
-
|
|
84392
|
+
if (decision.approve) {
|
|
84393
|
+
this.emit(session2, {
|
|
84394
|
+
type: "permission_resolved",
|
|
84395
|
+
requestId,
|
|
84396
|
+
outcome: { optionId: decision.optionId },
|
|
84397
|
+
by: "lumem",
|
|
84398
|
+
reason: decision.reason
|
|
84399
|
+
});
|
|
84400
|
+
return Promise.resolve({
|
|
84401
|
+
outcome: { outcome: "selected", optionId: decision.optionId }
|
|
84402
|
+
});
|
|
84403
|
+
}
|
|
84404
|
+
return new Promise((resolve6) => {
|
|
84149
84405
|
session2.pendingPermissions.set(requestId, {
|
|
84150
|
-
resolve: (outcome) =>
|
|
84406
|
+
resolve: (outcome) => resolve6({ outcome })
|
|
84151
84407
|
});
|
|
84152
84408
|
});
|
|
84153
84409
|
}).onNotification(
|
|
@@ -84387,7 +84643,10 @@ var AcpManager = class {
|
|
|
84387
84643
|
this.emit(session2, {
|
|
84388
84644
|
type: "config",
|
|
84389
84645
|
mode: session2.info.mode,
|
|
84390
|
-
options: [...session2.info.configOptions]
|
|
84646
|
+
options: [...session2.info.configOptions],
|
|
84647
|
+
modeOwner: modeOwnerOf(session2.info),
|
|
84648
|
+
lumemMode: session2.info.lumemMode,
|
|
84649
|
+
lumemModeDefault: session2.info.lumemModeDefault
|
|
84391
84650
|
});
|
|
84392
84651
|
for (const watcher of [...this.configWatchers]) {
|
|
84393
84652
|
try {
|
|
@@ -84551,6 +84810,18 @@ function flattenChoices(options) {
|
|
|
84551
84810
|
];
|
|
84552
84811
|
});
|
|
84553
84812
|
}
|
|
84813
|
+
function kindOf(toolCall) {
|
|
84814
|
+
const parsed = acpToolKindSchema.safeParse(toolCall.kind);
|
|
84815
|
+
return parsed.success ? parsed.data : "other";
|
|
84816
|
+
}
|
|
84817
|
+
function locationsOf(toolCall) {
|
|
84818
|
+
const locations = toolCall.locations;
|
|
84819
|
+
if (!Array.isArray(locations)) return [];
|
|
84820
|
+
return locations.flatMap((location) => {
|
|
84821
|
+
const path = location.path;
|
|
84822
|
+
return typeof path === "string" ? [{ path, line: null }] : [];
|
|
84823
|
+
});
|
|
84824
|
+
}
|
|
84554
84825
|
function commandOf(toolCall) {
|
|
84555
84826
|
const raw = toolCall.rawInput;
|
|
84556
84827
|
if (typeof raw === "object" && raw !== null) {
|
|
@@ -84711,7 +84982,7 @@ import { dirname as dirname6, join as join11 } from "node:path";
|
|
|
84711
84982
|
// src/memory/catalog.ts
|
|
84712
84983
|
import { createHash as createHash2 } from "node:crypto";
|
|
84713
84984
|
import { readdir as readdir5, readFile as readFile3 } from "node:fs/promises";
|
|
84714
|
-
import { join as join9, relative, sep as sep4 } from "node:path";
|
|
84985
|
+
import { join as join9, relative as relative2, sep as sep4 } from "node:path";
|
|
84715
84986
|
|
|
84716
84987
|
// src/memory/entry.ts
|
|
84717
84988
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -85010,7 +85281,7 @@ async function collectFrom(stateDir, dir, location, items) {
|
|
|
85010
85281
|
if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
|
|
85011
85282
|
if (dirent.name === "MEMORY.md") continue;
|
|
85012
85283
|
const absolute = join9(dir, dirent.name);
|
|
85013
|
-
const path =
|
|
85284
|
+
const path = relative2(stateDir, absolute).split(sep4).join("/");
|
|
85014
85285
|
const text2 = await readFile3(absolute, "utf8").catch((error40) => error40);
|
|
85015
85286
|
if (typeof text2 !== "string") {
|
|
85016
85287
|
items.push({ path, reason: `n\xE3o foi poss\xEDvel ler: ${text2.message}` });
|
|
@@ -85201,7 +85472,7 @@ function listDecisions(db, { path, limit = 50 } = {}) {
|
|
|
85201
85472
|
}
|
|
85202
85473
|
|
|
85203
85474
|
// src/memory/paths.ts
|
|
85204
|
-
import { join as join10, relative as
|
|
85475
|
+
import { join as join10, relative as relative3, sep as sep5 } from "node:path";
|
|
85205
85476
|
var ID_SEGMENT = "[A-Za-z0-9_-]+";
|
|
85206
85477
|
function memoryDirFor(stateDir, target) {
|
|
85207
85478
|
switch (target.scope) {
|
|
@@ -85281,7 +85552,7 @@ function slugOf(path, type) {
|
|
|
85281
85552
|
return file2.replace(new RegExp(`^${type}_`), "").replace(/\.md$/, "");
|
|
85282
85553
|
}
|
|
85283
85554
|
function repoRelative(stateDir, absolutePath) {
|
|
85284
|
-
const rel =
|
|
85555
|
+
const rel = relative3(stateDir, absolutePath);
|
|
85285
85556
|
if (rel === "" || rel.startsWith("..")) {
|
|
85286
85557
|
throw new DomainError("INVALID_ARGUMENT", `caminho fora do state dir: ${absolutePath}`);
|
|
85287
85558
|
}
|
|
@@ -86396,7 +86667,7 @@ function parseWrite(requested) {
|
|
|
86396
86667
|
}
|
|
86397
86668
|
|
|
86398
86669
|
// src/memory/projection.ts
|
|
86399
|
-
import { relative as
|
|
86670
|
+
import { relative as relative4, isAbsolute as isAbsolute5 } from "node:path";
|
|
86400
86671
|
var MAX_FILES = 12;
|
|
86401
86672
|
var MAX_COMMANDS = 8;
|
|
86402
86673
|
function isEmpty(projection) {
|
|
@@ -86444,8 +86715,8 @@ function projectSession(entries, { cwd }) {
|
|
|
86444
86715
|
};
|
|
86445
86716
|
}
|
|
86446
86717
|
function toRelative(path, cwd) {
|
|
86447
|
-
if (!
|
|
86448
|
-
const rel =
|
|
86718
|
+
if (!isAbsolute5(path)) return path;
|
|
86719
|
+
const rel = relative4(cwd, path);
|
|
86449
86720
|
if (rel === "" || rel.startsWith("..")) return null;
|
|
86450
86721
|
return rel;
|
|
86451
86722
|
}
|
|
@@ -87212,18 +87483,18 @@ var PtyManager = class {
|
|
|
87212
87483
|
const running = [...this.sessions.values()].filter((s) => s.info.state === "running");
|
|
87213
87484
|
await Promise.all(
|
|
87214
87485
|
running.map(
|
|
87215
|
-
(session2) => new Promise((
|
|
87216
|
-
const timer = setTimeout(
|
|
87486
|
+
(session2) => new Promise((resolve6) => {
|
|
87487
|
+
const timer = setTimeout(resolve6, timeoutMs);
|
|
87217
87488
|
timer.unref?.();
|
|
87218
87489
|
session2.exitListeners.add(() => {
|
|
87219
87490
|
clearTimeout(timer);
|
|
87220
|
-
|
|
87491
|
+
resolve6();
|
|
87221
87492
|
});
|
|
87222
87493
|
try {
|
|
87223
87494
|
session2.pty.kill();
|
|
87224
87495
|
} catch {
|
|
87225
87496
|
clearTimeout(timer);
|
|
87226
|
-
|
|
87497
|
+
resolve6();
|
|
87227
87498
|
}
|
|
87228
87499
|
})
|
|
87229
87500
|
)
|
|
@@ -87333,10 +87604,10 @@ async function releasePort(db, scope) {
|
|
|
87333
87604
|
);
|
|
87334
87605
|
}
|
|
87335
87606
|
function isPortFree(port) {
|
|
87336
|
-
return new Promise((
|
|
87607
|
+
return new Promise((resolve6) => {
|
|
87337
87608
|
const probe = createServer();
|
|
87338
|
-
probe.once("error", () =>
|
|
87339
|
-
probe.once("listening", () => probe.close(() =>
|
|
87609
|
+
probe.once("error", () => resolve6(false));
|
|
87610
|
+
probe.once("listening", () => probe.close(() => resolve6(true)));
|
|
87340
87611
|
probe.listen(port, "0.0.0.0");
|
|
87341
87612
|
});
|
|
87342
87613
|
}
|
|
@@ -87999,7 +88270,7 @@ function parse3(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
87999
88270
|
}
|
|
88000
88271
|
|
|
88001
88272
|
// src/memory/project-identity.ts
|
|
88002
|
-
import { dirname as dirname7, join as join13, resolve as
|
|
88273
|
+
import { dirname as dirname7, join as join13, resolve as resolve4 } from "node:path";
|
|
88003
88274
|
var PROJECT_FILE = join13(".lumem", "project.toml");
|
|
88004
88275
|
|
|
88005
88276
|
// src/scripts/project-scripts.ts
|
|
@@ -88131,7 +88402,7 @@ function createScriptRunner({
|
|
|
88131
88402
|
log
|
|
88132
88403
|
}) {
|
|
88133
88404
|
const discovered = /* @__PURE__ */ new Map();
|
|
88134
|
-
async function
|
|
88405
|
+
async function checkoutOf2(scope) {
|
|
88135
88406
|
const projects = createProjectRepository(db);
|
|
88136
88407
|
if (scope.scopeType === "project") {
|
|
88137
88408
|
const project3 = await projects.findById(scope.scopeId);
|
|
@@ -88184,7 +88455,7 @@ function createScriptRunner({
|
|
|
88184
88455
|
}
|
|
88185
88456
|
return {
|
|
88186
88457
|
async status(scope) {
|
|
88187
|
-
const { project: project2, cwd } = await
|
|
88458
|
+
const { project: project2, cwd } = await checkoutOf2(scope);
|
|
88188
88459
|
const scripts = await readProjectScripts(cwd, {
|
|
88189
88460
|
warn: (message) => log?.warn({ scope, message }, "scripts ignorados")
|
|
88190
88461
|
});
|
|
@@ -88208,7 +88479,7 @@ function createScriptRunner({
|
|
|
88208
88479
|
};
|
|
88209
88480
|
},
|
|
88210
88481
|
async start(scope, phase) {
|
|
88211
|
-
const { project: project2, worktree: worktree2, cwd } = await
|
|
88482
|
+
const { project: project2, worktree: worktree2, cwd } = await checkoutOf2(scope);
|
|
88212
88483
|
const scripts = await readProjectScripts(cwd);
|
|
88213
88484
|
const command = scripts[phase];
|
|
88214
88485
|
if (command === null) {
|
|
@@ -88274,15 +88545,15 @@ function createScriptRunner({
|
|
|
88274
88545
|
},
|
|
88275
88546
|
async runToCompletion(scope, phase, { timeoutMs = TEARDOWN_TIMEOUT_MS } = {}) {
|
|
88276
88547
|
const { session: row } = await this.start(scope, phase);
|
|
88277
|
-
return new Promise((
|
|
88548
|
+
return new Promise((resolve6) => {
|
|
88278
88549
|
const timer = setTimeout(() => {
|
|
88279
88550
|
log?.warn({ scope, phase }, "script n\xE3o terminou no tempo \u2014 seguindo sem ele");
|
|
88280
88551
|
ptyManager.kill(row.id);
|
|
88281
|
-
|
|
88552
|
+
resolve6(null);
|
|
88282
88553
|
}, timeoutMs);
|
|
88283
88554
|
ptyManager.onExit(row.id, ({ exitCode }) => {
|
|
88284
88555
|
clearTimeout(timer);
|
|
88285
|
-
|
|
88556
|
+
resolve6(exitCode);
|
|
88286
88557
|
});
|
|
88287
88558
|
});
|
|
88288
88559
|
},
|
|
@@ -88450,6 +88721,19 @@ function createSessionStore({
|
|
|
88450
88721
|
log?.warn({ session: row.id, err: error40 }, "falha ao varrer reverts do checkout");
|
|
88451
88722
|
}
|
|
88452
88723
|
}
|
|
88724
|
+
async function inheritedMode(scopeType, scopeId) {
|
|
88725
|
+
try {
|
|
88726
|
+
const projects = createProjectRepository(db);
|
|
88727
|
+
const projectId = scopeType === "project" ? scopeId : (await createWorktreeRepository(db).findById(scopeId))?.projectId;
|
|
88728
|
+
if (!projectId) return "ask";
|
|
88729
|
+
const project2 = await projects.findById(projectId);
|
|
88730
|
+
if (!project2) return "ask";
|
|
88731
|
+
const workspace2 = await createWorkspaceRepository(db).findById(project2.workspaceId);
|
|
88732
|
+
return workspace2?.defaultLumemMode === "auto" ? "auto" : "ask";
|
|
88733
|
+
} catch {
|
|
88734
|
+
return "ask";
|
|
88735
|
+
}
|
|
88736
|
+
}
|
|
88453
88737
|
return {
|
|
88454
88738
|
async start(input) {
|
|
88455
88739
|
const { kind, agentConfigId = null, scopeType, scopeId, cwd, command } = input;
|
|
@@ -88462,12 +88746,17 @@ function createSessionStore({
|
|
|
88462
88746
|
"esta inst\xE2ncia n\xE3o sabe iniciar sess\xE3o ACP: nenhum AcpManager foi ligado"
|
|
88463
88747
|
);
|
|
88464
88748
|
}
|
|
88749
|
+
const inherited = await inheritedMode(scopeType, scopeId);
|
|
88465
88750
|
const agent = await acpManager.spawn({
|
|
88466
88751
|
command,
|
|
88467
88752
|
...input.args ? { args: input.args } : {},
|
|
88468
88753
|
cwd,
|
|
88469
88754
|
...input.env ? { env: input.env } : {},
|
|
88470
|
-
...input.adapterVersion ? { adapterVersion: input.adapterVersion } : {}
|
|
88755
|
+
...input.adapterVersion ? { adapterVersion: input.adapterVersion } : {},
|
|
88756
|
+
// O modo herdado, e ele é o mesmo nos dois campos: uma sessão nova
|
|
88757
|
+
// começa no padrão do workspace, e o menu mostra de onde veio.
|
|
88758
|
+
lumemMode: inherited,
|
|
88759
|
+
lumemModeDefault: inherited
|
|
88471
88760
|
});
|
|
88472
88761
|
try {
|
|
88473
88762
|
return await sessions.create({
|
|
@@ -88545,6 +88834,16 @@ function createSessionStore({
|
|
|
88545
88834
|
...config2?.env && Object.keys(config2.env).length > 0 ? { env: config2.env } : {},
|
|
88546
88835
|
...config2?.adapterVersion ? { adapterVersion: config2.adapterVersion } : {},
|
|
88547
88836
|
acpSessionId: row.acpSessionId,
|
|
88837
|
+
/*
|
|
88838
|
+
* A política volta como estava (F1.4).
|
|
88839
|
+
*
|
|
88840
|
+
* `lumemMode` da linha morta, e não o padrão do workspace: retomar é
|
|
88841
|
+
* continuar a mesma conversa, e uma que estava em `auto` voltar
|
|
88842
|
+
* perguntando tudo seria a feature desfazendo a escolha em silêncio.
|
|
88843
|
+
* Inclusive `free` — o portão já foi atravessado por esta conversa.
|
|
88844
|
+
*/
|
|
88845
|
+
lumemMode: row.lumemMode,
|
|
88846
|
+
lumemModeDefault: await inheritedMode(row.scopeType, row.scopeId),
|
|
88548
88847
|
// What makes the new session's transcript self-contained (D15): the old
|
|
88549
88848
|
// conversation is copied in front of it, and the separator recorded after.
|
|
88550
88849
|
fromSessionId: row.id
|
|
@@ -88597,6 +88896,19 @@ function createSessionStore({
|
|
|
88597
88896
|
* interface offering something it cannot do.
|
|
88598
88897
|
*/
|
|
88599
88898
|
configOptions: [],
|
|
88899
|
+
/*
|
|
88900
|
+
* O modo em que a conversa **esteve** (F1.8).
|
|
88901
|
+
*
|
|
88902
|
+
* A autoria sai de `row.mode`, e não de `configOptions`: aqui a lista é
|
|
88903
|
+
* vazia por construção, e perguntar a ela quem era o dono responderia
|
|
88904
|
+
* "o Lumem" para toda conversa morta — inclusive as que rodaram com um
|
|
88905
|
+
* agente cheio de modos. O que a linha guarda é qual modo estava valendo,
|
|
88906
|
+
* e ter um é a prova de que o agente era o dono.
|
|
88907
|
+
*/
|
|
88908
|
+
modeOwner: row.mode ? "agent" : "lumem",
|
|
88909
|
+
lumemMode: row.lumemMode,
|
|
88910
|
+
lumemModeDefault: "ask",
|
|
88911
|
+
cwd: row.cwd,
|
|
88600
88912
|
transcript: [...acpManager.storedTranscript(row.id)]
|
|
88601
88913
|
};
|
|
88602
88914
|
},
|
|
@@ -88636,7 +88948,11 @@ function createSessionStore({
|
|
|
88636
88948
|
const offPty = ptyManager.watchExits((info) => record2(info.id, info.exitCode));
|
|
88637
88949
|
const offAcp = acpManager?.watchExits((info) => record2(info.id, info.exitCode));
|
|
88638
88950
|
const offConfig = acpManager?.watchConfig((info) => {
|
|
88639
|
-
void sessions.setConfig(info.id, {
|
|
88951
|
+
void sessions.setConfig(info.id, {
|
|
88952
|
+
mode: info.mode,
|
|
88953
|
+
model: info.model,
|
|
88954
|
+
lumemMode: info.lumemMode
|
|
88955
|
+
}).catch((error40) => {
|
|
88640
88956
|
log?.warn({ session: info.id, err: error40 }, "falha ao registrar troca de configura\xE7\xE3o");
|
|
88641
88957
|
});
|
|
88642
88958
|
});
|
|
@@ -89593,8 +89909,8 @@ var Unpromise = class Unpromise2 {
|
|
|
89593
89909
|
status: "fulfilled",
|
|
89594
89910
|
value
|
|
89595
89911
|
};
|
|
89596
|
-
subscribers === null || subscribers === void 0 || subscribers.forEach(({ resolve:
|
|
89597
|
-
|
|
89912
|
+
subscribers === null || subscribers === void 0 || subscribers.forEach(({ resolve: resolve6 }) => {
|
|
89913
|
+
resolve6(value);
|
|
89598
89914
|
});
|
|
89599
89915
|
});
|
|
89600
89916
|
if ("catch" in thenReturn) thenReturn.catch((reason) => {
|
|
@@ -89735,15 +90051,15 @@ function resolveSelfTuple(promise2) {
|
|
|
89735
90051
|
return Unpromise.proxy(promise2).then(() => [promise2]);
|
|
89736
90052
|
}
|
|
89737
90053
|
function withResolvers() {
|
|
89738
|
-
let
|
|
90054
|
+
let resolve6;
|
|
89739
90055
|
let reject;
|
|
89740
90056
|
const promise2 = new Promise((_resolve, _reject) => {
|
|
89741
|
-
|
|
90057
|
+
resolve6 = _resolve;
|
|
89742
90058
|
reject = _reject;
|
|
89743
90059
|
});
|
|
89744
90060
|
return {
|
|
89745
90061
|
promise: promise2,
|
|
89746
|
-
resolve:
|
|
90062
|
+
resolve: resolve6,
|
|
89747
90063
|
reject
|
|
89748
90064
|
};
|
|
89749
90065
|
}
|
|
@@ -89787,8 +90103,8 @@ function timerResource(ms) {
|
|
|
89787
90103
|
let timer = null;
|
|
89788
90104
|
return makeResource({ start() {
|
|
89789
90105
|
if (timer) throw new Error("Timer already started");
|
|
89790
|
-
const promise2 = new Promise((
|
|
89791
|
-
timer = setTimeout(() =>
|
|
90106
|
+
const promise2 = new Promise((resolve6) => {
|
|
90107
|
+
timer = setTimeout(() => resolve6(disposablePromiseTimerResult), ms);
|
|
89792
90108
|
});
|
|
89793
90109
|
return promise2;
|
|
89794
90110
|
} }, () => {
|
|
@@ -89975,15 +90291,15 @@ function _takeWithGrace() {
|
|
|
89975
90291
|
return _takeWithGrace.apply(this, arguments);
|
|
89976
90292
|
}
|
|
89977
90293
|
function createDeferred() {
|
|
89978
|
-
let
|
|
90294
|
+
let resolve6;
|
|
89979
90295
|
let reject;
|
|
89980
90296
|
const promise2 = new Promise((res, rej) => {
|
|
89981
|
-
|
|
90297
|
+
resolve6 = res;
|
|
89982
90298
|
reject = rej;
|
|
89983
90299
|
});
|
|
89984
90300
|
return {
|
|
89985
90301
|
promise: promise2,
|
|
89986
|
-
resolve:
|
|
90302
|
+
resolve: resolve6,
|
|
89987
90303
|
reject
|
|
89988
90304
|
};
|
|
89989
90305
|
}
|
|
@@ -91558,8 +91874,8 @@ function getWSConnectionHandler(opts) {
|
|
|
91558
91874
|
try {
|
|
91559
91875
|
var _usingCtx = (0, import_usingCtx2.default)();
|
|
91560
91876
|
const iterator = _usingCtx.a(iteratorResource(iterable));
|
|
91561
|
-
const abortPromise = new Promise((
|
|
91562
|
-
abortController$1.signal.onabort = () =>
|
|
91877
|
+
const abortPromise = new Promise((resolve6) => {
|
|
91878
|
+
abortController$1.signal.onabort = () => resolve6("abort");
|
|
91563
91879
|
});
|
|
91564
91880
|
let next;
|
|
91565
91881
|
let result$1;
|
|
@@ -92039,8 +92355,8 @@ async function* snapshots(id, current, listeners, signal) {
|
|
|
92039
92355
|
yield job;
|
|
92040
92356
|
if (isTerminal(job.state)) return;
|
|
92041
92357
|
}
|
|
92042
|
-
await new Promise((
|
|
92043
|
-
wake =
|
|
92358
|
+
await new Promise((resolve6) => {
|
|
92359
|
+
wake = resolve6;
|
|
92044
92360
|
});
|
|
92045
92361
|
wake = void 0;
|
|
92046
92362
|
}
|
|
@@ -92051,6 +92367,652 @@ async function* snapshots(id, current, listeners, signal) {
|
|
|
92051
92367
|
}
|
|
92052
92368
|
}
|
|
92053
92369
|
|
|
92370
|
+
// src/pr/GhHost.ts
|
|
92371
|
+
import { mkdtemp, rm as rm4, writeFile as writeFile4 } from "node:fs/promises";
|
|
92372
|
+
import { tmpdir } from "node:os";
|
|
92373
|
+
import { join as join15 } from "node:path";
|
|
92374
|
+
|
|
92375
|
+
// src/git/git-url.ts
|
|
92376
|
+
var ALLOWED = /* @__PURE__ */ new Set(["https", "http", "ssh", "file"]);
|
|
92377
|
+
var HELPER = /^([A-Za-z][A-Za-z0-9+.-]*)::/;
|
|
92378
|
+
var SCHEME = /^([A-Za-z][A-Za-z0-9+.-]*):\/\//;
|
|
92379
|
+
var CONTROL = /[\u0000-\u001f\u007f]/;
|
|
92380
|
+
function refuse(rule, message) {
|
|
92381
|
+
return { ok: false, rule, message };
|
|
92382
|
+
}
|
|
92383
|
+
function refuseScheme(scheme) {
|
|
92384
|
+
if (scheme === "git") {
|
|
92385
|
+
return refuse(
|
|
92386
|
+
"scheme",
|
|
92387
|
+
"o transporte git:// n\xE3o \xE9 aceito: ele n\xE3o autentica nem verifica integridade \u2014 use a URL https ou ssh do mesmo reposit\xF3rio"
|
|
92388
|
+
);
|
|
92389
|
+
}
|
|
92390
|
+
return refuse(
|
|
92391
|
+
"scheme",
|
|
92392
|
+
`o transporte "${scheme}" n\xE3o est\xE1 na lista de transportes aceitos (https, http, ssh, file)`
|
|
92393
|
+
);
|
|
92394
|
+
}
|
|
92395
|
+
function parseGitUrl(input) {
|
|
92396
|
+
const raw = input.trim();
|
|
92397
|
+
if (raw === "") return refuse("empty", "informe a URL do reposit\xF3rio");
|
|
92398
|
+
if (CONTROL.test(raw)) {
|
|
92399
|
+
return refuse("control-chars", "a URL tem caracteres de controle");
|
|
92400
|
+
}
|
|
92401
|
+
if (raw.startsWith("-")) {
|
|
92402
|
+
return refuse("leading-dash", "a URL n\xE3o pode come\xE7ar com '-'");
|
|
92403
|
+
}
|
|
92404
|
+
const helper = HELPER.exec(raw);
|
|
92405
|
+
if (helper) return refuseScheme(helper[1].toLowerCase());
|
|
92406
|
+
const scheme = SCHEME.exec(raw);
|
|
92407
|
+
if (scheme) return parseWithScheme(raw, scheme[1].toLowerCase());
|
|
92408
|
+
if (isScp(raw)) return parseScp(raw);
|
|
92409
|
+
return refuse(
|
|
92410
|
+
"scheme",
|
|
92411
|
+
"n\xE3o reconheci isto como URL git: use https://, ssh://, file:// ou a forma git@host:org/repo.git"
|
|
92412
|
+
);
|
|
92413
|
+
}
|
|
92414
|
+
function scpColon(raw) {
|
|
92415
|
+
const at = raw.indexOf("@");
|
|
92416
|
+
return raw.indexOf(":", at === -1 ? 0 : at + 1);
|
|
92417
|
+
}
|
|
92418
|
+
function isScp(raw) {
|
|
92419
|
+
const colon = scpColon(raw);
|
|
92420
|
+
if (colon <= 0) return false;
|
|
92421
|
+
const slash = raw.indexOf("/");
|
|
92422
|
+
return slash === -1 || colon < slash;
|
|
92423
|
+
}
|
|
92424
|
+
function parseWithScheme(raw, scheme) {
|
|
92425
|
+
if (!ALLOWED.has(scheme)) return refuseScheme(scheme);
|
|
92426
|
+
let parsed;
|
|
92427
|
+
try {
|
|
92428
|
+
parsed = new URL(raw);
|
|
92429
|
+
} catch {
|
|
92430
|
+
return refuse("host", `n\xE3o consegui ler ${raw} como URL`);
|
|
92431
|
+
}
|
|
92432
|
+
if (scheme === "file") return parseFile(raw, parsed);
|
|
92433
|
+
if (parsed.hostname === "" || raw.slice(scheme.length + "://".length).startsWith("/")) {
|
|
92434
|
+
return refuse("host", "a URL n\xE3o tem host");
|
|
92435
|
+
}
|
|
92436
|
+
const path = parsed.pathname.replace(/^\/+/, "");
|
|
92437
|
+
if (path === "") {
|
|
92438
|
+
return refuse("path", "a URL n\xE3o diz qual reposit\xF3rio");
|
|
92439
|
+
}
|
|
92440
|
+
const sanitized = new URL(raw);
|
|
92441
|
+
sanitized.username = "";
|
|
92442
|
+
sanitized.password = "";
|
|
92443
|
+
return {
|
|
92444
|
+
ok: true,
|
|
92445
|
+
raw,
|
|
92446
|
+
url: {
|
|
92447
|
+
scheme,
|
|
92448
|
+
href: sanitized.href,
|
|
92449
|
+
host: parsed.host,
|
|
92450
|
+
path,
|
|
92451
|
+
insecure: scheme === "http",
|
|
92452
|
+
scp: false
|
|
92453
|
+
}
|
|
92454
|
+
};
|
|
92455
|
+
}
|
|
92456
|
+
function parseFile(raw, parsed) {
|
|
92457
|
+
if (parsed.hostname !== "" && parsed.hostname !== "localhost") {
|
|
92458
|
+
return refuse("host", "file:// com host n\xE3o \xE9 aceito; use file:///caminho/absoluto");
|
|
92459
|
+
}
|
|
92460
|
+
const path = decodeURIComponent(parsed.pathname);
|
|
92461
|
+
if (!path.startsWith("/")) {
|
|
92462
|
+
return refuse("path", "o caminho de um file:// precisa ser absoluto");
|
|
92463
|
+
}
|
|
92464
|
+
return {
|
|
92465
|
+
ok: true,
|
|
92466
|
+
raw,
|
|
92467
|
+
url: { scheme: "file", href: `file://${parsed.pathname}`, host: "", path, insecure: false, scp: false }
|
|
92468
|
+
};
|
|
92469
|
+
}
|
|
92470
|
+
function parseScp(raw) {
|
|
92471
|
+
const colon = scpColon(raw);
|
|
92472
|
+
const authority = raw.slice(0, colon);
|
|
92473
|
+
const path = raw.slice(colon + 1);
|
|
92474
|
+
const at = authority.lastIndexOf("@");
|
|
92475
|
+
const user = at === -1 ? "" : authority.slice(0, at);
|
|
92476
|
+
const host = authority.slice(at + 1);
|
|
92477
|
+
if (host === "") return refuse("host", "a URL n\xE3o tem host");
|
|
92478
|
+
if (path === "") return refuse("path", "a URL n\xE3o diz qual reposit\xF3rio");
|
|
92479
|
+
const cleanUser = user.includes(":") ? user.slice(0, user.indexOf(":")) : user;
|
|
92480
|
+
const prefix = cleanUser === "" ? "" : `${cleanUser}@`;
|
|
92481
|
+
return {
|
|
92482
|
+
ok: true,
|
|
92483
|
+
raw,
|
|
92484
|
+
url: {
|
|
92485
|
+
scheme: "ssh",
|
|
92486
|
+
href: `${prefix}${host}:${path}`,
|
|
92487
|
+
host,
|
|
92488
|
+
path: path.replace(/^\/+/, ""),
|
|
92489
|
+
insecure: false,
|
|
92490
|
+
scp: true
|
|
92491
|
+
}
|
|
92492
|
+
};
|
|
92493
|
+
}
|
|
92494
|
+
function repoNameOf(url2) {
|
|
92495
|
+
const segments = url2.path.split("/").filter((segment) => segment !== "");
|
|
92496
|
+
const last = segments.at(-1) ?? "";
|
|
92497
|
+
return last.endsWith(".git") ? last.slice(0, -".git".length) : last;
|
|
92498
|
+
}
|
|
92499
|
+
|
|
92500
|
+
// src/pr/exec.ts
|
|
92501
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
92502
|
+
var DEFAULT_GH_TIMEOUT_MS = 2e4;
|
|
92503
|
+
var GH_MAX_BUFFER = 8 * 1024 * 1024;
|
|
92504
|
+
var execGh = (args, { cwd, timeoutMs = DEFAULT_GH_TIMEOUT_MS, bin = "gh" }) => new Promise((resolve6) => {
|
|
92505
|
+
execFile2(
|
|
92506
|
+
bin,
|
|
92507
|
+
[...args],
|
|
92508
|
+
{
|
|
92509
|
+
cwd,
|
|
92510
|
+
timeout: timeoutMs,
|
|
92511
|
+
maxBuffer: GH_MAX_BUFFER,
|
|
92512
|
+
env: {
|
|
92513
|
+
...process.env,
|
|
92514
|
+
// Cor no meio de um JSON é o tipo de coisa que só quebra na máquina de
|
|
92515
|
+
// outra pessoa, que tem `GH_FORCE_TTY` no perfil.
|
|
92516
|
+
NO_COLOR: "1",
|
|
92517
|
+
GH_NO_UPDATE_NOTIFIER: "1",
|
|
92518
|
+
// O `gh` chama o `git`, e o `git` pode pedir credencial. Sem isto, um
|
|
92519
|
+
// remote mal configurado trava o daemon até o timeout.
|
|
92520
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
92521
|
+
}
|
|
92522
|
+
},
|
|
92523
|
+
(error40, stdout, stderr) => {
|
|
92524
|
+
const failure = error40;
|
|
92525
|
+
resolve6({
|
|
92526
|
+
stdout,
|
|
92527
|
+
stderr,
|
|
92528
|
+
code: failure === null ? 0 : typeof failure.code === "number" ? failure.code : null,
|
|
92529
|
+
spawnError: typeof failure?.code === "string" ? failure.code : null,
|
|
92530
|
+
timedOut: failure?.killed === true
|
|
92531
|
+
});
|
|
92532
|
+
}
|
|
92533
|
+
);
|
|
92534
|
+
});
|
|
92535
|
+
var EXIT_AUTH_REQUIRED = 4;
|
|
92536
|
+
var OFFLINE = [
|
|
92537
|
+
"dial tcp",
|
|
92538
|
+
"no such host",
|
|
92539
|
+
"connection refused",
|
|
92540
|
+
"network is unreachable",
|
|
92541
|
+
"i/o timeout",
|
|
92542
|
+
"tls: ",
|
|
92543
|
+
"proxyconnect",
|
|
92544
|
+
"eof"
|
|
92545
|
+
];
|
|
92546
|
+
function classify(result) {
|
|
92547
|
+
if (result.spawnError === "ENOENT") {
|
|
92548
|
+
return {
|
|
92549
|
+
kind: "no-binary",
|
|
92550
|
+
message: "o gh n\xE3o est\xE1 instalado ou n\xE3o est\xE1 no PATH"
|
|
92551
|
+
};
|
|
92552
|
+
}
|
|
92553
|
+
if (result.timedOut) {
|
|
92554
|
+
return { kind: "timeout", message: "o gh n\xE3o respondeu a tempo" };
|
|
92555
|
+
}
|
|
92556
|
+
if (result.spawnError !== null) {
|
|
92557
|
+
return { kind: "failed", message: "n\xE3o deu para executar o gh" };
|
|
92558
|
+
}
|
|
92559
|
+
if (result.code === 0) return null;
|
|
92560
|
+
const stderr = result.stderr.toLowerCase();
|
|
92561
|
+
if (result.code === EXIT_AUTH_REQUIRED || stderr.includes("gh auth login")) {
|
|
92562
|
+
if (stderr.includes("known github host")) {
|
|
92563
|
+
return {
|
|
92564
|
+
kind: "unsupported-host",
|
|
92565
|
+
message: "nenhum remote deste reposit\xF3rio aponta para um host GitHub conhecido"
|
|
92566
|
+
};
|
|
92567
|
+
}
|
|
92568
|
+
return { kind: "no-auth", message: "o gh n\xE3o est\xE1 autenticado" };
|
|
92569
|
+
}
|
|
92570
|
+
if (stderr.includes("rate limit")) {
|
|
92571
|
+
return {
|
|
92572
|
+
kind: "rate-limit",
|
|
92573
|
+
message: "o limite de consultas do GitHub foi atingido",
|
|
92574
|
+
retryAt: parseRetryAt(result.stderr)
|
|
92575
|
+
};
|
|
92576
|
+
}
|
|
92577
|
+
if (stderr.includes("not a git repository")) {
|
|
92578
|
+
return { kind: "not-a-repo", message: "este diret\xF3rio n\xE3o \xE9 um reposit\xF3rio git" };
|
|
92579
|
+
}
|
|
92580
|
+
if (OFFLINE.some((needle) => stderr.includes(needle))) {
|
|
92581
|
+
return { kind: "offline", message: "n\xE3o deu para falar com o GitHub" };
|
|
92582
|
+
}
|
|
92583
|
+
return { kind: "failed", message: "o gh recusou a consulta" };
|
|
92584
|
+
}
|
|
92585
|
+
function parseRetryAt(stderr) {
|
|
92586
|
+
const iso = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)/.exec(stderr);
|
|
92587
|
+
if (iso) return iso[1];
|
|
92588
|
+
const seconds = /retry after (\d+) seconds?/i.exec(stderr);
|
|
92589
|
+
if (seconds) return new Date(Date.now() + Number(seconds[1]) * 1e3).toISOString();
|
|
92590
|
+
return null;
|
|
92591
|
+
}
|
|
92592
|
+
|
|
92593
|
+
// src/pr/url.ts
|
|
92594
|
+
function safeUrl(candidate, host) {
|
|
92595
|
+
if (candidate === null || candidate === void 0 || candidate.trim() === "") return null;
|
|
92596
|
+
if (host === null || host === "") return null;
|
|
92597
|
+
let parsed;
|
|
92598
|
+
try {
|
|
92599
|
+
parsed = new URL(candidate.trim());
|
|
92600
|
+
} catch {
|
|
92601
|
+
return null;
|
|
92602
|
+
}
|
|
92603
|
+
if (parsed.protocol !== "https:") return null;
|
|
92604
|
+
if (parsed.username !== "" || parsed.password !== "") return null;
|
|
92605
|
+
if (parsed.hostname.toLowerCase() !== host.toLowerCase()) return null;
|
|
92606
|
+
return parsed.href;
|
|
92607
|
+
}
|
|
92608
|
+
var NAME_WITH_OWNER = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
92609
|
+
function compareUrl(input) {
|
|
92610
|
+
const { host, repo, base, head } = input;
|
|
92611
|
+
if (host === null || host === "" || base === "" || head === "") return null;
|
|
92612
|
+
if (!NAME_WITH_OWNER.test(repo)) return null;
|
|
92613
|
+
if (base === head) return null;
|
|
92614
|
+
const url2 = `https://${host}/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}?expand=1`;
|
|
92615
|
+
return safeUrl(url2, host);
|
|
92616
|
+
}
|
|
92617
|
+
|
|
92618
|
+
// src/pr/GhHost.ts
|
|
92619
|
+
var DEFAULT_LIMIT = 50;
|
|
92620
|
+
var FIELDS = [
|
|
92621
|
+
"number",
|
|
92622
|
+
"url",
|
|
92623
|
+
"title",
|
|
92624
|
+
"state",
|
|
92625
|
+
"isDraft",
|
|
92626
|
+
"mergeable",
|
|
92627
|
+
"mergeStateStatus",
|
|
92628
|
+
"reviewDecision",
|
|
92629
|
+
"latestReviews",
|
|
92630
|
+
"headRefName",
|
|
92631
|
+
"baseRefName",
|
|
92632
|
+
"updatedAt",
|
|
92633
|
+
"mergedAt",
|
|
92634
|
+
"closedAt",
|
|
92635
|
+
"author",
|
|
92636
|
+
"statusCheckRollup"
|
|
92637
|
+
].join(",");
|
|
92638
|
+
var PROJECTION = [
|
|
92639
|
+
"map({number, url, title, state, isDraft, mergeable, mergeStateStatus, reviewDecision,",
|
|
92640
|
+
"headRefName, baseRefName, updatedAt, mergedAt, closedAt,",
|
|
92641
|
+
'author: (.author.login // ""),',
|
|
92642
|
+
'reviews: [.latestReviews[]? | {author: (.author.login // ""), state: .state}],',
|
|
92643
|
+
"checks: [.statusCheckRollup[]? | {",
|
|
92644
|
+
'name: (.name // .context // ""), app: (.workflowName // .context // ""),',
|
|
92645
|
+
'status: (.status // "COMPLETED"), conclusion: (.conclusion // .state // ""),',
|
|
92646
|
+
'url: (.detailsUrl // .targetUrl // ""),',
|
|
92647
|
+
"startedAt: (.startedAt // null), completedAt: (.completedAt // null)}]})"
|
|
92648
|
+
].join(" ");
|
|
92649
|
+
var REPO_FIELDS = [
|
|
92650
|
+
"nameWithOwner",
|
|
92651
|
+
"mergeCommitAllowed",
|
|
92652
|
+
"squashMergeAllowed",
|
|
92653
|
+
"rebaseMergeAllowed",
|
|
92654
|
+
"deleteBranchOnMerge"
|
|
92655
|
+
].join(",");
|
|
92656
|
+
var CONTROL2 = /[\u0000-\u001f\u007f]/;
|
|
92657
|
+
function createGhHost({ exec = execGh, limit = DEFAULT_LIMIT } = {}) {
|
|
92658
|
+
function hostOf(remoteUrl) {
|
|
92659
|
+
if (remoteUrl === null || remoteUrl.trim() === "") return null;
|
|
92660
|
+
const parsed = parseGitUrl(remoteUrl);
|
|
92661
|
+
if (!parsed.ok) return null;
|
|
92662
|
+
const host = parsed.url.host.split(":")[0] ?? "";
|
|
92663
|
+
return host === "" ? null : host.toLowerCase();
|
|
92664
|
+
}
|
|
92665
|
+
function isGitHub(host) {
|
|
92666
|
+
if (host === null) return false;
|
|
92667
|
+
return host === "github.com" || host.endsWith(".github.com") || host.startsWith("github.");
|
|
92668
|
+
}
|
|
92669
|
+
async function run3(args, cwd) {
|
|
92670
|
+
const result = await exec(args, { cwd });
|
|
92671
|
+
const failure = classify(result);
|
|
92672
|
+
return failure === null ? { ok: true, stdout: result.stdout } : { ok: false, failure };
|
|
92673
|
+
}
|
|
92674
|
+
function unsupported(host) {
|
|
92675
|
+
return {
|
|
92676
|
+
kind: "unsupported-host",
|
|
92677
|
+
message: host === null ? "este reposit\xF3rio n\xE3o tem um remote conhecido" : `o Lumem ainda n\xE3o fala com ${host}`
|
|
92678
|
+
};
|
|
92679
|
+
}
|
|
92680
|
+
function flag(name, value) {
|
|
92681
|
+
return `--${name}=${value}`;
|
|
92682
|
+
}
|
|
92683
|
+
function refuseControl(value, what) {
|
|
92684
|
+
return CONTROL2.test(value) ? { kind: "failed", message: `o ${what} tem caracteres de controle` } : null;
|
|
92685
|
+
}
|
|
92686
|
+
return {
|
|
92687
|
+
name: "GitHub",
|
|
92688
|
+
supports(remoteUrl) {
|
|
92689
|
+
return isGitHub(hostOf(remoteUrl));
|
|
92690
|
+
},
|
|
92691
|
+
async read({ repoPath, remoteUrl }) {
|
|
92692
|
+
const host = hostOf(remoteUrl);
|
|
92693
|
+
if (!isGitHub(host)) return { ok: false, failure: unsupported(host) };
|
|
92694
|
+
const [pulls, repo] = await Promise.all([
|
|
92695
|
+
run3(
|
|
92696
|
+
[
|
|
92697
|
+
"pr",
|
|
92698
|
+
"list",
|
|
92699
|
+
"--state",
|
|
92700
|
+
"all",
|
|
92701
|
+
"--limit",
|
|
92702
|
+
String(limit),
|
|
92703
|
+
"--json",
|
|
92704
|
+
FIELDS,
|
|
92705
|
+
"--jq",
|
|
92706
|
+
PROJECTION
|
|
92707
|
+
],
|
|
92708
|
+
repoPath
|
|
92709
|
+
),
|
|
92710
|
+
run3(["repo", "view", "--json", REPO_FIELDS], repoPath)
|
|
92711
|
+
]);
|
|
92712
|
+
if (!pulls.ok) return pulls;
|
|
92713
|
+
if (!repo.ok) return repo;
|
|
92714
|
+
const parsed = parseJson(pulls.stdout, []);
|
|
92715
|
+
const settings = parseJson(repo.stdout, {});
|
|
92716
|
+
if (parsed === null || settings === null) {
|
|
92717
|
+
return {
|
|
92718
|
+
ok: false,
|
|
92719
|
+
failure: { kind: "failed", message: "o gh respondeu algo que n\xE3o \xE9 JSON" }
|
|
92720
|
+
};
|
|
92721
|
+
}
|
|
92722
|
+
return {
|
|
92723
|
+
ok: true,
|
|
92724
|
+
snapshot: {
|
|
92725
|
+
host: host ?? "",
|
|
92726
|
+
repo: typeof settings.nameWithOwner === "string" ? settings.nameWithOwner : "",
|
|
92727
|
+
pulls: parsed,
|
|
92728
|
+
merge: mergeOptionsOf(settings),
|
|
92729
|
+
readAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
92730
|
+
}
|
|
92731
|
+
};
|
|
92732
|
+
},
|
|
92733
|
+
async create(input) {
|
|
92734
|
+
const host = hostOf(input.remoteUrl);
|
|
92735
|
+
if (!isGitHub(host)) return { ok: false, failure: unsupported(host) };
|
|
92736
|
+
const bad = refuseControl(input.title, "t\xEDtulo") ?? refuseControl(input.base, "nome da base") ?? refuseControl(input.head, "nome da branch");
|
|
92737
|
+
if (bad !== null) return { ok: false, failure: bad };
|
|
92738
|
+
if (input.title.trim() === "") {
|
|
92739
|
+
return { ok: false, failure: { kind: "failed", message: "a PR precisa de um t\xEDtulo" } };
|
|
92740
|
+
}
|
|
92741
|
+
const dir = await mkdtemp(join15(tmpdir(), "lumem-pr-"));
|
|
92742
|
+
const bodyFile = join15(dir, "body.md");
|
|
92743
|
+
try {
|
|
92744
|
+
await writeFile4(bodyFile, input.body, "utf8");
|
|
92745
|
+
const args = [
|
|
92746
|
+
"pr",
|
|
92747
|
+
"create",
|
|
92748
|
+
flag("base", input.base),
|
|
92749
|
+
flag("head", input.head),
|
|
92750
|
+
flag("title", input.title),
|
|
92751
|
+
flag("body-file", bodyFile)
|
|
92752
|
+
];
|
|
92753
|
+
if (input.draft) args.push("--draft");
|
|
92754
|
+
const result = await run3(args, input.repoPath);
|
|
92755
|
+
if (!result.ok) return { ok: false, failure: createFailure(result.failure) };
|
|
92756
|
+
const printed = result.stdout.trim().split("\n").at(-1)?.trim() ?? "";
|
|
92757
|
+
return { ok: true, url: safeUrl(printed, host) ?? "" };
|
|
92758
|
+
} finally {
|
|
92759
|
+
await rm4(dir, { recursive: true, force: true });
|
|
92760
|
+
}
|
|
92761
|
+
},
|
|
92762
|
+
async merge(input) {
|
|
92763
|
+
const host = hostOf(input.remoteUrl);
|
|
92764
|
+
if (!isGitHub(host)) return { ok: false, failure: unsupported(host) };
|
|
92765
|
+
if (!Number.isInteger(input.number) || input.number <= 0) {
|
|
92766
|
+
return { ok: false, failure: { kind: "failed", message: "n\xFAmero de PR inv\xE1lido" } };
|
|
92767
|
+
}
|
|
92768
|
+
const args = ["pr", "merge", String(input.number), `--${input.strategy}`];
|
|
92769
|
+
if (input.deleteBranch) args.push("--delete-branch");
|
|
92770
|
+
const result = await run3(args, input.repoPath);
|
|
92771
|
+
if (!result.ok) return { ok: false, failure: mergeFailure(result.failure) };
|
|
92772
|
+
return { ok: true, url: "" };
|
|
92773
|
+
}
|
|
92774
|
+
};
|
|
92775
|
+
}
|
|
92776
|
+
function createFailure(failure) {
|
|
92777
|
+
if (failure.kind !== "failed") return failure;
|
|
92778
|
+
return { kind: "failed", message: "o GitHub recusou criar a pull request" };
|
|
92779
|
+
}
|
|
92780
|
+
function mergeFailure(failure) {
|
|
92781
|
+
if (failure.kind !== "failed") return failure;
|
|
92782
|
+
return { kind: "failed", message: "o GitHub recusou o merge" };
|
|
92783
|
+
}
|
|
92784
|
+
function mergeOptionsOf(settings) {
|
|
92785
|
+
const flagOf = (key) => settings[key] === true;
|
|
92786
|
+
const options = {
|
|
92787
|
+
merge: flagOf("mergeCommitAllowed"),
|
|
92788
|
+
squash: flagOf("squashMergeAllowed"),
|
|
92789
|
+
rebase: flagOf("rebaseMergeAllowed"),
|
|
92790
|
+
deleteBranchOnMerge: flagOf("deleteBranchOnMerge")
|
|
92791
|
+
};
|
|
92792
|
+
if (!options.merge && !options.squash && !options.rebase) {
|
|
92793
|
+
return { ...options, merge: true };
|
|
92794
|
+
}
|
|
92795
|
+
return options;
|
|
92796
|
+
}
|
|
92797
|
+
function parseJson(stdout, whenEmpty) {
|
|
92798
|
+
const text2 = stdout.trim();
|
|
92799
|
+
if (text2 === "") return whenEmpty;
|
|
92800
|
+
try {
|
|
92801
|
+
return JSON.parse(text2);
|
|
92802
|
+
} catch {
|
|
92803
|
+
return null;
|
|
92804
|
+
}
|
|
92805
|
+
}
|
|
92806
|
+
|
|
92807
|
+
// src/pr/verdict.ts
|
|
92808
|
+
var PASSED = /* @__PURE__ */ new Set(["SUCCESS", "NEUTRAL"]);
|
|
92809
|
+
var SKIPPED = /* @__PURE__ */ new Set(["SKIPPED", "STALE"]);
|
|
92810
|
+
var FAILED = /* @__PURE__ */ new Set([
|
|
92811
|
+
"FAILURE",
|
|
92812
|
+
"TIMED_OUT",
|
|
92813
|
+
"CANCELLED",
|
|
92814
|
+
"ACTION_REQUIRED",
|
|
92815
|
+
"STARTUP_FAILURE",
|
|
92816
|
+
"ERROR"
|
|
92817
|
+
]);
|
|
92818
|
+
function groupOf(check3) {
|
|
92819
|
+
const status = check3.status.toUpperCase();
|
|
92820
|
+
if (status !== "COMPLETED" && status !== "SUCCESS" && status !== "FAILURE") {
|
|
92821
|
+
return "running";
|
|
92822
|
+
}
|
|
92823
|
+
const conclusion = check3.conclusion.toUpperCase();
|
|
92824
|
+
if (PASSED.has(conclusion)) return "passed";
|
|
92825
|
+
if (SKIPPED.has(conclusion)) return "skipped";
|
|
92826
|
+
if (FAILED.has(conclusion)) return "failed";
|
|
92827
|
+
return "running";
|
|
92828
|
+
}
|
|
92829
|
+
function countChecks(checks) {
|
|
92830
|
+
const counts = { failed: 0, running: 0, passed: 0, skipped: 0 };
|
|
92831
|
+
for (const check3 of checks) counts[groupOf(check3)] += 1;
|
|
92832
|
+
return counts;
|
|
92833
|
+
}
|
|
92834
|
+
function queuedCount(checks) {
|
|
92835
|
+
return checks.filter((check3) => {
|
|
92836
|
+
const status = check3.status.toUpperCase();
|
|
92837
|
+
return status === "QUEUED" || status === "WAITING" || status === "REQUESTED";
|
|
92838
|
+
}).length;
|
|
92839
|
+
}
|
|
92840
|
+
function namesOf(checks, group) {
|
|
92841
|
+
return checks.filter((check3) => groupOf(check3) === group).map((check3) => check3.name);
|
|
92842
|
+
}
|
|
92843
|
+
function changesRequestedBy(reviews) {
|
|
92844
|
+
return reviews.filter((review) => review.state.toUpperCase() === "CHANGES_REQUESTED").map((review) => review.author);
|
|
92845
|
+
}
|
|
92846
|
+
function approvedBy(reviews) {
|
|
92847
|
+
return reviews.filter((review) => review.state.toUpperCase() === "APPROVED").map((review) => review.author);
|
|
92848
|
+
}
|
|
92849
|
+
function decide2(pr) {
|
|
92850
|
+
const state = pr.state.toUpperCase();
|
|
92851
|
+
if (state === "MERGED") {
|
|
92852
|
+
return { verdict: "merged", reason: { kind: "merged", base: pr.baseRefName } };
|
|
92853
|
+
}
|
|
92854
|
+
if (state === "CLOSED") {
|
|
92855
|
+
return { verdict: "closed", reason: { kind: "closed" } };
|
|
92856
|
+
}
|
|
92857
|
+
const counts = countChecks(pr.checks);
|
|
92858
|
+
if (pr.isDraft) {
|
|
92859
|
+
return { verdict: "draft", reason: { kind: "draft", passed: counts.passed } };
|
|
92860
|
+
}
|
|
92861
|
+
const mergeable = pr.mergeable.toUpperCase();
|
|
92862
|
+
const mergeState = pr.mergeStateStatus.toUpperCase();
|
|
92863
|
+
if (mergeable === "CONFLICTING" || mergeState === "DIRTY") {
|
|
92864
|
+
return { verdict: "blocked", reason: { kind: "conflict", base: pr.baseRefName } };
|
|
92865
|
+
}
|
|
92866
|
+
if (counts.failed > 0) {
|
|
92867
|
+
return {
|
|
92868
|
+
verdict: "blocked",
|
|
92869
|
+
reason: { kind: "checks-failed", names: namesOf(pr.checks, "failed") }
|
|
92870
|
+
};
|
|
92871
|
+
}
|
|
92872
|
+
const requested = changesRequestedBy(pr.reviews);
|
|
92873
|
+
if (pr.reviewDecision.toUpperCase() === "CHANGES_REQUESTED" || requested.length > 0) {
|
|
92874
|
+
return { verdict: "blocked", reason: { kind: "changes-requested", by: requested } };
|
|
92875
|
+
}
|
|
92876
|
+
if (pr.reviewDecision.toUpperCase() === "REVIEW_REQUIRED") {
|
|
92877
|
+
return { verdict: "blocked", reason: { kind: "review-required" } };
|
|
92878
|
+
}
|
|
92879
|
+
if (mergeState === "BEHIND") {
|
|
92880
|
+
return { verdict: "blocked", reason: { kind: "behind", base: pr.baseRefName } };
|
|
92881
|
+
}
|
|
92882
|
+
if (counts.running > 0) {
|
|
92883
|
+
return {
|
|
92884
|
+
verdict: "pending",
|
|
92885
|
+
reason: {
|
|
92886
|
+
kind: "checks-running",
|
|
92887
|
+
names: namesOf(pr.checks, "running"),
|
|
92888
|
+
running: counts.running - queuedCount(pr.checks),
|
|
92889
|
+
queued: queuedCount(pr.checks)
|
|
92890
|
+
}
|
|
92891
|
+
};
|
|
92892
|
+
}
|
|
92893
|
+
if (mergeState === "BLOCKED") {
|
|
92894
|
+
return { verdict: "blocked", reason: { kind: "blocked-by-host" } };
|
|
92895
|
+
}
|
|
92896
|
+
if (mergeable !== "MERGEABLE") {
|
|
92897
|
+
return { verdict: "pending", reason: { kind: "mergeability-unknown" } };
|
|
92898
|
+
}
|
|
92899
|
+
if (mergeState !== "CLEAN" && mergeState !== "UNSTABLE" && mergeState !== "HAS_HOOKS") {
|
|
92900
|
+
return { verdict: "pending", reason: { kind: "mergeability-unknown" } };
|
|
92901
|
+
}
|
|
92902
|
+
return {
|
|
92903
|
+
verdict: "ready",
|
|
92904
|
+
reason: { kind: "ready", passed: counts.passed, approvedBy: approvedBy(pr.reviews) }
|
|
92905
|
+
};
|
|
92906
|
+
}
|
|
92907
|
+
|
|
92908
|
+
// src/pr/PrCache.ts
|
|
92909
|
+
var TTL_BUSY_MS = 15e3;
|
|
92910
|
+
var TTL_IDLE_MS = 6e4;
|
|
92911
|
+
var BACKOFF_START_MS = TTL_IDLE_MS;
|
|
92912
|
+
var BACKOFF_MAX_MS = 6e5;
|
|
92913
|
+
function createPrCache({
|
|
92914
|
+
host,
|
|
92915
|
+
now = () => Date.now(),
|
|
92916
|
+
onChange
|
|
92917
|
+
}) {
|
|
92918
|
+
const slots = /* @__PURE__ */ new Map();
|
|
92919
|
+
let reads = 0;
|
|
92920
|
+
function slotOf(projectId) {
|
|
92921
|
+
const existing = slots.get(projectId);
|
|
92922
|
+
if (existing) return existing;
|
|
92923
|
+
const fresh = {
|
|
92924
|
+
snapshot: null,
|
|
92925
|
+
failure: null,
|
|
92926
|
+
readAt: null,
|
|
92927
|
+
freshUntil: 0,
|
|
92928
|
+
failures: 0,
|
|
92929
|
+
inFlight: null,
|
|
92930
|
+
want: 0,
|
|
92931
|
+
served: 0
|
|
92932
|
+
};
|
|
92933
|
+
slots.set(projectId, fresh);
|
|
92934
|
+
return fresh;
|
|
92935
|
+
}
|
|
92936
|
+
function viewOf2(slot) {
|
|
92937
|
+
return { snapshot: slot.snapshot, failure: slot.failure, readAt: slot.readAt };
|
|
92938
|
+
}
|
|
92939
|
+
function ttlOf(slot) {
|
|
92940
|
+
if (slot.failures > 0) {
|
|
92941
|
+
return Math.min(BACKOFF_START_MS * 2 ** (slot.failures - 1), BACKOFF_MAX_MS);
|
|
92942
|
+
}
|
|
92943
|
+
const pulls = slot.snapshot?.pulls ?? [];
|
|
92944
|
+
const busy = pulls.some(
|
|
92945
|
+
(pull) => pull.state.toUpperCase() === "OPEN" && countChecks(pull.checks).running > 0
|
|
92946
|
+
);
|
|
92947
|
+
return busy ? TTL_BUSY_MS : TTL_IDLE_MS;
|
|
92948
|
+
}
|
|
92949
|
+
async function fetch(project2, slot, want) {
|
|
92950
|
+
reads += 1;
|
|
92951
|
+
try {
|
|
92952
|
+
const read = await host.read({ repoPath: project2.path, remoteUrl: project2.remoteUrl });
|
|
92953
|
+
if (read.ok) {
|
|
92954
|
+
const changed = digestOf(slot.snapshot) !== digestOf(read.snapshot);
|
|
92955
|
+
slot.snapshot = read.snapshot;
|
|
92956
|
+
slot.failure = null;
|
|
92957
|
+
slot.readAt = read.snapshot.readAt;
|
|
92958
|
+
slot.failures = 0;
|
|
92959
|
+
if (changed) onChange?.(project2.id);
|
|
92960
|
+
} else {
|
|
92961
|
+
slot.failure = read.failure;
|
|
92962
|
+
slot.failures += 1;
|
|
92963
|
+
}
|
|
92964
|
+
} catch {
|
|
92965
|
+
slot.failure = { kind: "failed", message: "n\xE3o deu para consultar o host" };
|
|
92966
|
+
slot.failures += 1;
|
|
92967
|
+
} finally {
|
|
92968
|
+
slot.freshUntil = now() + ttlOf(slot);
|
|
92969
|
+
slot.served = Math.max(slot.served, want);
|
|
92970
|
+
}
|
|
92971
|
+
return viewOf2(slot);
|
|
92972
|
+
}
|
|
92973
|
+
function start(project2, slot) {
|
|
92974
|
+
const current = slot.inFlight;
|
|
92975
|
+
if (current !== null) {
|
|
92976
|
+
if (current.want >= slot.want) return current.promise;
|
|
92977
|
+
return current.promise.then(() => start(project2, slot));
|
|
92978
|
+
}
|
|
92979
|
+
const holder = { want: slot.want, promise: Promise.resolve(viewOf2(slot)) };
|
|
92980
|
+
holder.promise = fetch(project2, slot, holder.want).finally(() => {
|
|
92981
|
+
if (slot.inFlight === holder) slot.inFlight = null;
|
|
92982
|
+
});
|
|
92983
|
+
slot.inFlight = holder;
|
|
92984
|
+
return holder.promise;
|
|
92985
|
+
}
|
|
92986
|
+
return {
|
|
92987
|
+
get(project2) {
|
|
92988
|
+
const slot = slotOf(project2.id);
|
|
92989
|
+
const known = slot.snapshot !== null || slot.failure !== null;
|
|
92990
|
+
if (!known || slot.want > slot.served) return start(project2, slot);
|
|
92991
|
+
if (now() < slot.freshUntil) return Promise.resolve(viewOf2(slot));
|
|
92992
|
+
void start(project2, slot).catch(() => void 0);
|
|
92993
|
+
return Promise.resolve(viewOf2(slot));
|
|
92994
|
+
},
|
|
92995
|
+
invalidate(projectId) {
|
|
92996
|
+
const slot = slots.get(projectId);
|
|
92997
|
+
if (!slot) return;
|
|
92998
|
+
slot.freshUntil = 0;
|
|
92999
|
+
slot.want += 1;
|
|
93000
|
+
slot.failures = 0;
|
|
93001
|
+
},
|
|
93002
|
+
forget(projectId) {
|
|
93003
|
+
slots.delete(projectId);
|
|
93004
|
+
},
|
|
93005
|
+
get reads() {
|
|
93006
|
+
return reads;
|
|
93007
|
+
}
|
|
93008
|
+
};
|
|
93009
|
+
}
|
|
93010
|
+
function digestOf(snapshot) {
|
|
93011
|
+
if (snapshot === null) return "";
|
|
93012
|
+
const { readAt: _ignored, ...rest } = snapshot;
|
|
93013
|
+
return JSON.stringify(rest);
|
|
93014
|
+
}
|
|
93015
|
+
|
|
92054
93016
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs
|
|
92055
93017
|
var import_stream2 = __toESM(require_stream(), 1);
|
|
92056
93018
|
var import_extension = __toESM(require_extension(), 1);
|
|
@@ -92143,6 +93105,13 @@ function registerAcpWebSocket({
|
|
|
92143
93105
|
// with empty dropdowns until the agent happened to mention something would
|
|
92144
93106
|
// look broken for as long as nothing did.
|
|
92145
93107
|
configOptions: [...info.configOptions],
|
|
93108
|
+
// Who owns the mode selector, and what the policy is set to — on attach for
|
|
93109
|
+
// the same reason `configOptions` is: a composer whose mode pill appeared
|
|
93110
|
+
// only once something changed would look broken for as long as nothing did.
|
|
93111
|
+
modeOwner: modeOwnerOf(info),
|
|
93112
|
+
lumemMode: info.lumemMode,
|
|
93113
|
+
lumemModeDefault: info.lumemModeDefault,
|
|
93114
|
+
cwd: info.cwd,
|
|
92146
93115
|
transcript: [...acpManager.transcript(sessionId)]
|
|
92147
93116
|
});
|
|
92148
93117
|
const offEvent = acpManager.onEvent(
|
|
@@ -92177,6 +93146,10 @@ function registerAcpWebSocket({
|
|
|
92177
93146
|
});
|
|
92178
93147
|
return;
|
|
92179
93148
|
}
|
|
93149
|
+
if (message.type === "set_lumem_mode") {
|
|
93150
|
+
acpManager.setLumemMode(sessionId, message.mode);
|
|
93151
|
+
return;
|
|
93152
|
+
}
|
|
92180
93153
|
acpManager.respondToPermission(sessionId, message.requestId, message.optionId);
|
|
92181
93154
|
} catch (error40) {
|
|
92182
93155
|
reportFailure(error40, message.type);
|
|
@@ -92205,8 +93178,8 @@ function registerAcpWebSocket({
|
|
|
92205
93178
|
});
|
|
92206
93179
|
app.addHook("onClose", async () => {
|
|
92207
93180
|
for (const client2 of wss.clients) client2.close(CLOSE_GOING_AWAY, "daemon shutting down");
|
|
92208
|
-
await new Promise((
|
|
92209
|
-
wss.close(() =>
|
|
93181
|
+
await new Promise((resolve6) => {
|
|
93182
|
+
wss.close(() => resolve6());
|
|
92210
93183
|
});
|
|
92211
93184
|
});
|
|
92212
93185
|
}
|
|
@@ -92599,8 +93572,8 @@ function registerPtyWebSocket({
|
|
|
92599
93572
|
});
|
|
92600
93573
|
app.addHook("onClose", async () => {
|
|
92601
93574
|
for (const client2 of wss.clients) client2.close(CLOSE_GOING_AWAY2, "daemon shutting down");
|
|
92602
|
-
await new Promise((
|
|
92603
|
-
wss.close(() =>
|
|
93575
|
+
await new Promise((resolve6) => {
|
|
93576
|
+
wss.close(() => resolve6());
|
|
92604
93577
|
});
|
|
92605
93578
|
});
|
|
92606
93579
|
}
|
|
@@ -92608,12 +93581,12 @@ function registerPtyWebSocket({
|
|
|
92608
93581
|
// src/web/static.ts
|
|
92609
93582
|
var import_static = __toESM(require_static(), 1);
|
|
92610
93583
|
import { existsSync as existsSync4 } from "node:fs";
|
|
92611
|
-
import { join as
|
|
93584
|
+
import { join as join16 } from "node:path";
|
|
92612
93585
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
92613
93586
|
var DAEMON_PREFIXES = ["/trpc", "/pty", "/acp", "/memory"];
|
|
92614
93587
|
function resolveWebRoot(override = null) {
|
|
92615
93588
|
const candidate = override ?? fileURLToPath2(new URL("../web/", import.meta.url));
|
|
92616
|
-
return existsSync4(
|
|
93589
|
+
return existsSync4(join16(candidate, "index.html")) ? candidate : null;
|
|
92617
93590
|
}
|
|
92618
93591
|
var IMMUTABLE = "public, max-age=31536000, immutable";
|
|
92619
93592
|
var REVALIDATE = "no-cache";
|
|
@@ -93276,14 +94249,305 @@ var memoryRouter = router({
|
|
|
93276
94249
|
)
|
|
93277
94250
|
});
|
|
93278
94251
|
|
|
94252
|
+
// src/pr/view.ts
|
|
94253
|
+
var GROUP_ORDER = { failed: 0, running: 1, passed: 2, skipped: 3 };
|
|
94254
|
+
function durationOf(check3) {
|
|
94255
|
+
if (check3.startedAt === null) return null;
|
|
94256
|
+
const start = Date.parse(check3.startedAt);
|
|
94257
|
+
const end = check3.completedAt === null ? Date.now() : Date.parse(check3.completedAt);
|
|
94258
|
+
if (Number.isNaN(start) || Number.isNaN(end)) return null;
|
|
94259
|
+
return Math.max(0, end - start);
|
|
94260
|
+
}
|
|
94261
|
+
function checkViewOf(check3, host) {
|
|
94262
|
+
return {
|
|
94263
|
+
name: check3.name,
|
|
94264
|
+
app: check3.app,
|
|
94265
|
+
group: groupOf(check3),
|
|
94266
|
+
url: safeUrl(check3.url, host),
|
|
94267
|
+
durationMs: durationOf(check3)
|
|
94268
|
+
};
|
|
94269
|
+
}
|
|
94270
|
+
function viewOf({ pull, host, alsoOpen }) {
|
|
94271
|
+
const { verdict, reason } = decide2(pull);
|
|
94272
|
+
const checks = pull.checks.map((check3) => checkViewOf(check3, host)).sort((a, b) => GROUP_ORDER[a.group] - GROUP_ORDER[b.group]);
|
|
94273
|
+
return {
|
|
94274
|
+
number: pull.number,
|
|
94275
|
+
url: safeUrl(pull.url, host),
|
|
94276
|
+
title: pull.title,
|
|
94277
|
+
verdict,
|
|
94278
|
+
reason,
|
|
94279
|
+
counts: countChecks(pull.checks),
|
|
94280
|
+
checks,
|
|
94281
|
+
base: pull.baseRefName,
|
|
94282
|
+
head: pull.headRefName,
|
|
94283
|
+
updatedAt: pull.updatedAt,
|
|
94284
|
+
author: pull.author,
|
|
94285
|
+
alsoOpen
|
|
94286
|
+
};
|
|
94287
|
+
}
|
|
94288
|
+
var CLOSED_PR_MAX_AGE_DAYS = 30;
|
|
94289
|
+
function pickForBranch(pulls, branch, now = Date.now()) {
|
|
94290
|
+
const mine = pulls.filter((pull) => pull.headRefName === branch);
|
|
94291
|
+
if (mine.length === 0) return null;
|
|
94292
|
+
const open = mine.filter((pull) => pull.state.toUpperCase() === "OPEN");
|
|
94293
|
+
const recent = (pull) => {
|
|
94294
|
+
const at = Date.parse(pull.updatedAt);
|
|
94295
|
+
if (Number.isNaN(at)) return false;
|
|
94296
|
+
return now - at <= CLOSED_PR_MAX_AGE_DAYS * 24 * 60 * 60 * 1e3;
|
|
94297
|
+
};
|
|
94298
|
+
const byUpdated = (a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt);
|
|
94299
|
+
if (open.length > 0) {
|
|
94300
|
+
const [first2] = [...open].sort(byUpdated);
|
|
94301
|
+
return { pull: first2, alsoOpen: open.length - 1 };
|
|
94302
|
+
}
|
|
94303
|
+
const closed = mine.filter(recent).sort(byUpdated);
|
|
94304
|
+
const [first] = closed;
|
|
94305
|
+
return first === void 0 ? null : { pull: first, alsoOpen: 0 };
|
|
94306
|
+
}
|
|
94307
|
+
|
|
94308
|
+
// src/routers/pr.ts
|
|
94309
|
+
var worktreeInput = external_exports.object({ worktreeId: external_exports.string().min(1) });
|
|
94310
|
+
var projectInput = external_exports.object({ projectId: external_exports.string().min(1) });
|
|
94311
|
+
var strategySchema = external_exports.enum(["merge", "squash", "rebase"]);
|
|
94312
|
+
async function remoteOf(ctx, project2) {
|
|
94313
|
+
return project2.remoteUrl ?? await ctx.git.getRemoteUrl(project2.path);
|
|
94314
|
+
}
|
|
94315
|
+
async function checkoutOf(ctx, worktreeId) {
|
|
94316
|
+
const worktree2 = await createWorktreeRepository(ctx.db).findById(worktreeId);
|
|
94317
|
+
if (!worktree2) throw new DomainError("NOT_FOUND", `worktree ${worktreeId} n\xE3o existe`);
|
|
94318
|
+
if (worktree2.state === "missing") {
|
|
94319
|
+
throw new DomainError("BLOCKED", `a worktree "${worktree2.name}" n\xE3o est\xE1 no disco`);
|
|
94320
|
+
}
|
|
94321
|
+
const project2 = await createProjectRepository(ctx.db).findById(worktree2.projectId);
|
|
94322
|
+
if (!project2) {
|
|
94323
|
+
throw new DomainError("NOT_FOUND", `projeto ${worktree2.projectId} n\xE3o existe`);
|
|
94324
|
+
}
|
|
94325
|
+
return {
|
|
94326
|
+
project: { id: project2.id, path: project2.path, remoteUrl: await remoteOf(ctx, project2) },
|
|
94327
|
+
branch: worktree2.branch,
|
|
94328
|
+
base: project2.defaultBranch,
|
|
94329
|
+
cwd: worktree2.path
|
|
94330
|
+
};
|
|
94331
|
+
}
|
|
94332
|
+
function failureViewOf(entry) {
|
|
94333
|
+
if (entry.failure === null) return null;
|
|
94334
|
+
return {
|
|
94335
|
+
kind: entry.failure.kind,
|
|
94336
|
+
message: entry.failure.message,
|
|
94337
|
+
retryAt: entry.failure.retryAt ?? null
|
|
94338
|
+
};
|
|
94339
|
+
}
|
|
94340
|
+
var NO_MERGE_OPTIONS = {
|
|
94341
|
+
merge: false,
|
|
94342
|
+
squash: false,
|
|
94343
|
+
rebase: false,
|
|
94344
|
+
deleteBranchOnMerge: false
|
|
94345
|
+
};
|
|
94346
|
+
var prRouter = router({
|
|
94347
|
+
/**
|
|
94348
|
+
* A barra, inteira, numa leitura só.
|
|
94349
|
+
*
|
|
94350
|
+
* Ela precisa de sete coisas que vêm de três lugares — o host, o git local e
|
|
94351
|
+
* o banco —, e pedi-las em três chamadas daria três respostas de instantes
|
|
94352
|
+
* diferentes na mesma barra.
|
|
94353
|
+
*/
|
|
94354
|
+
getByWorktree: publicProcedure.input(worktreeInput).query(
|
|
94355
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94356
|
+
const checkout = await checkoutOf(ctx, input.worktreeId);
|
|
94357
|
+
const [entry, published] = await Promise.all([
|
|
94358
|
+
ctx.pr.get(checkout.project),
|
|
94359
|
+
// Barato e local: lê a referência de rastreamento do disco. É o que
|
|
94360
|
+
// separa "sem pull request" de "branch não publicada" — as duas neutras,
|
|
94361
|
+
// e dizer a errada manda a pessoa procurar uma PR que não podia existir.
|
|
94362
|
+
ctx.git.hasRemoteBranch(checkout.cwd, checkout.branch)
|
|
94363
|
+
]);
|
|
94364
|
+
const snapshot = entry.snapshot;
|
|
94365
|
+
const host = snapshot?.host ?? null;
|
|
94366
|
+
const picked = snapshot === null ? null : pickForBranch(snapshot.pulls, checkout.branch);
|
|
94367
|
+
return {
|
|
94368
|
+
pull: picked === null ? null : viewOf({ pull: picked.pull, host, alsoOpen: picked.alsoOpen }),
|
|
94369
|
+
failure: failureViewOf(entry),
|
|
94370
|
+
readAt: entry.readAt,
|
|
94371
|
+
host,
|
|
94372
|
+
branch: checkout.branch,
|
|
94373
|
+
base: checkout.base,
|
|
94374
|
+
published,
|
|
94375
|
+
compareUrl: snapshot === null ? null : compareUrl({
|
|
94376
|
+
host,
|
|
94377
|
+
repo: snapshot.repo,
|
|
94378
|
+
base: checkout.base,
|
|
94379
|
+
head: checkout.branch
|
|
94380
|
+
}),
|
|
94381
|
+
merge: snapshot?.merge ?? NO_MERGE_OPTIONS
|
|
94382
|
+
};
|
|
94383
|
+
})
|
|
94384
|
+
),
|
|
94385
|
+
/**
|
|
94386
|
+
* Os marcadores da sidebar, num pedido só.
|
|
94387
|
+
*
|
|
94388
|
+
* F3.1 e F3.3: N worktrees não fazem N consultas, e a cor sai do **mesmo**
|
|
94389
|
+
* veredito da barra. Worktree sem PR não entra na lista — marcador cinza em
|
|
94390
|
+
* cinco linhas ensina o olho a ignorar a coluna inteira (Q9).
|
|
94391
|
+
*/
|
|
94392
|
+
listByProject: publicProcedure.input(projectInput).query(
|
|
94393
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94394
|
+
const project2 = await createProjectRepository(ctx.db).findById(input.projectId);
|
|
94395
|
+
if (!project2) throw new DomainError("NOT_FOUND", `projeto ${input.projectId} n\xE3o existe`);
|
|
94396
|
+
const entry = await ctx.pr.get({
|
|
94397
|
+
id: project2.id,
|
|
94398
|
+
path: project2.path,
|
|
94399
|
+
remoteUrl: await remoteOf(ctx, project2)
|
|
94400
|
+
});
|
|
94401
|
+
const snapshot = entry.snapshot;
|
|
94402
|
+
if (snapshot === null) return [];
|
|
94403
|
+
const worktrees = await createWorktreeRepository(ctx.db).listByProject(project2.id);
|
|
94404
|
+
return worktrees.flatMap((worktree2) => {
|
|
94405
|
+
const picked = pickForBranch(snapshot.pulls, worktree2.branch);
|
|
94406
|
+
if (picked === null) return [];
|
|
94407
|
+
const view = viewOf({ pull: picked.pull, host: snapshot.host, alsoOpen: picked.alsoOpen });
|
|
94408
|
+
return [{ worktreeId: worktree2.id, number: view.number, verdict: view.verdict }];
|
|
94409
|
+
});
|
|
94410
|
+
})
|
|
94411
|
+
),
|
|
94412
|
+
/**
|
|
94413
|
+
* F7 — mesclar.
|
|
94414
|
+
*
|
|
94415
|
+
* O portão é o veredito, e ele é **relido aqui** (F7.2). Recusar só na tela
|
|
94416
|
+
* seria conforto: quem garante é a procedure, e o teste que a prova chama
|
|
94417
|
+
* daqui, sem passar pelo botão.
|
|
94418
|
+
*/
|
|
94419
|
+
merge: publicProcedure.input(worktreeInput.extend({ strategy: strategySchema, deleteBranch: external_exports.boolean() })).mutation(
|
|
94420
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94421
|
+
const checkout = await checkoutOf(ctx, input.worktreeId);
|
|
94422
|
+
ctx.pr.invalidate(checkout.project.id);
|
|
94423
|
+
const entry = await ctx.pr.get(checkout.project);
|
|
94424
|
+
const snapshot = entry.snapshot;
|
|
94425
|
+
if (entry.failure !== null) {
|
|
94426
|
+
throw new DomainError(
|
|
94427
|
+
"BLOCKED",
|
|
94428
|
+
`n\xE3o deu para confirmar o estado da pull request: ${entry.failure.message}`
|
|
94429
|
+
);
|
|
94430
|
+
}
|
|
94431
|
+
if (snapshot === null) {
|
|
94432
|
+
throw new DomainError("BLOCKED", "n\xE3o deu para ler o estado da pull request");
|
|
94433
|
+
}
|
|
94434
|
+
const picked = pickForBranch(snapshot.pulls, checkout.branch);
|
|
94435
|
+
if (picked === null) {
|
|
94436
|
+
throw new DomainError("NOT_FOUND", "esta worktree n\xE3o tem pull request");
|
|
94437
|
+
}
|
|
94438
|
+
const view = viewOf({ pull: picked.pull, host: snapshot.host, alsoOpen: picked.alsoOpen });
|
|
94439
|
+
if (view.verdict !== "ready") {
|
|
94440
|
+
throw new DomainError(
|
|
94441
|
+
"BLOCKED",
|
|
94442
|
+
`a pull request #${String(view.number)} n\xE3o est\xE1 pronta para merge`
|
|
94443
|
+
);
|
|
94444
|
+
}
|
|
94445
|
+
if (!allows(snapshot.merge, input.strategy)) {
|
|
94446
|
+
throw new DomainError(
|
|
94447
|
+
"BLOCKED",
|
|
94448
|
+
`o reposit\xF3rio n\xE3o permite merge por ${input.strategy}`
|
|
94449
|
+
);
|
|
94450
|
+
}
|
|
94451
|
+
const write = await ctx.prHost.merge({
|
|
94452
|
+
repoPath: checkout.cwd,
|
|
94453
|
+
remoteUrl: checkout.project.remoteUrl,
|
|
94454
|
+
// Do cache do daemon, **nunca** do cliente (§4.2.12 do PRD).
|
|
94455
|
+
number: view.number,
|
|
94456
|
+
strategy: input.strategy,
|
|
94457
|
+
deleteBranch: input.deleteBranch
|
|
94458
|
+
});
|
|
94459
|
+
if (!write.ok) throw new DomainError("GIT_FAILED", write.failure.message);
|
|
94460
|
+
ctx.pr.invalidate(checkout.project.id);
|
|
94461
|
+
ctx.events.emit({ type: "worktree.changed", projectId: checkout.project.id });
|
|
94462
|
+
return { number: view.number };
|
|
94463
|
+
})
|
|
94464
|
+
),
|
|
94465
|
+
/**
|
|
94466
|
+
* O que o formulário propõe, e por que ele não é um campo do `PrStatus`.
|
|
94467
|
+
*
|
|
94468
|
+
* A [Q4](../../../../docs/prd/pull-request-status/open-questions.md) e a F7.6
|
|
94469
|
+
* pedem título vindo do assunto do último commit. Isso custa um `git log`, e
|
|
94470
|
+
* só interessa quando o formulário abre — dentro do `PrStatus` seria um
|
|
94471
|
+
* processo git a cada ciclo de poll, por worktree aberta.
|
|
94472
|
+
*/
|
|
94473
|
+
draft: publicProcedure.input(worktreeInput).query(
|
|
94474
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94475
|
+
const checkout = await checkoutOf(ctx, input.worktreeId);
|
|
94476
|
+
return {
|
|
94477
|
+
title: await ctx.git.getSubject(checkout.cwd) ?? "",
|
|
94478
|
+
base: checkout.base,
|
|
94479
|
+
head: checkout.branch
|
|
94480
|
+
};
|
|
94481
|
+
})
|
|
94482
|
+
),
|
|
94483
|
+
/**
|
|
94484
|
+
* F7 — criar.
|
|
94485
|
+
*
|
|
94486
|
+
* Título e corpo vêm da tela, que é o que o §4.2 do PRD existe para aguentar.
|
|
94487
|
+
* A base e a head **não** vêm: elas saem do banco e do git local.
|
|
94488
|
+
*/
|
|
94489
|
+
create: publicProcedure.input(
|
|
94490
|
+
worktreeInput.extend({
|
|
94491
|
+
title: external_exports.string().min(1).max(256),
|
|
94492
|
+
body: external_exports.string().max(6e4),
|
|
94493
|
+
draft: external_exports.boolean()
|
|
94494
|
+
})
|
|
94495
|
+
).mutation(
|
|
94496
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94497
|
+
const checkout = await checkoutOf(ctx, input.worktreeId);
|
|
94498
|
+
const published = await ctx.git.hasRemoteBranch(checkout.cwd, checkout.branch);
|
|
94499
|
+
if (!published) {
|
|
94500
|
+
throw new DomainError(
|
|
94501
|
+
"BLOCKED",
|
|
94502
|
+
`a branch "${checkout.branch}" ainda n\xE3o foi publicada`
|
|
94503
|
+
);
|
|
94504
|
+
}
|
|
94505
|
+
const write = await ctx.prHost.create({
|
|
94506
|
+
repoPath: checkout.cwd,
|
|
94507
|
+
remoteUrl: checkout.project.remoteUrl,
|
|
94508
|
+
base: checkout.base,
|
|
94509
|
+
head: checkout.branch,
|
|
94510
|
+
title: input.title,
|
|
94511
|
+
body: input.body,
|
|
94512
|
+
draft: input.draft
|
|
94513
|
+
});
|
|
94514
|
+
if (!write.ok) throw new DomainError("GIT_FAILED", write.failure.message);
|
|
94515
|
+
ctx.pr.invalidate(checkout.project.id);
|
|
94516
|
+
ctx.events.emit({ type: "worktree.changed", projectId: checkout.project.id });
|
|
94517
|
+
return { url: write.url };
|
|
94518
|
+
})
|
|
94519
|
+
),
|
|
94520
|
+
/**
|
|
94521
|
+
* "Tentar de novo", e o `⟳` da coluna. Não escreve nada; só invalida.
|
|
94522
|
+
*
|
|
94523
|
+
* A entrada é o **escopo**, e não o id do projeto, porque o escopo é o que o
|
|
94524
|
+
* cliente sabe **na hora do clique** — o projeto de uma worktree chega uma
|
|
94525
|
+
* consulta depois. Pedir o projeto fazia o botão não fazer nada quando o
|
|
94526
|
+
* clique vinha cedo, que é exatamente quando alguém clica em recarregar.
|
|
94527
|
+
*/
|
|
94528
|
+
refresh: publicProcedure.input(external_exports.object({ scopeType: external_exports.enum(["project", "worktree"]), scopeId: external_exports.string().min(1) })).mutation(
|
|
94529
|
+
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94530
|
+
const projectId = input.scopeType === "project" ? input.scopeId : (await createWorktreeRepository(ctx.db).findById(input.scopeId))?.projectId ?? null;
|
|
94531
|
+
if (projectId === null) {
|
|
94532
|
+
throw new DomainError("NOT_FOUND", `worktree ${input.scopeId} n\xE3o existe`);
|
|
94533
|
+
}
|
|
94534
|
+
ctx.pr.invalidate(projectId);
|
|
94535
|
+
return { ok: true };
|
|
94536
|
+
})
|
|
94537
|
+
)
|
|
94538
|
+
});
|
|
94539
|
+
function allows(options, strategy) {
|
|
94540
|
+
return options[strategy];
|
|
94541
|
+
}
|
|
94542
|
+
|
|
93279
94543
|
// src/routers/project.ts
|
|
93280
94544
|
import { existsSync as existsSync5 } from "node:fs";
|
|
93281
|
-
import { rename as rename4, rm as
|
|
93282
|
-
import { basename as basename3, dirname as dirname11, isAbsolute as
|
|
94545
|
+
import { rename as rename4, rm as rm7 } from "node:fs/promises";
|
|
94546
|
+
import { basename as basename3, dirname as dirname11, isAbsolute as isAbsolute6, normalize as normalize4 } from "node:path";
|
|
93283
94547
|
|
|
93284
94548
|
// src/git/clone.ts
|
|
93285
94549
|
import { spawn as spawn2 } from "node:child_process";
|
|
93286
|
-
import { rename as rename3, rm as
|
|
94550
|
+
import { rename as rename3, rm as rm5 } from "node:fs/promises";
|
|
93287
94551
|
var CloneError = class extends DomainError {
|
|
93288
94552
|
constructor(failure, message, options) {
|
|
93289
94553
|
super(failure === "internal" ? "BLOCKED" : "GIT_FAILED", message, options);
|
|
@@ -93304,7 +94568,7 @@ async function cloneRepository(options) {
|
|
|
93304
94568
|
await rename3(tempPath, finalTarget);
|
|
93305
94569
|
return finalTarget;
|
|
93306
94570
|
} catch (error40) {
|
|
93307
|
-
await
|
|
94571
|
+
await rm5(tempPath, { recursive: true, force: true }).catch(() => {
|
|
93308
94572
|
});
|
|
93309
94573
|
throw error40;
|
|
93310
94574
|
}
|
|
@@ -93348,7 +94612,7 @@ function runClone({
|
|
|
93348
94612
|
silenceMs = DEFAULT_SILENCE_MS,
|
|
93349
94613
|
env
|
|
93350
94614
|
}) {
|
|
93351
|
-
return new Promise((
|
|
94615
|
+
return new Promise((resolve6, reject) => {
|
|
93352
94616
|
const child = spawn2("git", cloneArgs(rawUrl, tempPath), {
|
|
93353
94617
|
env: cloneEnv(env),
|
|
93354
94618
|
stdio: ["ignore", "ignore", "pipe"]
|
|
@@ -93371,7 +94635,7 @@ function runClone({
|
|
|
93371
94635
|
silence.stop();
|
|
93372
94636
|
signal?.removeEventListener("abort", onAbort);
|
|
93373
94637
|
if (error40) reject(error40);
|
|
93374
|
-
else
|
|
94638
|
+
else resolve6();
|
|
93375
94639
|
}
|
|
93376
94640
|
function onAbort() {
|
|
93377
94641
|
finish(new CloneError("internal", "clone cancelado"));
|
|
@@ -93402,7 +94666,7 @@ function runClone({
|
|
|
93402
94666
|
if (killTimer) clearTimeout(killTimer);
|
|
93403
94667
|
if (code === 0) return finish();
|
|
93404
94668
|
const stderr = errors.text();
|
|
93405
|
-
finish(new CloneError(
|
|
94669
|
+
finish(new CloneError(classify2(stderr), lastMeaningfulLine(stderr) || `git saiu com ${code}`));
|
|
93406
94670
|
});
|
|
93407
94671
|
});
|
|
93408
94672
|
}
|
|
@@ -93410,7 +94674,7 @@ async function rewriteOrigin({ rawUrl, url: url2, tempPath }) {
|
|
|
93410
94674
|
if (rawUrl === url2) return;
|
|
93411
94675
|
await execGit(["remote", "set-url", "origin", url2], { cwd: tempPath });
|
|
93412
94676
|
}
|
|
93413
|
-
function
|
|
94677
|
+
function classify2(stderr) {
|
|
93414
94678
|
if (/authentication failed|could not read username|could not read password|invalid username or password|permission denied \(publickey|terminal prompts disabled|host key verification failed/i.test(
|
|
93415
94679
|
stderr
|
|
93416
94680
|
)) {
|
|
@@ -93509,134 +94773,7 @@ var SilenceTimer = class {
|
|
|
93509
94773
|
|
|
93510
94774
|
// src/git/clone-plan.ts
|
|
93511
94775
|
import { homedir } from "node:os";
|
|
93512
|
-
import { dirname as dirname9, join as
|
|
93513
|
-
|
|
93514
|
-
// src/git/git-url.ts
|
|
93515
|
-
var ALLOWED = /* @__PURE__ */ new Set(["https", "http", "ssh", "file"]);
|
|
93516
|
-
var HELPER = /^([A-Za-z][A-Za-z0-9+.-]*)::/;
|
|
93517
|
-
var SCHEME = /^([A-Za-z][A-Za-z0-9+.-]*):\/\//;
|
|
93518
|
-
var CONTROL = /[\u0000-\u001f\u007f]/;
|
|
93519
|
-
function refuse(rule, message) {
|
|
93520
|
-
return { ok: false, rule, message };
|
|
93521
|
-
}
|
|
93522
|
-
function refuseScheme(scheme) {
|
|
93523
|
-
if (scheme === "git") {
|
|
93524
|
-
return refuse(
|
|
93525
|
-
"scheme",
|
|
93526
|
-
"o transporte git:// n\xE3o \xE9 aceito: ele n\xE3o autentica nem verifica integridade \u2014 use a URL https ou ssh do mesmo reposit\xF3rio"
|
|
93527
|
-
);
|
|
93528
|
-
}
|
|
93529
|
-
return refuse(
|
|
93530
|
-
"scheme",
|
|
93531
|
-
`o transporte "${scheme}" n\xE3o est\xE1 na lista de transportes aceitos (https, http, ssh, file)`
|
|
93532
|
-
);
|
|
93533
|
-
}
|
|
93534
|
-
function parseGitUrl(input) {
|
|
93535
|
-
const raw = input.trim();
|
|
93536
|
-
if (raw === "") return refuse("empty", "informe a URL do reposit\xF3rio");
|
|
93537
|
-
if (CONTROL.test(raw)) {
|
|
93538
|
-
return refuse("control-chars", "a URL tem caracteres de controle");
|
|
93539
|
-
}
|
|
93540
|
-
if (raw.startsWith("-")) {
|
|
93541
|
-
return refuse("leading-dash", "a URL n\xE3o pode come\xE7ar com '-'");
|
|
93542
|
-
}
|
|
93543
|
-
const helper = HELPER.exec(raw);
|
|
93544
|
-
if (helper) return refuseScheme(helper[1].toLowerCase());
|
|
93545
|
-
const scheme = SCHEME.exec(raw);
|
|
93546
|
-
if (scheme) return parseWithScheme(raw, scheme[1].toLowerCase());
|
|
93547
|
-
if (isScp(raw)) return parseScp(raw);
|
|
93548
|
-
return refuse(
|
|
93549
|
-
"scheme",
|
|
93550
|
-
"n\xE3o reconheci isto como URL git: use https://, ssh://, file:// ou a forma git@host:org/repo.git"
|
|
93551
|
-
);
|
|
93552
|
-
}
|
|
93553
|
-
function scpColon(raw) {
|
|
93554
|
-
const at = raw.indexOf("@");
|
|
93555
|
-
return raw.indexOf(":", at === -1 ? 0 : at + 1);
|
|
93556
|
-
}
|
|
93557
|
-
function isScp(raw) {
|
|
93558
|
-
const colon = scpColon(raw);
|
|
93559
|
-
if (colon <= 0) return false;
|
|
93560
|
-
const slash = raw.indexOf("/");
|
|
93561
|
-
return slash === -1 || colon < slash;
|
|
93562
|
-
}
|
|
93563
|
-
function parseWithScheme(raw, scheme) {
|
|
93564
|
-
if (!ALLOWED.has(scheme)) return refuseScheme(scheme);
|
|
93565
|
-
let parsed;
|
|
93566
|
-
try {
|
|
93567
|
-
parsed = new URL(raw);
|
|
93568
|
-
} catch {
|
|
93569
|
-
return refuse("host", `n\xE3o consegui ler ${raw} como URL`);
|
|
93570
|
-
}
|
|
93571
|
-
if (scheme === "file") return parseFile(raw, parsed);
|
|
93572
|
-
if (parsed.hostname === "" || raw.slice(scheme.length + "://".length).startsWith("/")) {
|
|
93573
|
-
return refuse("host", "a URL n\xE3o tem host");
|
|
93574
|
-
}
|
|
93575
|
-
const path = parsed.pathname.replace(/^\/+/, "");
|
|
93576
|
-
if (path === "") {
|
|
93577
|
-
return refuse("path", "a URL n\xE3o diz qual reposit\xF3rio");
|
|
93578
|
-
}
|
|
93579
|
-
const sanitized = new URL(raw);
|
|
93580
|
-
sanitized.username = "";
|
|
93581
|
-
sanitized.password = "";
|
|
93582
|
-
return {
|
|
93583
|
-
ok: true,
|
|
93584
|
-
raw,
|
|
93585
|
-
url: {
|
|
93586
|
-
scheme,
|
|
93587
|
-
href: sanitized.href,
|
|
93588
|
-
host: parsed.host,
|
|
93589
|
-
path,
|
|
93590
|
-
insecure: scheme === "http",
|
|
93591
|
-
scp: false
|
|
93592
|
-
}
|
|
93593
|
-
};
|
|
93594
|
-
}
|
|
93595
|
-
function parseFile(raw, parsed) {
|
|
93596
|
-
if (parsed.hostname !== "" && parsed.hostname !== "localhost") {
|
|
93597
|
-
return refuse("host", "file:// com host n\xE3o \xE9 aceito; use file:///caminho/absoluto");
|
|
93598
|
-
}
|
|
93599
|
-
const path = decodeURIComponent(parsed.pathname);
|
|
93600
|
-
if (!path.startsWith("/")) {
|
|
93601
|
-
return refuse("path", "o caminho de um file:// precisa ser absoluto");
|
|
93602
|
-
}
|
|
93603
|
-
return {
|
|
93604
|
-
ok: true,
|
|
93605
|
-
raw,
|
|
93606
|
-
url: { scheme: "file", href: `file://${parsed.pathname}`, host: "", path, insecure: false, scp: false }
|
|
93607
|
-
};
|
|
93608
|
-
}
|
|
93609
|
-
function parseScp(raw) {
|
|
93610
|
-
const colon = scpColon(raw);
|
|
93611
|
-
const authority = raw.slice(0, colon);
|
|
93612
|
-
const path = raw.slice(colon + 1);
|
|
93613
|
-
const at = authority.lastIndexOf("@");
|
|
93614
|
-
const user = at === -1 ? "" : authority.slice(0, at);
|
|
93615
|
-
const host = authority.slice(at + 1);
|
|
93616
|
-
if (host === "") return refuse("host", "a URL n\xE3o tem host");
|
|
93617
|
-
if (path === "") return refuse("path", "a URL n\xE3o diz qual reposit\xF3rio");
|
|
93618
|
-
const cleanUser = user.includes(":") ? user.slice(0, user.indexOf(":")) : user;
|
|
93619
|
-
const prefix = cleanUser === "" ? "" : `${cleanUser}@`;
|
|
93620
|
-
return {
|
|
93621
|
-
ok: true,
|
|
93622
|
-
raw,
|
|
93623
|
-
url: {
|
|
93624
|
-
scheme: "ssh",
|
|
93625
|
-
href: `${prefix}${host}:${path}`,
|
|
93626
|
-
host,
|
|
93627
|
-
path: path.replace(/^\/+/, ""),
|
|
93628
|
-
insecure: false,
|
|
93629
|
-
scp: true
|
|
93630
|
-
}
|
|
93631
|
-
};
|
|
93632
|
-
}
|
|
93633
|
-
function repoNameOf(url2) {
|
|
93634
|
-
const segments = url2.path.split("/").filter((segment) => segment !== "");
|
|
93635
|
-
const last = segments.at(-1) ?? "";
|
|
93636
|
-
return last.endsWith(".git") ? last.slice(0, -".git".length) : last;
|
|
93637
|
-
}
|
|
93638
|
-
|
|
93639
|
-
// src/git/clone-plan.ts
|
|
94776
|
+
import { dirname as dirname9, join as join17, normalize as normalize3 } from "node:path";
|
|
93640
94777
|
function planClone({
|
|
93641
94778
|
source,
|
|
93642
94779
|
workspacesDir,
|
|
@@ -93667,11 +94804,11 @@ function rawUrlOf(source) {
|
|
|
93667
94804
|
return parsed.ok ? parsed.raw : null;
|
|
93668
94805
|
}
|
|
93669
94806
|
function tempCloneDir(target, jobId) {
|
|
93670
|
-
return
|
|
94807
|
+
return join17(dirname9(target), `.lumem-clone-${jobId}`);
|
|
93671
94808
|
}
|
|
93672
94809
|
|
|
93673
94810
|
// src/git/managed-dir.ts
|
|
93674
|
-
import { lstat as lstat4, readdir as readdir6, realpath as realpath5, rm as
|
|
94811
|
+
import { lstat as lstat4, readdir as readdir6, realpath as realpath5, rm as rm6, rmdir as rmdir2 } from "node:fs/promises";
|
|
93675
94812
|
import { dirname as dirname10 } from "node:path";
|
|
93676
94813
|
async function deleteManagedRepo({ path, workspacesDir }) {
|
|
93677
94814
|
let info;
|
|
@@ -93688,7 +94825,7 @@ async function deleteManagedRepo({ path, workspacesDir }) {
|
|
|
93688
94825
|
);
|
|
93689
94826
|
}
|
|
93690
94827
|
await requireInsideTree(path, workspacesDir);
|
|
93691
|
-
await
|
|
94828
|
+
await rm6(path, { recursive: true, force: true });
|
|
93692
94829
|
}
|
|
93693
94830
|
async function collectEmptyProjectHome(home, workspacesDir) {
|
|
93694
94831
|
await requireInsideTree(home, workspacesDir).catch(() => {
|
|
@@ -93752,7 +94889,7 @@ async function resolveAvailableName(ctx, workspaceId, desired) {
|
|
|
93752
94889
|
if (!taken.has(candidate)) return candidate;
|
|
93753
94890
|
}
|
|
93754
94891
|
}
|
|
93755
|
-
var pathSchema = external_exports.string().trim().min(1, "informe o caminho do reposit\xF3rio").refine((value) =>
|
|
94892
|
+
var pathSchema = external_exports.string().trim().min(1, "informe o caminho do reposit\xF3rio").refine((value) => isAbsolute6(value), "o caminho precisa ser absoluto").transform((value) => normalize4(value));
|
|
93756
94893
|
var projectRouter = router({
|
|
93757
94894
|
listByWorkspace: publicProcedure.input(external_exports.object({ workspaceId: external_exports.string().min(1) })).query(async ({ ctx, input }) => {
|
|
93758
94895
|
const rows = await createProjectRepository(ctx.db).listByWorkspace(input.workspaceId);
|
|
@@ -93827,23 +94964,27 @@ var projectRouter = router({
|
|
|
93827
94964
|
),
|
|
93828
94965
|
remove: publicProcedure.input(external_exports.object({ id: external_exports.string().min(1) })).mutation(
|
|
93829
94966
|
({ ctx, input }) => domainSafeAsync(async () => {
|
|
93830
|
-
const
|
|
93831
|
-
|
|
94967
|
+
const projects = createProjectRepository(ctx.db);
|
|
94968
|
+
const worktrees = createWorktreeRepository(ctx.db);
|
|
94969
|
+
const row = await projects.findById(input.id);
|
|
94970
|
+
const owned = await worktrees.listByProject(input.id);
|
|
94971
|
+
const vanishing = row?.managed === true ? [] : owned;
|
|
94972
|
+
const runningLists = await Promise.all([
|
|
94973
|
+
ctx.sessionStore.listRunningInScope("project", input.id),
|
|
94974
|
+
...vanishing.map((wt) => ctx.sessionStore.listRunningInScope("worktree", wt.id))
|
|
94975
|
+
]);
|
|
94976
|
+
const running = runningLists.reduce((total, list) => total + list.length, 0);
|
|
94977
|
+
if (running > 0) {
|
|
93832
94978
|
throw new DomainError(
|
|
93833
94979
|
"BLOCKED",
|
|
93834
|
-
`o projeto tem ${running
|
|
94980
|
+
`o projeto tem ${running} sess\xE3o(\xF5es) rodando; encerre-as antes de remover`
|
|
93835
94981
|
);
|
|
93836
94982
|
}
|
|
93837
|
-
|
|
93838
|
-
|
|
93839
|
-
|
|
93840
|
-
|
|
93841
|
-
|
|
93842
|
-
throw new DomainError(
|
|
93843
|
-
"IN_USE",
|
|
93844
|
-
`o projeto ainda tem worktrees registradas (${worktrees.length}); remova-as antes`
|
|
93845
|
-
);
|
|
93846
|
-
}
|
|
94983
|
+
if (row?.managed && owned.length > 0) {
|
|
94984
|
+
throw new DomainError(
|
|
94985
|
+
"IN_USE",
|
|
94986
|
+
`o projeto ainda tem worktrees registradas (${owned.length}); remova-as antes`
|
|
94987
|
+
);
|
|
93847
94988
|
}
|
|
93848
94989
|
if (row) {
|
|
93849
94990
|
if (row.managed) {
|
|
@@ -93855,7 +94996,11 @@ var projectRouter = router({
|
|
|
93855
94996
|
).catch(() => false);
|
|
93856
94997
|
}
|
|
93857
94998
|
await projects.remove(input.id);
|
|
93858
|
-
if (row)
|
|
94999
|
+
if (row) {
|
|
95000
|
+
ctx.events.emit({ type: "project.changed", workspaceId: row.workspaceId });
|
|
95001
|
+
if (vanishing.length > 0)
|
|
95002
|
+
ctx.events.emit({ type: "worktree.changed", projectId: input.id });
|
|
95003
|
+
}
|
|
93859
95004
|
return { ok: true };
|
|
93860
95005
|
})
|
|
93861
95006
|
),
|
|
@@ -93983,7 +95128,7 @@ async function runCloneJob(ctx, job, { rawUrl, url: url2, name }) {
|
|
|
93983
95128
|
finalName === name ? void 0 : `o nome ${name} j\xE1 existia; registrado como ${finalName}`
|
|
93984
95129
|
);
|
|
93985
95130
|
} catch (error40) {
|
|
93986
|
-
if (landed !== null) await
|
|
95131
|
+
if (landed !== null) await rm7(landed, { recursive: true, force: true }).catch(() => {
|
|
93987
95132
|
});
|
|
93988
95133
|
await sweep();
|
|
93989
95134
|
if (ctx.clones.get(job.id)?.state === "cancelled") return;
|
|
@@ -94248,24 +95393,24 @@ var sessionRouter = router({
|
|
|
94248
95393
|
|
|
94249
95394
|
// src/routers/setup.ts
|
|
94250
95395
|
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
94251
|
-
import { join as
|
|
95396
|
+
import { join as join19 } from "node:path";
|
|
94252
95397
|
|
|
94253
95398
|
// src/setup/run-command.ts
|
|
94254
|
-
import { execFile as
|
|
95399
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
94255
95400
|
var DEFAULT_VERSION_TIMEOUT_MS = 3e3;
|
|
94256
|
-
var runCommand = (command, args, { timeoutMs = DEFAULT_VERSION_TIMEOUT_MS } = {}) => new Promise((
|
|
94257
|
-
|
|
95401
|
+
var runCommand = (command, args, { timeoutMs = DEFAULT_VERSION_TIMEOUT_MS } = {}) => new Promise((resolve6) => {
|
|
95402
|
+
execFile3(
|
|
94258
95403
|
command,
|
|
94259
95404
|
[...args],
|
|
94260
95405
|
{ timeout: timeoutMs, maxBuffer: 1024 * 1024 },
|
|
94261
95406
|
(error40, stdout, stderr) => {
|
|
94262
95407
|
const output = (stdout.trim() !== "" ? stdout : stderr).trim();
|
|
94263
95408
|
if (error40 === null) {
|
|
94264
|
-
|
|
95409
|
+
resolve6({ ok: true, output, failure: null });
|
|
94265
95410
|
return;
|
|
94266
95411
|
}
|
|
94267
95412
|
const killed = error40.killed === true;
|
|
94268
|
-
|
|
95413
|
+
resolve6({
|
|
94269
95414
|
ok: false,
|
|
94270
95415
|
output,
|
|
94271
95416
|
failure: killed ? `n\xE3o respondeu em ${timeoutMs} ms` : error40.message
|
|
@@ -94316,9 +95461,9 @@ async function detectAgents({
|
|
|
94316
95461
|
// src/setup/install-adapter.ts
|
|
94317
95462
|
import { existsSync as existsSync6 } from "node:fs";
|
|
94318
95463
|
import { mkdir as mkdir8 } from "node:fs/promises";
|
|
94319
|
-
import { join as
|
|
95464
|
+
import { join as join18 } from "node:path";
|
|
94320
95465
|
function adapterBinaryPath(dir) {
|
|
94321
|
-
return
|
|
95466
|
+
return join18(dir, "node_modules", ".bin", ACP_ADAPTER_COMMAND);
|
|
94322
95467
|
}
|
|
94323
95468
|
async function installAdapter({
|
|
94324
95469
|
dir,
|
|
@@ -94564,7 +95709,7 @@ var setupRouter = router({
|
|
|
94564
95709
|
* have it globally, and the flow must not ask twice for the same thing.
|
|
94565
95710
|
*/
|
|
94566
95711
|
agents: publicProcedure.query(
|
|
94567
|
-
({ ctx }) => detectAgents({ installedAt: adapterBinaryPath(
|
|
95712
|
+
({ ctx }) => detectAgents({ installedAt: adapterBinaryPath(join19(ctx.config.stateDir, ADAPTERS_DIR_NAME)) })
|
|
94568
95713
|
),
|
|
94569
95714
|
/**
|
|
94570
95715
|
* Installs the adapter into the daemon's own directory, at the pinned version.
|
|
@@ -94575,7 +95720,7 @@ var setupRouter = router({
|
|
|
94575
95720
|
*/
|
|
94576
95721
|
installAdapter: publicProcedure.mutation(
|
|
94577
95722
|
({ ctx }) => domainSafeAsync(
|
|
94578
|
-
() => installAdapter({ dir:
|
|
95723
|
+
() => installAdapter({ dir: join19(ctx.config.stateDir, ADAPTERS_DIR_NAME) })
|
|
94579
95724
|
)
|
|
94580
95725
|
),
|
|
94581
95726
|
/**
|
|
@@ -94604,7 +95749,7 @@ var setupRouter = router({
|
|
|
94604
95749
|
).mutation(
|
|
94605
95750
|
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94606
95751
|
const command = input.command ?? ACP_ADAPTER_COMMAND;
|
|
94607
|
-
const cwd =
|
|
95752
|
+
const cwd = join19(ctx.config.stateDir, "probe");
|
|
94608
95753
|
const report = await ctx.acpManager.probe({
|
|
94609
95754
|
command,
|
|
94610
95755
|
...input.args === void 0 ? {} : { args: input.args },
|
|
@@ -94649,7 +95794,7 @@ var setupRouter = router({
|
|
|
94649
95794
|
).query(
|
|
94650
95795
|
({ ctx, input }) => domainSafeAsync(async () => {
|
|
94651
95796
|
const command = input?.command ?? ACP_ADAPTER_COMMAND;
|
|
94652
|
-
const cwd =
|
|
95797
|
+
const cwd = join19(ctx.config.stateDir, "probe");
|
|
94653
95798
|
try {
|
|
94654
95799
|
mkdirSync4(cwd, { recursive: true });
|
|
94655
95800
|
} catch (error40) {
|
|
@@ -94959,6 +96104,7 @@ var appRouter = router({
|
|
|
94959
96104
|
events: eventsRouter,
|
|
94960
96105
|
files: filesRouter,
|
|
94961
96106
|
memory: memoryRouter,
|
|
96107
|
+
pr: prRouter,
|
|
94962
96108
|
project: projectRouter,
|
|
94963
96109
|
scripts: scriptsRouter,
|
|
94964
96110
|
session: sessionRouter,
|
|
@@ -94989,6 +96135,13 @@ async function createServer2({
|
|
|
94989
96135
|
}),
|
|
94990
96136
|
git = createGitService(),
|
|
94991
96137
|
clones = createCloneJobStore(),
|
|
96138
|
+
prHost = createGhHost(),
|
|
96139
|
+
pr = createPrCache({
|
|
96140
|
+
host: prHost,
|
|
96141
|
+
// F6.3: a barra não depende só do relógio dela. É o que faz um merge feito
|
|
96142
|
+
// noutra aba aparecer nesta sem esperar o próximo ciclo.
|
|
96143
|
+
onChange: (projectId) => events.emit({ type: "pr.changed", projectId })
|
|
96144
|
+
}),
|
|
94992
96145
|
logger = false
|
|
94993
96146
|
}) {
|
|
94994
96147
|
const app = (0, import_fastify2.default)({
|
|
@@ -95007,6 +96160,8 @@ async function createServer2({
|
|
|
95007
96160
|
scripts,
|
|
95008
96161
|
git,
|
|
95009
96162
|
clones,
|
|
96163
|
+
pr,
|
|
96164
|
+
prHost,
|
|
95010
96165
|
events
|
|
95011
96166
|
});
|
|
95012
96167
|
await app.register(fastifyTRPCPlugin, {
|
|
@@ -95253,7 +96408,7 @@ async function bootstrap({
|
|
|
95253
96408
|
|
|
95254
96409
|
// src/config.ts
|
|
95255
96410
|
import { homedir as homedir2 } from "node:os";
|
|
95256
|
-
import { isAbsolute as
|
|
96411
|
+
import { isAbsolute as isAbsolute7, join as join20, resolve as resolve5 } from "node:path";
|
|
95257
96412
|
function readPort(raw) {
|
|
95258
96413
|
if (raw === void 0 || raw === "") return DEFAULT_SERVER_PORT;
|
|
95259
96414
|
const trimmed2 = raw.trim();
|
|
@@ -95267,22 +96422,22 @@ function readPort(raw) {
|
|
|
95267
96422
|
return parsed;
|
|
95268
96423
|
}
|
|
95269
96424
|
function absoluteDir(raw) {
|
|
95270
|
-
const expanded = raw === "~" || raw.startsWith("~/") ?
|
|
95271
|
-
return
|
|
96425
|
+
const expanded = raw === "~" || raw.startsWith("~/") ? join20(homedir2(), raw.slice(1)) : raw;
|
|
96426
|
+
return isAbsolute7(expanded) ? join20(expanded) : resolve5(expanded);
|
|
95272
96427
|
}
|
|
95273
96428
|
function readBudget(raw) {
|
|
95274
96429
|
if (raw === void 0 || !/^\d+$/.test(raw.trim())) return 3;
|
|
95275
96430
|
return Number.parseInt(raw.trim(), 10);
|
|
95276
96431
|
}
|
|
95277
96432
|
function loadConfig(env = process.env) {
|
|
95278
|
-
const stateDir = absoluteDir(env.LUMEM_STATE_DIR ??
|
|
96433
|
+
const stateDir = absoluteDir(env.LUMEM_STATE_DIR ?? join20(homedir2(), ".lumem"));
|
|
95279
96434
|
return {
|
|
95280
96435
|
port: readPort(env.LUMEM_PORT),
|
|
95281
96436
|
host: env.LUMEM_HOST ?? "127.0.0.1",
|
|
95282
96437
|
stateDir,
|
|
95283
|
-
databasePath: env.LUMEM_DB_PATH ??
|
|
95284
|
-
workspacesDir:
|
|
95285
|
-
transcriptsDir:
|
|
96438
|
+
databasePath: env.LUMEM_DB_PATH ?? join20(stateDir, "lumem.db"),
|
|
96439
|
+
workspacesDir: join20(stateDir, "workspaces"),
|
|
96440
|
+
transcriptsDir: join20(stateDir, "transcripts"),
|
|
95286
96441
|
// /bin/sh exists on every POSIX system this daemon can run on; SHELL is
|
|
95287
96442
|
// unset under launchd and in some containers.
|
|
95288
96443
|
shell: env.SHELL === void 0 || env.SHELL === "" ? "/bin/sh" : env.SHELL,
|