@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.
@@ -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(resolve5, reject) {
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
- resolve5(result);
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(resolve5, reject) {
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
- resolve5(result);
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(resolve5) {
7658
+ var p = new Promise(function(resolve6) {
7659
7659
  process.nextTick(function() {
7660
7660
  if (queue.idle()) {
7661
- resolve5();
7661
+ resolve6();
7662
7662
  } else {
7663
7663
  var previousDrain = queue.drain;
7664
7664
  queue.drain = function() {
7665
7665
  if (typeof previousDrain === "function") previousDrain();
7666
- resolve5();
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((resolve5, reject) => {
8010
- obj.resolve = resolve5;
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 (resolve5, reject) => {
8279
+ return (resolve6, reject) => {
8280
8280
  const p = this._loadRegistered();
8281
8281
  return p.then(() => {
8282
8282
  this[kThenifyDoNotWrap] = true;
8283
- return resolve5(this._server);
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((resolve5, reject) => {
8420
+ return new Promise((resolve6, reject) => {
8421
8421
  this.close((err) => {
8422
8422
  if (err) {
8423
8423
  return reject(err);
8424
8424
  }
8425
- resolve5();
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(resolve5, reject) {
8572
+ promise2 = new Promise(function(resolve6, reject) {
8573
8573
  func = function(err) {
8574
8574
  if (err) {
8575
8575
  return reject(err);
8576
8576
  }
8577
- resolve5();
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((resolve5, reject) => {
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
- resolve5(relativeContext);
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((resolve5, reject) => {
9986
- res = resolve5;
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: resolve5 } = PonyPromise.withResolvers();
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
- resolve5(address);
10089
+ resolve6(address);
10090
10090
  onListenHookRunner(this);
10091
10091
  });
10092
10092
  } else {
10093
- resolve5(address);
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: resolve5, reject } = PonyPromise.withResolvers();
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
- resolve5(logServerAddress.call(
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: join20 } = __require("path");
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"] || join20(__dirname, "lib", "worker.js");
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: join20, isAbsolute: isAbsolute7, sep: sep6 } = __require("node:path");
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 isAbsolute7(path) && !existsSync10(path);
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"] || join20(__dirname, "worker.js");
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"] || join20(__dirname, "worker.js");
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 (isAbsolute7(origin) || origin.indexOf("file://") === 0) {
15893
+ if (isAbsolute8(origin) || origin.indexOf("file://") === 0) {
15894
15894
  return origin;
15895
15895
  }
15896
15896
  if (origin === "pino/file") {
15897
- return join20(__dirname, "..", "file.js");
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 join20 = ",";
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
- join20 = `,
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 += join20;
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 += `${join20}"... ${getItemCount(removedKeys)} not stringified"`;
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
- join20 = `,
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 = join20;
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 = join20;
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 join20 = ",";
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
- join20 = `,
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 += join20;
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 += `${join20}"... ${getItemCount(removedKeys)} not stringified"`;
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
- join20 = `,
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 = join20;
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 join21 = `,
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 += join21;
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 += `${join21}"... ${getItemCount(removedKeys)} not stringified"`;
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 join20 = `,
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, join20, maximumBreadth);
17129
+ res += stringifyTypedArray(value, join21, maximumBreadth);
17130
17130
  keys = keys.slice(value.length);
17131
17131
  maximumPropertiesToStringify -= value.length;
17132
- separator = join20;
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 = join20;
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 = join20;
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 = resolve5.call(this, root, ref);
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 resolve5(root, ref) {
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 resolve5(baseURI, relativeURI, options) {
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, relative4, options, skipNormalization) {
24875
+ function resolveComponent(base, relative5, options, skipNormalization) {
24876
24876
  const target = {};
24877
24877
  if (!skipNormalization) {
24878
24878
  base = parse5(serialize(base, options), options);
24879
- relative4 = parse5(serialize(relative4, options), options);
24879
+ relative5 = parse5(serialize(relative5, options), options);
24880
24880
  }
24881
24881
  options = options || {};
24882
- if (!options.tolerant && relative4.scheme) {
24883
- target.scheme = relative4.scheme;
24884
- target.userinfo = relative4.userinfo;
24885
- target.host = relative4.host;
24886
- target.port = relative4.port;
24887
- target.path = removeDotSegments(relative4.path || "");
24888
- target.query = relative4.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 (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
24891
- target.userinfo = relative4.userinfo;
24892
- target.host = relative4.host;
24893
- target.port = relative4.port;
24894
- target.path = removeDotSegments(relative4.path || "");
24895
- target.query = relative4.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 (!relative4.path) {
24897
+ if (!relative5.path) {
24898
24898
  target.path = base.path;
24899
- if (relative4.query !== void 0) {
24900
- target.query = relative4.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 (relative4.path[0] === "/") {
24906
- target.path = removeDotSegments(relative4.path);
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 = "/" + relative4.path;
24909
+ target.path = "/" + relative5.path;
24910
24910
  } else if (!base.path) {
24911
- target.path = relative4.path;
24911
+ target.path = relative5.path;
24912
24912
  } else {
24913
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
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 = relative4.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 = relative4.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: resolve5,
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 parseJson(s, pos) {
28904
+ function parseJson2(s, pos) {
28905
28905
  let endPos;
28906
- parseJson.message = void 0;
28906
+ parseJson2.message = void 0;
28907
28907
  let matches;
28908
28908
  if (pos)
28909
28909
  s = s.slice(pos);
28910
28910
  try {
28911
- parseJson.position = pos + s.length;
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
- parseJson.message = "unexpected end";
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
- parseJson.position = pos + endPos;
28922
+ parseJson2.position = pos + endPos;
28923
28923
  try {
28924
28924
  return JSON.parse(s);
28925
28925
  } catch (e1) {
28926
- parseJson.message = `unexpected token ${c}`;
28926
+ parseJson2.message = `unexpected token ${c}`;
28927
28927
  return void 0;
28928
28928
  }
28929
28929
  }
28930
28930
  }
28931
- exports.parseJson = parseJson;
28932
- parseJson.message = void 0;
28933
- parseJson.position = 0;
28934
- parseJson.code = 'require("ajv/dist/runtime/parseJson").parseJson';
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 resolve5(baseURI, relativeURI, options) {
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, relative4, options, skipNormalization) {
30159
+ function resolveComponent(base, relative5, options, skipNormalization) {
30160
30160
  const target = {};
30161
30161
  if (!skipNormalization) {
30162
30162
  base = parse5(serialize(base, options), options);
30163
- relative4 = parse5(serialize(relative4, options), options);
30163
+ relative5 = parse5(serialize(relative5, options), options);
30164
30164
  }
30165
30165
  options = options || {};
30166
- if (!options.tolerant && relative4.scheme) {
30167
- target.scheme = relative4.scheme;
30168
- target.userinfo = relative4.userinfo;
30169
- target.host = relative4.host;
30170
- target.port = relative4.port;
30171
- target.path = removeDotSegments(relative4.path || "");
30172
- target.query = relative4.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 (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
30175
- target.userinfo = relative4.userinfo;
30176
- target.host = relative4.host;
30177
- target.port = relative4.port;
30178
- target.path = removeDotSegments(relative4.path || "");
30179
- target.query = relative4.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 (!relative4.path) {
30181
+ if (!relative5.path) {
30182
30182
  target.path = base.path;
30183
- if (relative4.query !== void 0) {
30184
- target.query = relative4.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 (relative4.path[0] === "/") {
30190
- target.path = removeDotSegments(relative4.path);
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 = "/" + relative4.path;
30193
+ target.path = "/" + relative5.path;
30194
30194
  } else if (!base.path) {
30195
- target.path = relative4.path;
30195
+ target.path = relative5.path;
30196
30196
  } else {
30197
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
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 = relative4.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 = relative4.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: resolve5,
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((resolve5, reject) => {
42292
+ return new Promise((resolve6, reject) => {
42293
42293
  const req = new RequestConstructor(options);
42294
- const res = new Response2(req, resolve5, reject);
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 READ = Symbol("read");
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[READ](n || null, this[BUFFER][0]);
49778
+ const ret = this[READ2](n || null, this[BUFFER][0]);
49779
49779
  this[MAYBE_EMIT_END]();
49780
49780
  return ret;
49781
49781
  }
49782
- [READ](n, chunk) {
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((resolve5, reject) => {
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", () => resolve5());
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 resolve5;
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
- resolve5({ value, done: !!this[EOF] });
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
- resolve5({ done: true, value: void 0 });
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
- resolve5 = res2;
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 resolve5 = () => {
51257
+ let resolve6 = () => {
51258
51258
  };
51259
- this.#asyncReaddirInFlight = new Promise((res) => resolve5 = 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
- resolve5();
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 relative4 = p.relative() || ".";
52360
- const relatives = `${relative4}/`;
52359
+ const relative5 = p.relative() || ".";
52360
+ const relatives = `${relative5}/`;
52361
52361
  for (const m of this.relative) {
52362
- if (m.match(relative4) || m.match(relatives))
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 relative4 = (p.relative() || ".") + "/";
52373
+ const relative5 = (p.relative() || ".") + "/";
52374
52374
  for (const m of this.relativeChildren) {
52375
- if (m.match(relative4))
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 relative4 = __require("path").relative;
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 relative4(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
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 join20 = path.join;
54469
+ var join21 = path.join;
54470
54470
  var normalize5 = path.normalize;
54471
- var resolve5 = path.resolve;
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 ? resolve5(options.root) : null;
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(join20(root, path2));
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 = resolve5(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((resolve6) => {
54659
+ return new Promise((resolve7) => {
54660
54660
  fs2.stat(path2, function onstat(error40, stat3) {
54661
- resolve6({ error: error40, stat: stat3 });
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 = join20(path2, index2);
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.1.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 join20(chunks, separator) {
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 = join20;
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((join20) => join20.alias === tableName)) {
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((join20) => join20.alias === tableName)) {
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("workspace", {
66332
- id: text("id").primaryKey(),
66333
- name: text("name").notNull().unique(),
66334
- ...timestamps
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
- await withConstraints(() => db.delete(project).where(eq(project.id, id)).returning(), {
67067
- foreignKey: {
67068
- code: "IN_USE",
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((resolve5, reject) => {
81153
+ const response = new Promise((resolve6, reject) => {
81022
81154
  const pendingResponse = {
81023
81155
  resolve: (value) => {
81024
81156
  try {
81025
- resolve5(mapResponse ? mapResponse(value) : value);
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((resolve5) => {
81083
- this.abortController.signal.addEventListener("abort", () => resolve5());
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((resolve5, reject) => {
81965
- this.waiters.push({ resolve: resolve5, reject });
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 relative4 = normalizeRelative(requested);
82789
+ const relative5 = normalizeRelative(requested);
82658
82790
  const realRoot = await realRootOf(root);
82659
- const target = join6(realRoot, relative4);
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 ${relative4 || "."}`);
82798
+ throw new DomainError("BLOCKED", `sem permiss\xE3o de leitura em ${relative5 || "."}`);
82667
82799
  }
82668
- throw new DomainError("NOT_FOUND", `${relative4 || "."} n\xE3o existe no checkout`);
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 ? `${relative4} est\xE1 fora do checkout` : `${relative4} aponta para fora do checkout`
82805
+ target === absolute ? `${relative5} est\xE1 fora do checkout` : `${relative5} aponta para fora do checkout`
82674
82806
  );
82675
82807
  }
82676
- const insideGit = touchesGit(relative4) || touchesGit(relativeTo(realRoot, absolute));
82677
- return { absolute, relative: relative4, insideGit };
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 relative4 = normalizeRelative(requested);
82694
- if (relative4 === "") {
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(relative4, relative4);
82829
+ refuseWritingIntoGit(relative5, relative5);
82698
82830
  const realRoot = await realRootOf(root);
82699
- const parentRelative = dirname4(relative4) === "." ? "" : dirname4(relative4);
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(relative4));
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(relative4)));
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 ${relative4}`);
82882
+ throw new DomainError("BLOCKED", `sem acesso a ${relative5}`);
82751
82883
  }
82752
82884
  exists2 = false;
82753
82885
  }
82754
- refuseWritingIntoGit(relative4, relativeTo(realRoot, entry));
82755
- if (target !== null) refuseWritingIntoGit(relative4, relativeTo(realRoot, target));
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: relative4, entry, target, targetless, exists: exists2 };
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, relative4) {
82943
+ function asCreationFailure(error40, relative5) {
82812
82944
  const code = error40.code;
82813
- const parent = dirname5(relative4) === "." ? "." : dirname5(relative4);
82945
+ const parent = dirname5(relative5) === "." ? "." : dirname5(relative5);
82814
82946
  if (code === "EEXIST") {
82815
- return new DomainError("DUPLICATE", `j\xE1 existe alguma coisa em ${relative4}`);
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, relative4) {
82982
+ function asRemovalFailure(error40, relative5) {
82851
82983
  const code = error40.code;
82852
82984
  if (code === "ENOENT") {
82853
- return new DomainError("NOT_FOUND", `${relative4} n\xE3o est\xE1 mais no checkout`);
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", `${relative4} deixou de estar vazia`);
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 ${relative4}`);
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: relative4 } = await resolveInsideRoot(root, path);
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", `${relative4} n\xE3o \xE9 um diret\xF3rio`);
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 ${relative4 || "."}`);
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: relative4, entries, total, truncated: total > kept.length };
83092
+ return { path: relative5, entries, total, truncated: total > kept.length };
82961
83093
  },
82962
83094
  async readFile(root, path) {
82963
- const { absolute, relative: relative4, insideGit } = await resolveInsideRoot(root, path);
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", `${relative4} \xE9 um diret\xF3rio`);
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: relative4, bytes: info.size, limit: maxBytes };
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 ${relative4}`);
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: relative4, bytes: buffer.length };
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: relative4,
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: relative4, target, targetless, exists: exists2 } = await resolveForWrite(root, path);
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 ${relative4}: o link aponta para fora do checkout` : `escrita recusada em ${relative4}: o link est\xE1 pendurado, e nada prova onde a grava\xE7\xE3o cairia`
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", `${relative4} n\xE3o existe no checkout`);
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
- `${relative4} n\xE3o est\xE1 mais no checkout`
83147
+ `${relative5} n\xE3o est\xE1 mais no checkout`
83016
83148
  );
83017
83149
  });
83018
83150
  if (info.isDirectory()) {
83019
- throw new DomainError("INVALID_ARGUMENT", `${relative4} \xE9 um diret\xF3rio`);
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
- `${relative4} tem ${info.size} bytes no disco, acima do limite de ${maxBytes}`
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 ${relative4}: o arquivo \xE9 somente leitura no disco`
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 ${relative4}`);
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 ${relative4}: o conte\xFAdo no disco n\xE3o sobrevive a uma ida e volta em UTF-8, e gravar destruiria bytes`
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 ${relative4}`);
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: relative4, entry } = await resolveForWrite(root, path);
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, relative4);
83201
+ throw asCreationFailure(error40, relative5);
83070
83202
  }
83071
- return { path: relative4 };
83203
+ return { path: relative5 };
83072
83204
  },
83073
83205
  async createDir(root, path) {
83074
- const { relative: relative4, entry } = await resolveForWrite(root, path);
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, relative4);
83210
+ throw asCreationFailure(error40, relative5);
83079
83211
  }
83080
- return { path: relative4 };
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: relative4, entry, exists: exists2 } = await resolveForWrite(root, path);
83237
+ const { relative: relative5, entry, exists: exists2 } = await resolveForWrite(root, path);
83106
83238
  if (!exists2) {
83107
- throw new DomainError("NOT_FOUND", `${relative4} n\xE3o existe no checkout`);
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, relative4);
83242
+ throw asRemovalFailure(error40, relative5);
83111
83243
  });
83112
83244
  if (!info.isDirectory()) {
83113
83245
  await unlink(entry).catch((error40) => {
83114
- throw asRemovalFailure(error40, relative4);
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, relative4);
83252
+ throw asRemovalFailure(error40, relative5);
83121
83253
  });
83122
83254
  return;
83123
83255
  }
83124
- const inside2 = await readdir4(entry).catch((error40) => {
83125
- throw asRemovalFailure(error40, relative4);
83256
+ const inside3 = await readdir4(entry).catch((error40) => {
83257
+ throw asRemovalFailure(error40, relative5);
83126
83258
  });
83127
- if (inside2.length > 0) {
83259
+ if (inside3.length > 0) {
83128
83260
  throw new DomainError(
83129
83261
  "BLOCKED",
83130
- `a pasta ${relative4} tem ${inside2.length} ${inside2.length === 1 ? "entrada" : "entradas"} dentro; apagar assim mesmo exige recursive`
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, relative4);
83266
+ throw asRemovalFailure(error40, relative5);
83135
83267
  });
83136
83268
  },
83137
83269
  async deletePreview(root, path) {
83138
- const { relative: relative4, entry, exists: exists2 } = await resolveForWrite(root, path);
83270
+ const { relative: relative5, entry, exists: exists2 } = await resolveForWrite(root, path);
83139
83271
  if (!exists2) {
83140
- throw new DomainError("NOT_FOUND", `${relative4} n\xE3o existe no checkout`);
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, relative4);
83275
+ throw asRemovalFailure(error40, relative5);
83144
83276
  });
83145
83277
  if (!info.isDirectory()) {
83146
- return { kind: "file", path: relative4, tracked: await isTracked(entry) };
83278
+ return { kind: "file", path: relative5, tracked: await isTracked(entry) };
83147
83279
  }
83148
- return { kind: "dir", path: relative4, ...await countTree(entry, maxPreviewEntries) };
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(relative4) {
83169
- const parts = relative4.split(sep3).slice(0, -1);
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 relative4 = toRelative2(path);
83200
- const existing = await files2.readFile(absoluteRoot, relative4).catch((error40) => {
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(relative4);
83207
- await files2.createFile(absoluteRoot, relative4);
83208
- before = await files2.readFile(absoluteRoot, relative4);
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, relative4, {
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((resolve5) => {
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
- resolve5(status);
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((resolve5) => {
83326
- child.once("exit", (exitCode, signal) => resolve5({ exitCode, signal }));
83327
- child.once("error", () => resolve5({ exitCode: null, signal: null }));
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, { type: "permission_resolved", requestId, outcome: { optionId } });
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((resolve5) => {
84061
- const timer = setTimeout(resolve5, timeoutMs);
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
- resolve5();
84302
+ resolve6();
84066
84303
  });
84067
84304
  try {
84068
84305
  session2.process.kill();
84069
84306
  } catch {
84070
84307
  clearTimeout(timer);
84071
- resolve5();
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: params.options.map((option) => ({
84143
- optionId: option.optionId,
84144
- name: option.name,
84145
- kind: option.kind
84146
- }))
84389
+ options,
84390
+ policyReason: decision.approve ? null : decision.reason
84147
84391
  });
84148
- return new Promise((resolve5) => {
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) => resolve5({ 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 = relative(stateDir, absolute).split(sep4).join("/");
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 relative2, sep as sep5 } from "node:path";
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 = relative2(stateDir, absolutePath);
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 relative3, isAbsolute as isAbsolute4 } from "node:path";
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 (!isAbsolute4(path)) return path;
86448
- const rel = relative3(cwd, path);
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((resolve5) => {
87216
- const timer = setTimeout(resolve5, timeoutMs);
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
- resolve5();
87491
+ resolve6();
87221
87492
  });
87222
87493
  try {
87223
87494
  session2.pty.kill();
87224
87495
  } catch {
87225
87496
  clearTimeout(timer);
87226
- resolve5();
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((resolve5) => {
87607
+ return new Promise((resolve6) => {
87337
87608
  const probe = createServer();
87338
- probe.once("error", () => resolve5(false));
87339
- probe.once("listening", () => probe.close(() => resolve5(true)));
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 resolve3 } from "node:path";
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 checkoutOf(scope) {
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 checkoutOf(scope);
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 checkoutOf(scope);
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((resolve5) => {
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
- resolve5(null);
88552
+ resolve6(null);
88282
88553
  }, timeoutMs);
88283
88554
  ptyManager.onExit(row.id, ({ exitCode }) => {
88284
88555
  clearTimeout(timer);
88285
- resolve5(exitCode);
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, { mode: info.mode, model: info.model }).catch((error40) => {
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: resolve5 }) => {
89597
- resolve5(value);
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 resolve5;
90054
+ let resolve6;
89739
90055
  let reject;
89740
90056
  const promise2 = new Promise((_resolve, _reject) => {
89741
- resolve5 = _resolve;
90057
+ resolve6 = _resolve;
89742
90058
  reject = _reject;
89743
90059
  });
89744
90060
  return {
89745
90061
  promise: promise2,
89746
- resolve: resolve5,
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((resolve5) => {
89791
- timer = setTimeout(() => resolve5(disposablePromiseTimerResult), ms);
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 resolve5;
90294
+ let resolve6;
89979
90295
  let reject;
89980
90296
  const promise2 = new Promise((res, rej) => {
89981
- resolve5 = res;
90297
+ resolve6 = res;
89982
90298
  reject = rej;
89983
90299
  });
89984
90300
  return {
89985
90301
  promise: promise2,
89986
- resolve: resolve5,
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((resolve5) => {
91562
- abortController$1.signal.onabort = () => resolve5("abort");
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((resolve5) => {
92043
- wake = resolve5;
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((resolve5) => {
92209
- wss.close(() => resolve5());
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((resolve5) => {
92603
- wss.close(() => resolve5());
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 join15 } from "node:path";
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(join15(candidate, "index.html")) ? candidate : null;
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 rm6 } from "node:fs/promises";
93282
- import { basename as basename3, dirname as dirname11, isAbsolute as isAbsolute5, normalize as normalize4 } from "node:path";
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 rm4 } from "node:fs/promises";
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 rm4(tempPath, { recursive: true, force: true }).catch(() => {
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((resolve5, reject) => {
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 resolve5();
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(classify(stderr), lastMeaningfulLine(stderr) || `git saiu com ${code}`));
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 classify(stderr) {
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 join16, normalize as normalize3 } from "node:path";
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 join16(dirname9(target), `.lumem-clone-${jobId}`);
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 rm5, rmdir as rmdir2 } from "node:fs/promises";
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 rm5(path, { recursive: true, force: true });
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) => isAbsolute5(value), "o caminho precisa ser absoluto").transform((value) => normalize4(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 running = await ctx.sessionStore.listRunningInScope("project", input.id);
93831
- if (running.length > 0) {
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.length} sess\xE3o(\xF5es) rodando; encerre-as antes de remover`
94980
+ `o projeto tem ${running} sess\xE3o(\xF5es) rodando; encerre-as antes de remover`
93835
94981
  );
93836
94982
  }
93837
- const projects = createProjectRepository(ctx.db);
93838
- const row = await projects.findById(input.id);
93839
- if (row) {
93840
- const worktrees = await createWorktreeRepository(ctx.db).listByProject(row.id);
93841
- if (worktrees.length > 0) {
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) ctx.events.emit({ type: "project.changed", workspaceId: row.workspaceId });
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 rm6(landed, { recursive: true, force: true }).catch(() => {
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 join18 } from "node:path";
95396
+ import { join as join19 } from "node:path";
94252
95397
 
94253
95398
  // src/setup/run-command.ts
94254
- import { execFile as execFile2 } from "node:child_process";
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((resolve5) => {
94257
- execFile2(
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
- resolve5({ ok: true, output, failure: null });
95409
+ resolve6({ ok: true, output, failure: null });
94265
95410
  return;
94266
95411
  }
94267
95412
  const killed = error40.killed === true;
94268
- resolve5({
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 join17 } from "node:path";
95464
+ import { join as join18 } from "node:path";
94320
95465
  function adapterBinaryPath(dir) {
94321
- return join17(dir, "node_modules", ".bin", ACP_ADAPTER_COMMAND);
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(join18(ctx.config.stateDir, ADAPTERS_DIR_NAME)) })
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: join18(ctx.config.stateDir, ADAPTERS_DIR_NAME) })
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 = join18(ctx.config.stateDir, "probe");
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 = join18(ctx.config.stateDir, "probe");
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 isAbsolute6, join as join19, resolve as resolve4 } from "node:path";
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("~/") ? join19(homedir2(), raw.slice(1)) : raw;
95271
- return isAbsolute6(expanded) ? join19(expanded) : resolve4(expanded);
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 ?? join19(homedir2(), ".lumem"));
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 ?? join19(stateDir, "lumem.db"),
95284
- workspacesDir: join19(stateDir, "workspaces"),
95285
- transcriptsDir: join19(stateDir, "transcripts"),
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,