elit 3.5.3 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -936,10 +936,10 @@ var init_http = __esm({
936
936
  }
937
937
  async text() {
938
938
  if (isNode) {
939
- return new Promise((resolve8, reject) => {
939
+ return new Promise((resolve9, reject) => {
940
940
  const chunks = [];
941
941
  this._req.on("data", (chunk) => chunks.push(chunk));
942
- this._req.on("end", () => resolve8(Buffer.concat(chunks).toString("utf8")));
942
+ this._req.on("end", () => resolve9(Buffer.concat(chunks).toString("utf8")));
943
943
  this._req.on("error", reject);
944
944
  });
945
945
  }
@@ -1083,8 +1083,8 @@ var init_http = __esm({
1083
1083
  }
1084
1084
  return this;
1085
1085
  }
1086
- _setResolver(resolve8) {
1087
- this._resolve = resolve8;
1086
+ _setResolver(resolve9) {
1087
+ this._resolve = resolve9;
1088
1088
  }
1089
1089
  // Express.js-like methods
1090
1090
  json(data, statusCode = 200) {
@@ -1290,12 +1290,12 @@ var init_http = __esm({
1290
1290
  headers
1291
1291
  });
1292
1292
  }
1293
- return new Promise((resolve8) => {
1293
+ return new Promise((resolve9) => {
1294
1294
  serverResponse.end = (chunk) => {
1295
1295
  if (chunk !== void 0) {
1296
1296
  body += chunk;
1297
1297
  }
1298
- resolve8(new Response(body, {
1298
+ resolve9(new Response(body, {
1299
1299
  status: statusCode,
1300
1300
  statusText: statusMessage,
1301
1301
  headers
@@ -1311,10 +1311,10 @@ var init_http = __esm({
1311
1311
  port,
1312
1312
  hostname,
1313
1313
  handler: (req) => {
1314
- return new Promise((resolve8) => {
1314
+ return new Promise((resolve9) => {
1315
1315
  const incomingMessage = new IncomingMessage(req);
1316
1316
  const serverResponse = new ServerResponse();
1317
- serverResponse._setResolver(resolve8);
1317
+ serverResponse._setResolver(resolve9);
1318
1318
  if (self2.requestListener) {
1319
1319
  self2.requestListener(incomingMessage, serverResponse);
1320
1320
  } else {
@@ -25175,11 +25175,11 @@ var require_scope = __commonJS({
25175
25175
  "use strict";
25176
25176
  var __awaiter2 = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
25177
25177
  function adopt(value) {
25178
- return value instanceof P ? value : new P(function(resolve8) {
25179
- resolve8(value);
25178
+ return value instanceof P ? value : new P(function(resolve9) {
25179
+ resolve9(value);
25180
25180
  });
25181
25181
  }
25182
- return new (P || (P = Promise))(function(resolve8, reject) {
25182
+ return new (P || (P = Promise))(function(resolve9, reject) {
25183
25183
  function fulfilled(value) {
25184
25184
  try {
25185
25185
  step(generator.next(value));
@@ -25195,7 +25195,7 @@ var require_scope = __commonJS({
25195
25195
  }
25196
25196
  }
25197
25197
  function step(result2) {
25198
- result2.done ? resolve8(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25198
+ result2.done ? resolve9(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25199
25199
  }
25200
25200
  step((generator = generator.apply(thisArg, _arguments || [])).next());
25201
25201
  });
@@ -25486,11 +25486,11 @@ var require_instantiation = __commonJS({
25486
25486
  };
25487
25487
  var __awaiter2 = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
25488
25488
  function adopt(value) {
25489
- return value instanceof P ? value : new P(function(resolve8) {
25490
- resolve8(value);
25489
+ return value instanceof P ? value : new P(function(resolve9) {
25490
+ resolve9(value);
25491
25491
  });
25492
25492
  }
25493
- return new (P || (P = Promise))(function(resolve8, reject) {
25493
+ return new (P || (P = Promise))(function(resolve9, reject) {
25494
25494
  function fulfilled(value) {
25495
25495
  try {
25496
25496
  step(generator.next(value));
@@ -25506,7 +25506,7 @@ var require_instantiation = __commonJS({
25506
25506
  }
25507
25507
  }
25508
25508
  function step(result2) {
25509
- result2.done ? resolve8(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25509
+ result2.done ? resolve9(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25510
25510
  }
25511
25511
  step((generator = generator.apply(thisArg, _arguments || [])).next());
25512
25512
  });
@@ -25761,11 +25761,11 @@ var require_resolver = __commonJS({
25761
25761
  };
25762
25762
  var __awaiter2 = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
25763
25763
  function adopt(value) {
25764
- return value instanceof P ? value : new P(function(resolve9) {
25765
- resolve9(value);
25764
+ return value instanceof P ? value : new P(function(resolve10) {
25765
+ resolve10(value);
25766
25766
  });
25767
25767
  }
25768
- return new (P || (P = Promise))(function(resolve9, reject) {
25768
+ return new (P || (P = Promise))(function(resolve10, reject) {
25769
25769
  function fulfilled(value) {
25770
25770
  try {
25771
25771
  step(generator.next(value));
@@ -25781,7 +25781,7 @@ var require_resolver = __commonJS({
25781
25781
  }
25782
25782
  }
25783
25783
  function step(result2) {
25784
- result2.done ? resolve9(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25784
+ result2.done ? resolve10(result2.value) : adopt(result2.value).then(fulfilled, rejected);
25785
25785
  }
25786
25786
  step((generator = generator.apply(thisArg, _arguments || [])).next());
25787
25787
  });
@@ -25856,7 +25856,7 @@ var require_resolver = __commonJS({
25856
25856
  }
25857
25857
  };
25858
25858
  Object.defineProperty(exports2, "__esModule", { value: true });
25859
- exports2.resolve = resolve8;
25859
+ exports2.resolve = resolve9;
25860
25860
  var ERROR_MSGS = __importStar(require_error_msgs());
25861
25861
  var literal_types_1 = require_literal_types();
25862
25862
  var planner_1 = require_planner();
@@ -26023,7 +26023,7 @@ var require_resolver = __commonJS({
26023
26023
  };
26024
26024
  return containersIterator;
26025
26025
  };
26026
- function resolve8(context) {
26026
+ function resolve9(context) {
26027
26027
  var resolveRequestFunction = _resolveRequest(context.plan.rootRequest.requestScope);
26028
26028
  return resolveRequestFunction(context.plan.rootRequest);
26029
26029
  }
@@ -26818,11 +26818,11 @@ var require_container = __commonJS({
26818
26818
  };
26819
26819
  var __awaiter2 = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
26820
26820
  function adopt(value) {
26821
- return value instanceof P ? value : new P(function(resolve8) {
26822
- resolve8(value);
26821
+ return value instanceof P ? value : new P(function(resolve9) {
26822
+ resolve9(value);
26823
26823
  });
26824
26824
  }
26825
- return new (P || (P = Promise))(function(resolve8, reject) {
26825
+ return new (P || (P = Promise))(function(resolve9, reject) {
26826
26826
  function fulfilled(value) {
26827
26827
  try {
26828
26828
  step(generator.next(value));
@@ -26838,7 +26838,7 @@ var require_container = __commonJS({
26838
26838
  }
26839
26839
  }
26840
26840
  function step(result2) {
26841
- result2.done ? resolve8(result2.value) : adopt(result2.value).then(fulfilled, rejected);
26841
+ result2.done ? resolve9(result2.value) : adopt(result2.value).then(fulfilled, rejected);
26842
26842
  }
26843
26843
  step((generator = generator.apply(thisArg, _arguments || [])).next());
26844
26844
  });
@@ -29201,7 +29201,7 @@ var require_escodegen = __commonJS({
29201
29201
  function noEmptySpace() {
29202
29202
  return space ? space : " ";
29203
29203
  }
29204
- function join7(left, right) {
29204
+ function join8(left, right) {
29205
29205
  var leftSource, rightSource, leftCharCode, rightCharCode;
29206
29206
  leftSource = toSourceNodeWhenNeeded(left).toString();
29207
29207
  if (leftSource.length === 0) {
@@ -29536,8 +29536,8 @@ var require_escodegen = __commonJS({
29536
29536
  } else {
29537
29537
  result2.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
29538
29538
  }
29539
- result2 = join7(result2, operator);
29540
- result2 = [join7(
29539
+ result2 = join8(result2, operator);
29540
+ result2 = [join8(
29541
29541
  result2,
29542
29542
  that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
29543
29543
  ), ")"];
@@ -29680,11 +29680,11 @@ var require_escodegen = __commonJS({
29680
29680
  var result2, fragment;
29681
29681
  result2 = ["class"];
29682
29682
  if (stmt.id) {
29683
- result2 = join7(result2, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
29683
+ result2 = join8(result2, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
29684
29684
  }
29685
29685
  if (stmt.superClass) {
29686
- fragment = join7("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
29687
- result2 = join7(result2, fragment);
29686
+ fragment = join8("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
29687
+ result2 = join8(result2, fragment);
29688
29688
  }
29689
29689
  result2.push(space);
29690
29690
  result2.push(this.generateStatement(stmt.body, S_TFFT));
@@ -29697,9 +29697,9 @@ var require_escodegen = __commonJS({
29697
29697
  return escapeDirective(stmt.directive) + this.semicolon(flags);
29698
29698
  },
29699
29699
  DoWhileStatement: function(stmt, flags) {
29700
- var result2 = join7("do", this.maybeBlock(stmt.body, S_TFFF));
29700
+ var result2 = join8("do", this.maybeBlock(stmt.body, S_TFFF));
29701
29701
  result2 = this.maybeBlockSuffix(stmt.body, result2);
29702
- return join7(result2, [
29702
+ return join8(result2, [
29703
29703
  "while" + space + "(",
29704
29704
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
29705
29705
  ")" + this.semicolon(flags)
@@ -29735,11 +29735,11 @@ var require_escodegen = __commonJS({
29735
29735
  ExportDefaultDeclaration: function(stmt, flags) {
29736
29736
  var result2 = ["export"], bodyFlags;
29737
29737
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
29738
- result2 = join7(result2, "default");
29738
+ result2 = join8(result2, "default");
29739
29739
  if (isStatement(stmt.declaration)) {
29740
- result2 = join7(result2, this.generateStatement(stmt.declaration, bodyFlags));
29740
+ result2 = join8(result2, this.generateStatement(stmt.declaration, bodyFlags));
29741
29741
  } else {
29742
- result2 = join7(result2, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
29742
+ result2 = join8(result2, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
29743
29743
  }
29744
29744
  return result2;
29745
29745
  },
@@ -29747,15 +29747,15 @@ var require_escodegen = __commonJS({
29747
29747
  var result2 = ["export"], bodyFlags, that = this;
29748
29748
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
29749
29749
  if (stmt.declaration) {
29750
- return join7(result2, this.generateStatement(stmt.declaration, bodyFlags));
29750
+ return join8(result2, this.generateStatement(stmt.declaration, bodyFlags));
29751
29751
  }
29752
29752
  if (stmt.specifiers) {
29753
29753
  if (stmt.specifiers.length === 0) {
29754
- result2 = join7(result2, "{" + space + "}");
29754
+ result2 = join8(result2, "{" + space + "}");
29755
29755
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
29756
- result2 = join7(result2, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
29756
+ result2 = join8(result2, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
29757
29757
  } else {
29758
- result2 = join7(result2, "{");
29758
+ result2 = join8(result2, "{");
29759
29759
  withIndent(function(indent6) {
29760
29760
  var i, iz;
29761
29761
  result2.push(newline);
@@ -29773,7 +29773,7 @@ var require_escodegen = __commonJS({
29773
29773
  result2.push(base + "}");
29774
29774
  }
29775
29775
  if (stmt.source) {
29776
- result2 = join7(result2, [
29776
+ result2 = join8(result2, [
29777
29777
  "from" + space,
29778
29778
  // ModuleSpecifier
29779
29779
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -29793,7 +29793,7 @@ var require_escodegen = __commonJS({
29793
29793
  if (stmt.exported) {
29794
29794
  result2.push("as " + stmt.exported.name + " ");
29795
29795
  }
29796
- result2 = join7(result2, [
29796
+ result2 = join8(result2, [
29797
29797
  "from" + space,
29798
29798
  // ModuleSpecifier
29799
29799
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -29867,7 +29867,7 @@ var require_escodegen = __commonJS({
29867
29867
  ];
29868
29868
  cursor = 0;
29869
29869
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
29870
- result2 = join7(result2, [
29870
+ result2 = join8(result2, [
29871
29871
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
29872
29872
  ]);
29873
29873
  ++cursor;
@@ -29877,7 +29877,7 @@ var require_escodegen = __commonJS({
29877
29877
  result2.push(",");
29878
29878
  }
29879
29879
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
29880
- result2 = join7(result2, [
29880
+ result2 = join8(result2, [
29881
29881
  space,
29882
29882
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
29883
29883
  ]);
@@ -29906,7 +29906,7 @@ var require_escodegen = __commonJS({
29906
29906
  }
29907
29907
  }
29908
29908
  }
29909
- result2 = join7(result2, [
29909
+ result2 = join8(result2, [
29910
29910
  "from" + space,
29911
29911
  // ModuleSpecifier
29912
29912
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -29966,7 +29966,7 @@ var require_escodegen = __commonJS({
29966
29966
  ];
29967
29967
  },
29968
29968
  ThrowStatement: function(stmt, flags) {
29969
- return [join7(
29969
+ return [join8(
29970
29970
  "throw",
29971
29971
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
29972
29972
  ), this.semicolon(flags)];
@@ -29977,7 +29977,7 @@ var require_escodegen = __commonJS({
29977
29977
  result2 = this.maybeBlockSuffix(stmt.block, result2);
29978
29978
  if (stmt.handlers) {
29979
29979
  for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
29980
- result2 = join7(result2, this.generateStatement(stmt.handlers[i], S_TFFF));
29980
+ result2 = join8(result2, this.generateStatement(stmt.handlers[i], S_TFFF));
29981
29981
  if (stmt.finalizer || i + 1 !== iz) {
29982
29982
  result2 = this.maybeBlockSuffix(stmt.handlers[i].body, result2);
29983
29983
  }
@@ -29985,7 +29985,7 @@ var require_escodegen = __commonJS({
29985
29985
  } else {
29986
29986
  guardedHandlers = stmt.guardedHandlers || [];
29987
29987
  for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
29988
- result2 = join7(result2, this.generateStatement(guardedHandlers[i], S_TFFF));
29988
+ result2 = join8(result2, this.generateStatement(guardedHandlers[i], S_TFFF));
29989
29989
  if (stmt.finalizer || i + 1 !== iz) {
29990
29990
  result2 = this.maybeBlockSuffix(guardedHandlers[i].body, result2);
29991
29991
  }
@@ -29993,13 +29993,13 @@ var require_escodegen = __commonJS({
29993
29993
  if (stmt.handler) {
29994
29994
  if (Array.isArray(stmt.handler)) {
29995
29995
  for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
29996
- result2 = join7(result2, this.generateStatement(stmt.handler[i], S_TFFF));
29996
+ result2 = join8(result2, this.generateStatement(stmt.handler[i], S_TFFF));
29997
29997
  if (stmt.finalizer || i + 1 !== iz) {
29998
29998
  result2 = this.maybeBlockSuffix(stmt.handler[i].body, result2);
29999
29999
  }
30000
30000
  }
30001
30001
  } else {
30002
- result2 = join7(result2, this.generateStatement(stmt.handler, S_TFFF));
30002
+ result2 = join8(result2, this.generateStatement(stmt.handler, S_TFFF));
30003
30003
  if (stmt.finalizer) {
30004
30004
  result2 = this.maybeBlockSuffix(stmt.handler.body, result2);
30005
30005
  }
@@ -30007,7 +30007,7 @@ var require_escodegen = __commonJS({
30007
30007
  }
30008
30008
  }
30009
30009
  if (stmt.finalizer) {
30010
- result2 = join7(result2, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
30010
+ result2 = join8(result2, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
30011
30011
  }
30012
30012
  return result2;
30013
30013
  },
@@ -30041,7 +30041,7 @@ var require_escodegen = __commonJS({
30041
30041
  withIndent(function() {
30042
30042
  if (stmt.test) {
30043
30043
  result2 = [
30044
- join7("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
30044
+ join8("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
30045
30045
  ":"
30046
30046
  ];
30047
30047
  } else {
@@ -30089,9 +30089,9 @@ var require_escodegen = __commonJS({
30089
30089
  result2.push(this.maybeBlock(stmt.consequent, S_TFFF));
30090
30090
  result2 = this.maybeBlockSuffix(stmt.consequent, result2);
30091
30091
  if (stmt.alternate.type === Syntax.IfStatement) {
30092
- result2 = join7(result2, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
30092
+ result2 = join8(result2, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
30093
30093
  } else {
30094
- result2 = join7(result2, join7("else", this.maybeBlock(stmt.alternate, bodyFlags)));
30094
+ result2 = join8(result2, join8("else", this.maybeBlock(stmt.alternate, bodyFlags)));
30095
30095
  }
30096
30096
  } else {
30097
30097
  result2.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -30192,7 +30192,7 @@ var require_escodegen = __commonJS({
30192
30192
  },
30193
30193
  ReturnStatement: function(stmt, flags) {
30194
30194
  if (stmt.argument) {
30195
- return [join7(
30195
+ return [join8(
30196
30196
  "return",
30197
30197
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
30198
30198
  ), this.semicolon(flags)];
@@ -30297,14 +30297,14 @@ var require_escodegen = __commonJS({
30297
30297
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
30298
30298
  result2 = [fragment, noEmptySpace(), expr.operator];
30299
30299
  } else {
30300
- result2 = join7(fragment, expr.operator);
30300
+ result2 = join8(fragment, expr.operator);
30301
30301
  }
30302
30302
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
30303
30303
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
30304
30304
  result2.push(noEmptySpace());
30305
30305
  result2.push(fragment);
30306
30306
  } else {
30307
- result2 = join7(result2, fragment);
30307
+ result2 = join8(result2, fragment);
30308
30308
  }
30309
30309
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
30310
30310
  return ["(", result2, ")"];
@@ -30343,7 +30343,7 @@ var require_escodegen = __commonJS({
30343
30343
  var result2, length2, i, iz, itemFlags;
30344
30344
  length2 = expr["arguments"].length;
30345
30345
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length2 === 0 ? E_TFT : E_TFF;
30346
- result2 = join7(
30346
+ result2 = join8(
30347
30347
  "new",
30348
30348
  this.generateExpression(expr.callee, Precedence.New, itemFlags)
30349
30349
  );
@@ -30393,11 +30393,11 @@ var require_escodegen = __commonJS({
30393
30393
  var result2, fragment, rightCharCode, leftSource, leftCharCode;
30394
30394
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
30395
30395
  if (space === "") {
30396
- result2 = join7(expr.operator, fragment);
30396
+ result2 = join8(expr.operator, fragment);
30397
30397
  } else {
30398
30398
  result2 = [expr.operator];
30399
30399
  if (expr.operator.length > 2) {
30400
- result2 = join7(result2, fragment);
30400
+ result2 = join8(result2, fragment);
30401
30401
  } else {
30402
30402
  leftSource = toSourceNodeWhenNeeded(result2).toString();
30403
30403
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -30420,7 +30420,7 @@ var require_escodegen = __commonJS({
30420
30420
  result2 = "yield";
30421
30421
  }
30422
30422
  if (expr.argument) {
30423
- result2 = join7(
30423
+ result2 = join8(
30424
30424
  result2,
30425
30425
  this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
30426
30426
  );
@@ -30428,7 +30428,7 @@ var require_escodegen = __commonJS({
30428
30428
  return parenthesize(result2, Precedence.Yield, precedence);
30429
30429
  },
30430
30430
  AwaitExpression: function(expr, precedence, flags) {
30431
- var result2 = join7(
30431
+ var result2 = join8(
30432
30432
  expr.all ? "await*" : "await",
30433
30433
  this.generateExpression(expr.argument, Precedence.Await, E_TTT)
30434
30434
  );
@@ -30511,11 +30511,11 @@ var require_escodegen = __commonJS({
30511
30511
  var result2, fragment;
30512
30512
  result2 = ["class"];
30513
30513
  if (expr.id) {
30514
- result2 = join7(result2, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
30514
+ result2 = join8(result2, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
30515
30515
  }
30516
30516
  if (expr.superClass) {
30517
- fragment = join7("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
30518
- result2 = join7(result2, fragment);
30517
+ fragment = join8("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
30518
+ result2 = join8(result2, fragment);
30519
30519
  }
30520
30520
  result2.push(space);
30521
30521
  result2.push(this.generateStatement(expr.body, S_TFFT));
@@ -30530,7 +30530,7 @@ var require_escodegen = __commonJS({
30530
30530
  }
30531
30531
  if (expr.kind === "get" || expr.kind === "set") {
30532
30532
  fragment = [
30533
- join7(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
30533
+ join8(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
30534
30534
  this.generateFunctionBody(expr.value)
30535
30535
  ];
30536
30536
  } else {
@@ -30540,7 +30540,7 @@ var require_escodegen = __commonJS({
30540
30540
  this.generateFunctionBody(expr.value)
30541
30541
  ];
30542
30542
  }
30543
- return join7(result2, fragment);
30543
+ return join8(result2, fragment);
30544
30544
  },
30545
30545
  PrivateIdentifier: function(expr, precedence, flags) {
30546
30546
  return generateIdentifier(expr);
@@ -30753,7 +30753,7 @@ var require_escodegen = __commonJS({
30753
30753
  for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
30754
30754
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
30755
30755
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
30756
- result2 = join7(result2, fragment);
30756
+ result2 = join8(result2, fragment);
30757
30757
  } else {
30758
30758
  result2.push(fragment);
30759
30759
  }
@@ -30761,13 +30761,13 @@ var require_escodegen = __commonJS({
30761
30761
  });
30762
30762
  }
30763
30763
  if (expr.filter) {
30764
- result2 = join7(result2, "if" + space);
30764
+ result2 = join8(result2, "if" + space);
30765
30765
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
30766
- result2 = join7(result2, ["(", fragment, ")"]);
30766
+ result2 = join8(result2, ["(", fragment, ")"]);
30767
30767
  }
30768
30768
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
30769
30769
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
30770
- result2 = join7(result2, fragment);
30770
+ result2 = join8(result2, fragment);
30771
30771
  }
30772
30772
  result2.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
30773
30773
  return result2;
@@ -30783,8 +30783,8 @@ var require_escodegen = __commonJS({
30783
30783
  } else {
30784
30784
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
30785
30785
  }
30786
- fragment = join7(fragment, expr.of ? "of" : "in");
30787
- fragment = join7(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
30786
+ fragment = join8(fragment, expr.of ? "of" : "in");
30787
+ fragment = join8(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
30788
30788
  return ["for" + space + "(", fragment, ")"];
30789
30789
  },
30790
30790
  SpreadElement: function(expr, precedence, flags) {
@@ -33294,11 +33294,11 @@ var init_Validator = __esm({
33294
33294
  init_ValidationExecutor();
33295
33295
  __awaiter = function(thisArg, _arguments, P, generator) {
33296
33296
  function adopt(value) {
33297
- return value instanceof P ? value : new P(function(resolve8) {
33298
- resolve8(value);
33297
+ return value instanceof P ? value : new P(function(resolve9) {
33298
+ resolve9(value);
33299
33299
  });
33300
33300
  }
33301
- return new (P || (P = Promise))(function(resolve8, reject) {
33301
+ return new (P || (P = Promise))(function(resolve9, reject) {
33302
33302
  function fulfilled(value) {
33303
33303
  try {
33304
33304
  step(generator.next(value));
@@ -33314,7 +33314,7 @@ var init_Validator = __esm({
33314
33314
  }
33315
33315
  }
33316
33316
  function step(result2) {
33317
- result2.done ? resolve8(result2.value) : adopt(result2.value).then(fulfilled, rejected);
33317
+ result2.done ? resolve9(result2.value) : adopt(result2.value).then(fulfilled, rejected);
33318
33318
  }
33319
33319
  step((generator = generator.apply(thisArg, _arguments || [])).next());
33320
33320
  });
@@ -57437,13 +57437,13 @@ function readdirp(root, options = {}) {
57437
57437
  options.root = root;
57438
57438
  return new ReaddirpStream(options);
57439
57439
  }
57440
- var import_promises, import_node_stream, import_node_path5, EntryTypes, defaultOptions3, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
57440
+ var import_promises, import_node_stream, import_node_path6, EntryTypes, defaultOptions3, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
57441
57441
  var init_esm = __esm({
57442
57442
  "node_modules/readdirp/esm/index.js"() {
57443
57443
  "use strict";
57444
57444
  import_promises = require("fs/promises");
57445
57445
  import_node_stream = require("stream");
57446
- import_node_path5 = require("path");
57446
+ import_node_path6 = require("path");
57447
57447
  EntryTypes = {
57448
57448
  FILE_TYPE: "files",
57449
57449
  DIR_TYPE: "directories",
@@ -57518,7 +57518,7 @@ var init_esm = __esm({
57518
57518
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
57519
57519
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
57520
57520
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
57521
- this._root = (0, import_node_path5.resolve)(root);
57521
+ this._root = (0, import_node_path6.resolve)(root);
57522
57522
  this._isDirent = !opts.alwaysStat;
57523
57523
  this._statsProp = this._isDirent ? "dirent" : "stats";
57524
57524
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -57587,10 +57587,10 @@ var init_esm = __esm({
57587
57587
  }
57588
57588
  async _formatEntry(dirent, path) {
57589
57589
  let entry;
57590
- const basename7 = this._isDirent ? dirent.name : dirent;
57590
+ const basename8 = this._isDirent ? dirent.name : dirent;
57591
57591
  try {
57592
- const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path, basename7));
57593
- entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename7 };
57592
+ const fullPath = (0, import_node_path6.resolve)((0, import_node_path6.join)(path, basename8));
57593
+ entry = { path: (0, import_node_path6.relative)(this._root, fullPath), fullPath, basename: basename8 };
57594
57594
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
57595
57595
  } catch (err) {
57596
57596
  this._onError(err);
@@ -57624,7 +57624,7 @@ var init_esm = __esm({
57624
57624
  }
57625
57625
  if (entryRealPathStats.isDirectory()) {
57626
57626
  const len = entryRealPath.length;
57627
- if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path5.sep) {
57627
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path6.sep) {
57628
57628
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
57629
57629
  recursiveError.code = RECURSIVE_ERROR_CODE;
57630
57630
  return this._onError(recursiveError);
@@ -57655,7 +57655,7 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
57655
57655
  }
57656
57656
  };
57657
57657
  try {
57658
- return (0, import_fs6.watch)(path, {
57658
+ return (0, import_fs7.watch)(path, {
57659
57659
  persistent: options.persistent
57660
57660
  }, handleEvent);
57661
57661
  } catch (error) {
@@ -57663,11 +57663,11 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
57663
57663
  return void 0;
57664
57664
  }
57665
57665
  }
57666
- var import_fs6, import_promises2, sysPath, import_os, STR_DATA, STR_END, STR_CLOSE, EMPTY_FN, pl, isWindows2, isMacos, isLinux, isFreeBSD, isIBMi, EVENTS, EV, THROTTLE_MODE_WATCH, statMethods, KEY_LISTENERS, KEY_ERR, KEY_RAW, HANDLER_KEYS, binaryExtensions, isBinaryPath, foreach, addAndConvert, clearItem, delFromSet, isEmptySet, FsWatchInstances, fsWatchBroadcast, setFsWatchListener, FsWatchFileInstances, setFsWatchFileListener, NodeFsHandler;
57666
+ var import_fs7, import_promises2, sysPath, import_os, STR_DATA, STR_END, STR_CLOSE, EMPTY_FN, pl, isWindows2, isMacos, isLinux, isFreeBSD, isIBMi, EVENTS, EV, THROTTLE_MODE_WATCH, statMethods, KEY_LISTENERS, KEY_ERR, KEY_RAW, HANDLER_KEYS, binaryExtensions, isBinaryPath, foreach, addAndConvert, clearItem, delFromSet, isEmptySet, FsWatchInstances, fsWatchBroadcast, setFsWatchListener, FsWatchFileInstances, setFsWatchFileListener, NodeFsHandler;
57667
57667
  var init_handler = __esm({
57668
57668
  "node_modules/chokidar/esm/handler.js"() {
57669
57669
  "use strict";
57670
- import_fs6 = require("fs");
57670
+ import_fs7 = require("fs");
57671
57671
  import_promises2 = require("fs/promises");
57672
57672
  sysPath = __toESM(require("path"), 1);
57673
57673
  import_os = require("os");
@@ -58071,7 +58071,7 @@ var init_handler = __esm({
58071
58071
  let cont = FsWatchFileInstances.get(fullPath);
58072
58072
  const copts = cont && cont.options;
58073
58073
  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
58074
- (0, import_fs6.unwatchFile)(fullPath);
58074
+ (0, import_fs7.unwatchFile)(fullPath);
58075
58075
  cont = void 0;
58076
58076
  }
58077
58077
  if (cont) {
@@ -58082,7 +58082,7 @@ var init_handler = __esm({
58082
58082
  listeners: listener,
58083
58083
  rawEmitters: rawEmitter,
58084
58084
  options,
58085
- watcher: (0, import_fs6.watchFile)(fullPath, options, (curr, prev) => {
58085
+ watcher: (0, import_fs7.watchFile)(fullPath, options, (curr, prev) => {
58086
58086
  foreach(cont.rawEmitters, (rawEmitter2) => {
58087
58087
  rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
58088
58088
  });
@@ -58099,7 +58099,7 @@ var init_handler = __esm({
58099
58099
  delFromSet(cont, KEY_RAW, rawEmitter);
58100
58100
  if (isEmptySet(cont.listeners)) {
58101
58101
  FsWatchFileInstances.delete(fullPath);
58102
- (0, import_fs6.unwatchFile)(fullPath);
58102
+ (0, import_fs7.unwatchFile)(fullPath);
58103
58103
  cont.options = cont.watcher = void 0;
58104
58104
  Object.freeze(cont);
58105
58105
  }
@@ -58119,9 +58119,9 @@ var init_handler = __esm({
58119
58119
  _watchWithNodeFs(path, listener) {
58120
58120
  const opts = this.fsw.options;
58121
58121
  const directory = sysPath.dirname(path);
58122
- const basename7 = sysPath.basename(path);
58122
+ const basename8 = sysPath.basename(path);
58123
58123
  const parent = this.fsw._getWatchedDir(directory);
58124
- parent.add(basename7);
58124
+ parent.add(basename8);
58125
58125
  const absolutePath = sysPath.resolve(path);
58126
58126
  const options = {
58127
58127
  persistent: opts.persistent
@@ -58131,7 +58131,7 @@ var init_handler = __esm({
58131
58131
  let closer;
58132
58132
  if (opts.usePolling) {
58133
58133
  const enableBin = opts.interval !== opts.binaryInterval;
58134
- options.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
58134
+ options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
58135
58135
  closer = setFsWatchFileListener(path, absolutePath, options, {
58136
58136
  listener,
58137
58137
  rawEmitter: this.fsw._emitRaw
@@ -58153,11 +58153,11 @@ var init_handler = __esm({
58153
58153
  if (this.fsw.closed) {
58154
58154
  return;
58155
58155
  }
58156
- const dirname8 = sysPath.dirname(file);
58157
- const basename7 = sysPath.basename(file);
58158
- const parent = this.fsw._getWatchedDir(dirname8);
58156
+ const dirname9 = sysPath.dirname(file);
58157
+ const basename8 = sysPath.basename(file);
58158
+ const parent = this.fsw._getWatchedDir(dirname9);
58159
58159
  let prevStats = stats;
58160
- if (parent.has(basename7))
58160
+ if (parent.has(basename8))
58161
58161
  return;
58162
58162
  const listener = async (path, newStats) => {
58163
58163
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
@@ -58182,9 +58182,9 @@ var init_handler = __esm({
58182
58182
  prevStats = newStats2;
58183
58183
  }
58184
58184
  } catch (error) {
58185
- this.fsw._remove(dirname8, basename7);
58185
+ this.fsw._remove(dirname9, basename8);
58186
58186
  }
58187
- } else if (parent.has(basename7)) {
58187
+ } else if (parent.has(basename8)) {
58188
58188
  const at = newStats.atimeMs;
58189
58189
  const mt = newStats.mtimeMs;
58190
58190
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -58278,7 +58278,7 @@ var init_handler = __esm({
58278
58278
  this._addToNodeFs(path, initialAdd, wh, depth + 1);
58279
58279
  }
58280
58280
  }).on(EV.ERROR, this._boundHandleError);
58281
- return new Promise((resolve8, reject) => {
58281
+ return new Promise((resolve9, reject) => {
58282
58282
  if (!stream)
58283
58283
  return reject();
58284
58284
  stream.once(STR_END, () => {
@@ -58287,7 +58287,7 @@ var init_handler = __esm({
58287
58287
  return;
58288
58288
  }
58289
58289
  const wasThrottled = throttler ? throttler.clear() : false;
58290
- resolve8(void 0);
58290
+ resolve9(void 0);
58291
58291
  previous.getChildren().filter((item) => {
58292
58292
  return item !== directory && !current.has(item);
58293
58293
  }).forEach((item) => {
@@ -58484,11 +58484,11 @@ function watch3(paths, options = {}) {
58484
58484
  watcher.add(paths);
58485
58485
  return watcher;
58486
58486
  }
58487
- var import_fs7, import_promises3, import_events4, sysPath2, SLASH, SLASH_SLASH, ONE_DOT, TWO_DOTS, STRING_TYPE, BACK_SLASH_RE, DOUBLE_SLASH_RE, DOT_RE, REPLACER_RE, isMatcherObject, unifyPaths, toUnix, normalizePathToUnix, normalizeIgnored, getAbsolutePath, EMPTY_SET, DirEntry, STAT_METHOD_F, STAT_METHOD_L, WatchHelper, FSWatcher2, esm_default;
58487
+ var import_fs8, import_promises3, import_events4, sysPath2, SLASH, SLASH_SLASH, ONE_DOT, TWO_DOTS, STRING_TYPE, BACK_SLASH_RE, DOUBLE_SLASH_RE, DOT_RE, REPLACER_RE, isMatcherObject, unifyPaths, toUnix, normalizePathToUnix, normalizeIgnored, getAbsolutePath, EMPTY_SET, DirEntry, STAT_METHOD_F, STAT_METHOD_L, WatchHelper, FSWatcher2, esm_default;
58488
58488
  var init_esm2 = __esm({
58489
58489
  "node_modules/chokidar/esm/index.js"() {
58490
58490
  "use strict";
58491
- import_fs7 = require("fs");
58491
+ import_fs8 = require("fs");
58492
58492
  import_promises3 = require("fs/promises");
58493
58493
  import_events4 = require("events");
58494
58494
  sysPath2 = __toESM(require("path"), 1);
@@ -58966,7 +58966,7 @@ var init_esm2 = __esm({
58966
58966
  const now = /* @__PURE__ */ new Date();
58967
58967
  const writes = this._pendingWrites;
58968
58968
  function awaitWriteFinishFn(prevStat) {
58969
- (0, import_fs7.stat)(fullPath, (err, curStat) => {
58969
+ (0, import_fs8.stat)(fullPath, (err, curStat) => {
58970
58970
  if (err || !writes.has(path)) {
58971
58971
  if (err && err.code !== "ENOENT")
58972
58972
  awfEmit(err);
@@ -59400,7 +59400,7 @@ var require_package3 = __commonJS({
59400
59400
  "package.json"(exports2, module2) {
59401
59401
  module2.exports = {
59402
59402
  name: "elit",
59403
- version: "3.5.3",
59403
+ version: "3.5.4",
59404
59404
  description: "Optimized lightweight library for creating DOM elements with reactive state",
59405
59405
  main: "dist/index.js",
59406
59406
  module: "dist/index.mjs",
@@ -59558,6 +59558,7 @@ var require_package3 = __commonJS({
59558
59558
  "test:run": "elit test --run",
59559
59559
  "test:coverage": "elit test --coverage",
59560
59560
  "test:e2e": "elit test --e2e",
59561
+ "test:wapk:google-drive": "elit test --run --file ./testing/unit/wapk.google-drive.integration.test.ts",
59561
59562
  benchmark: "node benchmark/server-benchmark.js",
59562
59563
  "benchmark:router": "node benchmark/router-benchmark.js",
59563
59564
  "docs:dev": "npm run --prefix docs dev",
@@ -59639,6 +59640,7 @@ __export(cli_exports, {
59639
59640
  runDev: () => runDev,
59640
59641
  runMobile: () => runMobile,
59641
59642
  runNative: () => runNative,
59643
+ runPm: () => runPm,
59642
59644
  runPreview: () => runPreview,
59643
59645
  runTest: () => runTest,
59644
59646
  runWapk: () => runWapk
@@ -59731,9 +59733,9 @@ async function loadConfigFile(configPath) {
59731
59733
  } else if (ext === "ts" || ext === "mts") {
59732
59734
  try {
59733
59735
  const { build: build2 } = await import("esbuild");
59734
- const { join: join7, dirname: dirname8 } = await Promise.resolve().then(() => (init_path(), path_exports));
59735
- const configDir = dirname8(configPath);
59736
- const tempFile = join7(configDir, `.elit-config-${Date.now()}.mjs`);
59736
+ const { join: join8, dirname: dirname9 } = await Promise.resolve().then(() => (init_path(), path_exports));
59737
+ const configDir = dirname9(configPath);
59738
+ const tempFile = join8(configDir, `.elit-config-${Date.now()}.mjs`);
59737
59739
  const externalAllPlugin = {
59738
59740
  name: "external-all",
59739
59741
  setup(build3) {
@@ -60297,6 +60299,8 @@ var WebSocketServer = class extends import_events2.EventEmitter {
60297
60299
 
60298
60300
  // src/chokidar.ts
60299
60301
  var import_events3 = require("events");
60302
+ init_fs();
60303
+ init_path();
60300
60304
  init_runtime();
60301
60305
  function normalizePath2(path) {
60302
60306
  return path.replace(/\\/g, "/");
@@ -60418,18 +60422,35 @@ var FSWatcher = class extends import_events3.EventEmitter {
60418
60422
  }
60419
60423
  };
60420
60424
  function getBaseDirectory(pattern) {
60421
- const parts = pattern.split(/[\\\/]/);
60425
+ const normalizedPattern = normalizePath2(pattern);
60426
+ const parts = normalizedPattern.split(/[\\\/]/);
60422
60427
  let baseDir = "";
60428
+ let sawGlob = false;
60423
60429
  for (const part of parts) {
60424
60430
  if (part.includes("*") || part.includes("?")) {
60431
+ sawGlob = true;
60425
60432
  break;
60426
60433
  }
60427
60434
  baseDir = baseDir ? `${baseDir}/${part}` : part;
60428
60435
  }
60429
- return baseDir || ".";
60436
+ if (sawGlob) {
60437
+ return baseDir || ".";
60438
+ }
60439
+ if (normalizedPattern && existsSync(normalizedPattern)) {
60440
+ try {
60441
+ return statSync(normalizedPattern).isDirectory() ? normalizedPattern : normalizePath2(dirname(normalizedPattern)) || ".";
60442
+ } catch {
60443
+ return normalizePath2(dirname(normalizedPattern)) || ".";
60444
+ }
60445
+ }
60446
+ const lastSegment = parts[parts.length - 1] || "";
60447
+ if (lastSegment.includes(".") && !lastSegment.startsWith(".")) {
60448
+ return normalizePath2(dirname(normalizedPattern)) || ".";
60449
+ }
60450
+ return normalizedPattern || ".";
60430
60451
  }
60431
60452
  function matchesPattern(filePath, pattern) {
60432
- const regexPattern = normalizePath2(pattern).replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
60453
+ const regexPattern = normalizePath2(pattern).replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
60433
60454
  const regex = new RegExp(`^${regexPattern}$`);
60434
60455
  const normalizedPath = normalizePath2(filePath);
60435
60456
  return regex.test(normalizedPath);
@@ -62505,10 +62526,10 @@ ${elitImportMap}`;
62505
62526
  webSocketServers.forEach((wsServer) => wsServer.close());
62506
62527
  wsClients.clear();
62507
62528
  }
62508
- return new Promise((resolve8) => {
62529
+ return new Promise((resolve9) => {
62509
62530
  server.close(() => {
62510
62531
  if (config.logging) console.log("[Server] Closed");
62511
- resolve8();
62532
+ resolve9();
62512
62533
  });
62513
62534
  });
62514
62535
  };
@@ -74451,6 +74472,7 @@ var WAPK_SALT_LENGTH = 16;
74451
74472
  var WAPK_IV_LENGTH = 12;
74452
74473
  var WAPK_AUTH_TAG_LENGTH = 16;
74453
74474
  var WAPK_SCRYPT_OPTIONS = { N: 16384, r: 8, p: 1 };
74475
+ var DEFAULT_GOOGLE_DRIVE_TOKEN_ENV = "GOOGLE_DRIVE_ACCESS_TOKEN";
74454
74476
  function isRecord(value) {
74455
74477
  return typeof value === "object" && value !== null && !Array.isArray(value);
74456
74478
  }
@@ -74526,6 +74548,47 @@ function normalizeWapkConfig(value) {
74526
74548
  lock: normalizeWapkLockConfig(value.lock)
74527
74549
  };
74528
74550
  }
74551
+ function normalizeWapkGoogleDriveConfig(value) {
74552
+ if (!isRecord(value)) {
74553
+ return void 0;
74554
+ }
74555
+ const normalized = {
74556
+ fileId: normalizeNonEmptyString(value.fileId),
74557
+ accessToken: normalizeNonEmptyString(value.accessToken),
74558
+ accessTokenEnv: normalizeNonEmptyString(value.accessTokenEnv),
74559
+ supportsAllDrives: normalizeBoolean(value.supportsAllDrives)
74560
+ };
74561
+ return Object.values(normalized).some((entry) => entry !== void 0) ? normalized : void 0;
74562
+ }
74563
+ function normalizeBoolean(value) {
74564
+ return typeof value === "boolean" ? value : void 0;
74565
+ }
74566
+ function normalizeSyncInterval(value) {
74567
+ if (value === void 0 || value === null || value === "") {
74568
+ return void 0;
74569
+ }
74570
+ const interval = typeof value === "number" ? value : Number(value);
74571
+ if (!Number.isFinite(interval) || interval < 50) {
74572
+ return void 0;
74573
+ }
74574
+ return Math.trunc(interval);
74575
+ }
74576
+ function normalizeWapkRunConfig(value) {
74577
+ if (!isRecord(value)) {
74578
+ return void 0;
74579
+ }
74580
+ const normalized = {
74581
+ file: normalizeNonEmptyString(value.file),
74582
+ googleDrive: normalizeWapkGoogleDriveConfig(value.googleDrive),
74583
+ runtime: normalizeRuntime(value.runtime),
74584
+ syncInterval: normalizeSyncInterval(value.syncInterval),
74585
+ useWatcher: normalizeBoolean(value.useWatcher),
74586
+ watchArchive: normalizeBoolean(value.watchArchive),
74587
+ archiveSyncInterval: normalizeSyncInterval(value.archiveSyncInterval),
74588
+ password: normalizeNonEmptyString(value.password)
74589
+ };
74590
+ return Object.values(normalized).some((entry) => entry !== void 0) ? normalized : void 0;
74591
+ }
74529
74592
  function sanitizePackageName(name) {
74530
74593
  const sanitized = name.trim().replace(/[<>:"/\\|?*\x00-\x1F]+/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-");
74531
74594
  return sanitized.length > 0 ? sanitized : "app";
@@ -74972,49 +75035,360 @@ function extractFiles(files, destination) {
74972
75035
  }
74973
75036
  }
74974
75037
  function collectRuntimeSyncFiles(directory) {
74975
- const files = collectFiles(directory, directory, []);
74976
- return files.filter((file) => {
75038
+ return filterRuntimeSyncFiles(collectFiles(directory, directory, []));
75039
+ }
75040
+ function filterRuntimeSyncFiles(files) {
75041
+ return [...files].filter((file) => {
74977
75042
  const firstPart = file.path.split("/")[0] ?? "";
74978
75043
  return !RUNTIME_SYNC_IGNORE.has(firstPart);
74979
75044
  }).sort((left, right) => left.path.localeCompare(right.path));
74980
75045
  }
74981
- function writeWapkArchiveFromMemory(archivePath, header, files, lock) {
75046
+ function getLocalArchiveSignature(archivePath) {
75047
+ try {
75048
+ const stats = (0, import_node_fs2.statSync)(archivePath);
75049
+ return `${stats.size}:${stats.mtimeMs}`;
75050
+ } catch {
75051
+ return void 0;
75052
+ }
75053
+ }
75054
+ function createGoogleDriveArchiveSignature(metadata) {
75055
+ const signature = [metadata.modifiedTime, metadata.size, metadata.md5Checksum].filter((value) => typeof value === "string" && value.length > 0).join(":");
75056
+ return signature.length > 0 ? signature : void 0;
75057
+ }
75058
+ async function readResponseMessage(response) {
75059
+ try {
75060
+ const text = (await response.text()).trim();
75061
+ return text.length > 0 ? text.slice(0, 400) : response.statusText;
75062
+ } catch {
75063
+ return response.statusText;
75064
+ }
75065
+ }
75066
+ function buildGoogleDriveFileUrl(fileId, params) {
75067
+ const url = new URL(`https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}`);
75068
+ for (const [key, value] of Object.entries(params)) {
75069
+ if (value === void 0) {
75070
+ continue;
75071
+ }
75072
+ url.searchParams.set(key, typeof value === "boolean" ? String(value) : value);
75073
+ }
75074
+ return url.toString();
75075
+ }
75076
+ function buildGoogleDriveUploadUrl(fileId, params) {
75077
+ const url = new URL(`https://www.googleapis.com/upload/drive/v3/files/${encodeURIComponent(fileId)}`);
75078
+ for (const [key, value] of Object.entries(params)) {
75079
+ if (value === void 0) {
75080
+ continue;
75081
+ }
75082
+ url.searchParams.set(key, typeof value === "boolean" ? String(value) : value);
75083
+ }
75084
+ return url.toString();
75085
+ }
75086
+ async function fetchGoogleDriveMetadata(config) {
75087
+ const response = await fetch(buildGoogleDriveFileUrl(config.fileId, {
75088
+ fields: "id,name,modifiedTime,size,md5Checksum",
75089
+ supportsAllDrives: config.supportsAllDrives
75090
+ }), {
75091
+ headers: {
75092
+ Authorization: `Bearer ${config.accessToken}`
75093
+ }
75094
+ });
75095
+ if (!response.ok) {
75096
+ throw new Error(`Google Drive metadata request failed (${response.status}): ${await readResponseMessage(response)}`);
75097
+ }
75098
+ const payload = await response.json();
75099
+ return {
75100
+ name: normalizeNonEmptyString(payload?.name),
75101
+ modifiedTime: normalizeNonEmptyString(payload?.modifiedTime),
75102
+ size: normalizeNonEmptyString(payload?.size),
75103
+ md5Checksum: normalizeNonEmptyString(payload?.md5Checksum)
75104
+ };
75105
+ }
75106
+ async function downloadGoogleDriveArchive(config) {
75107
+ const metadata = await fetchGoogleDriveMetadata(config);
75108
+ const response = await fetch(buildGoogleDriveFileUrl(config.fileId, {
75109
+ alt: "media",
75110
+ supportsAllDrives: config.supportsAllDrives
75111
+ }), {
75112
+ headers: {
75113
+ Authorization: `Bearer ${config.accessToken}`
75114
+ }
75115
+ });
75116
+ if (!response.ok) {
75117
+ throw new Error(`Google Drive download failed (${response.status}): ${await readResponseMessage(response)}`);
75118
+ }
75119
+ const arrayBuffer = await response.arrayBuffer();
75120
+ return {
75121
+ buffer: Buffer.from(arrayBuffer),
75122
+ signature: createGoogleDriveArchiveSignature(metadata),
75123
+ label: metadata.name ?? `Google Drive:${config.fileId}`
75124
+ };
75125
+ }
75126
+ async function uploadGoogleDriveArchive(config, buffer) {
75127
+ const response = await fetch(buildGoogleDriveUploadUrl(config.fileId, {
75128
+ uploadType: "media",
75129
+ fields: "id,name,modifiedTime,size,md5Checksum",
75130
+ supportsAllDrives: config.supportsAllDrives
75131
+ }), {
75132
+ method: "PATCH",
75133
+ headers: {
75134
+ Authorization: `Bearer ${config.accessToken}`,
75135
+ "Content-Type": "application/octet-stream"
75136
+ },
75137
+ body: new Uint8Array(buffer)
75138
+ });
75139
+ if (!response.ok) {
75140
+ throw new Error(`Google Drive upload failed (${response.status}): ${await readResponseMessage(response)}`);
75141
+ }
75142
+ const payload = await response.json();
75143
+ const metadata = {
75144
+ name: normalizeNonEmptyString(payload?.name),
75145
+ modifiedTime: normalizeNonEmptyString(payload?.modifiedTime),
75146
+ size: normalizeNonEmptyString(payload?.size),
75147
+ md5Checksum: normalizeNonEmptyString(payload?.md5Checksum)
75148
+ };
75149
+ return {
75150
+ buffer,
75151
+ signature: createGoogleDriveArchiveSignature(metadata),
75152
+ label: metadata.name ?? `Google Drive:${config.fileId}`
75153
+ };
75154
+ }
75155
+ function resolveGoogleDriveAccessToken(config) {
75156
+ const explicitToken = normalizeNonEmptyString(config?.accessToken);
75157
+ const configuredEnvName = normalizeNonEmptyString(config?.accessTokenEnv);
75158
+ const configuredEnvToken = configuredEnvName ? normalizeNonEmptyString(process.env[configuredEnvName]) : void 0;
75159
+ const defaultEnvToken = normalizeNonEmptyString(process.env[DEFAULT_GOOGLE_DRIVE_TOKEN_ENV]);
75160
+ const token = explicitToken ?? configuredEnvToken ?? defaultEnvToken;
75161
+ if (token) {
75162
+ return token;
75163
+ }
75164
+ if (configuredEnvName) {
75165
+ throw new Error(`Google Drive access token not found in environment variable ${configuredEnvName}.`);
75166
+ }
75167
+ throw new Error(`Google Drive access token is required. Provide googleDrive.accessToken, googleDrive.accessTokenEnv, or set ${DEFAULT_GOOGLE_DRIVE_TOKEN_ENV}.`);
75168
+ }
75169
+ function parseGoogleDriveArchiveSpecifier(value) {
75170
+ const match = value.match(/^(?:gdrive|google-drive):\/\/(.+)$/i);
75171
+ if (!match) {
75172
+ return void 0;
75173
+ }
75174
+ const fileId = match[1]?.trim();
75175
+ return fileId && fileId.length > 0 ? fileId : void 0;
75176
+ }
75177
+ function resolveGoogleDriveConfig(archiveSpecifier, googleDrive) {
75178
+ const fileId = normalizeNonEmptyString(googleDrive?.fileId) ?? parseGoogleDriveArchiveSpecifier(archiveSpecifier);
75179
+ if (!fileId) {
75180
+ return void 0;
75181
+ }
75182
+ return {
75183
+ fileId,
75184
+ accessToken: resolveGoogleDriveAccessToken(googleDrive),
75185
+ accessTokenEnv: normalizeNonEmptyString(googleDrive?.accessTokenEnv),
75186
+ supportsAllDrives: googleDrive?.supportsAllDrives ?? false
75187
+ };
75188
+ }
75189
+ function createLocalArchiveHandle(archivePath) {
75190
+ const resolvedArchivePath = (0, import_node_path2.resolve)(archivePath);
75191
+ const readLocalBuffer = () => {
75192
+ if (!(0, import_node_fs2.existsSync)(resolvedArchivePath)) {
75193
+ throw new Error(`WAPK file not found: ${resolvedArchivePath}`);
75194
+ }
75195
+ return (0, import_node_fs2.readFileSync)(resolvedArchivePath);
75196
+ };
75197
+ return {
75198
+ identifier: resolvedArchivePath,
75199
+ label: (0, import_node_path2.basename)(resolvedArchivePath),
75200
+ readSnapshot: async () => ({
75201
+ buffer: readLocalBuffer(),
75202
+ signature: getLocalArchiveSignature(resolvedArchivePath),
75203
+ label: (0, import_node_path2.basename)(resolvedArchivePath)
75204
+ }),
75205
+ getSignature: async () => getLocalArchiveSignature(resolvedArchivePath),
75206
+ writeBuffer: async (buffer) => {
75207
+ (0, import_node_fs2.writeFileSync)(resolvedArchivePath, buffer);
75208
+ return {
75209
+ buffer,
75210
+ signature: getLocalArchiveSignature(resolvedArchivePath),
75211
+ label: (0, import_node_path2.basename)(resolvedArchivePath)
75212
+ };
75213
+ }
75214
+ };
75215
+ }
75216
+ function createGoogleDriveArchiveHandle(config) {
75217
+ const identifier = `gdrive://${config.fileId}`;
75218
+ const label = `Google Drive:${config.fileId}`;
75219
+ return {
75220
+ identifier,
75221
+ label,
75222
+ readSnapshot: async () => downloadGoogleDriveArchive(config),
75223
+ getSignature: async () => createGoogleDriveArchiveSignature(await fetchGoogleDriveMetadata(config)),
75224
+ writeBuffer: async (buffer) => uploadGoogleDriveArchive(config, buffer)
75225
+ };
75226
+ }
75227
+ function resolveArchiveHandle(archiveSpecifier, googleDrive) {
75228
+ const googleDriveConfig = resolveGoogleDriveConfig(archiveSpecifier, googleDrive);
75229
+ if (googleDriveConfig) {
75230
+ return createGoogleDriveArchiveHandle(googleDriveConfig);
75231
+ }
75232
+ return createLocalArchiveHandle(archiveSpecifier);
75233
+ }
75234
+ async function writeWapkArchiveFromMemory(archiveHandle, header, files, lock) {
74982
75235
  const updatedHeader = {
74983
75236
  ...header,
74984
75237
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
74985
75238
  };
74986
- (0, import_node_fs2.writeFileSync)(archivePath, encodeWapk(updatedHeader, files, lock));
75239
+ const snapshot = await archiveHandle.writeBuffer(encodeWapk(updatedHeader, files, lock));
75240
+ return {
75241
+ header: updatedHeader,
75242
+ signature: snapshot.signature,
75243
+ label: snapshot.label ?? archiveHandle.label
75244
+ };
75245
+ }
75246
+ function removeEmptyParentDirectories(directory, rootDir) {
75247
+ let currentDir = directory;
75248
+ while (true) {
75249
+ const relativeDir = (0, import_node_path2.relative)(rootDir, currentDir);
75250
+ if (!relativeDir || relativeDir.startsWith("..") || (0, import_node_path2.isAbsolute)(relativeDir)) {
75251
+ return;
75252
+ }
75253
+ try {
75254
+ if ((0, import_node_fs2.readdirSync)(currentDir).length > 0) {
75255
+ return;
75256
+ }
75257
+ (0, import_node_fs2.rmSync)(currentDir, { recursive: false, force: true });
75258
+ } catch {
75259
+ return;
75260
+ }
75261
+ currentDir = (0, import_node_path2.dirname)(currentDir);
75262
+ }
75263
+ }
75264
+ function applyArchiveFilesToWorkDir(directory, files) {
75265
+ const existingFiles = collectRuntimeSyncFiles(directory);
75266
+ const nextPaths = new Set(files.map((file) => file.path));
75267
+ for (const file of existingFiles) {
75268
+ if (nextPaths.has(file.path)) {
75269
+ continue;
75270
+ }
75271
+ const filePath = (0, import_node_path2.join)(directory, ...file.path.split("/"));
75272
+ (0, import_node_fs2.rmSync)(filePath, { force: true });
75273
+ removeEmptyParentDirectories((0, import_node_path2.dirname)(filePath), directory);
75274
+ }
75275
+ extractFiles(files, directory);
75276
+ }
75277
+ async function readArchiveRuntimeState(archiveHandle, lock) {
75278
+ const snapshot = await archiveHandle.readSnapshot();
75279
+ const decoded = decodeWapk(snapshot.buffer, lock ? { password: lock.password } : {});
75280
+ return {
75281
+ header: decoded.header,
75282
+ files: filterRuntimeSyncFiles(decoded.files),
75283
+ signature: snapshot.signature,
75284
+ label: snapshot.label ?? archiveHandle.label
75285
+ };
74987
75286
  }
74988
75287
  function createWapkLiveSync(prepared) {
74989
75288
  let memoryFiles = collectRuntimeSyncFiles(prepared.workDir);
74990
75289
  const syncInterval = prepared.syncInterval ?? 300;
75290
+ const archiveSyncInterval = prepared.archiveSyncInterval ?? syncInterval;
75291
+ const watchArchive = prepared.watchArchive ?? true;
75292
+ let currentHeader = prepared.header;
75293
+ let currentArchiveLabel = prepared.archiveLabel;
74991
75294
  let stopped = false;
74992
- const flush = () => {
74993
- if (stopped) return;
74994
- const nextFiles = collectRuntimeSyncFiles(prepared.workDir);
74995
- if (filesEqual(memoryFiles, nextFiles)) {
74996
- return;
75295
+ let lastArchiveSignature = prepared.archiveSignature;
75296
+ let lastArchivePollAt = 0;
75297
+ let pendingOperation = Promise.resolve();
75298
+ const reportSyncError = (error) => {
75299
+ console.warn(
75300
+ `[wapk] Sync error for ${currentArchiveLabel}: ${error instanceof Error ? error.message : String(error)}`
75301
+ );
75302
+ };
75303
+ const pullArchiveChanges = async () => {
75304
+ if (!watchArchive) {
75305
+ return false;
75306
+ }
75307
+ const archiveSignature = await prepared.archiveHandle.getSignature();
75308
+ if (!archiveSignature || archiveSignature === lastArchiveSignature) {
75309
+ return false;
75310
+ }
75311
+ try {
75312
+ const archiveState = await readArchiveRuntimeState(prepared.archiveHandle, prepared.lock);
75313
+ lastArchiveSignature = archiveState.signature ?? archiveSignature;
75314
+ currentHeader = archiveState.header;
75315
+ currentArchiveLabel = archiveState.label;
75316
+ if (filesEqual(memoryFiles, archiveState.files)) {
75317
+ return false;
75318
+ }
75319
+ applyArchiveFilesToWorkDir(prepared.workDir, archiveState.files);
75320
+ memoryFiles = archiveState.files;
75321
+ return true;
75322
+ } catch (error) {
75323
+ console.warn(
75324
+ `[wapk] Failed to pull external archive changes from ${currentArchiveLabel}: ${error instanceof Error ? error.message : String(error)}`
75325
+ );
75326
+ return false;
74997
75327
  }
74998
- memoryFiles = nextFiles;
74999
- writeWapkArchiveFromMemory(prepared.archivePath, prepared.header, memoryFiles, prepared.lock);
75328
+ };
75329
+ const flush = () => {
75330
+ pendingOperation = pendingOperation.catch(() => void 0).then(async () => {
75331
+ if (stopped) return;
75332
+ const nextFiles = collectRuntimeSyncFiles(prepared.workDir);
75333
+ const localDirty = !filesEqual(memoryFiles, nextFiles);
75334
+ const now = Date.now();
75335
+ const shouldPollArchive = watchArchive && (lastArchivePollAt === 0 || now - lastArchivePollAt >= archiveSyncInterval);
75336
+ if (!localDirty && shouldPollArchive) {
75337
+ lastArchivePollAt = now;
75338
+ await pullArchiveChanges();
75339
+ return;
75340
+ }
75341
+ if (!localDirty) {
75342
+ return;
75343
+ }
75344
+ if (shouldPollArchive) {
75345
+ lastArchivePollAt = now;
75346
+ const archiveSignature = await prepared.archiveHandle.getSignature();
75347
+ if (archiveSignature && archiveSignature !== lastArchiveSignature) {
75348
+ console.warn(
75349
+ `[wapk] Both the workdir and ${currentArchiveLabel} changed; writing local workdir changes back to the archive.`
75350
+ );
75351
+ }
75352
+ }
75353
+ memoryFiles = nextFiles;
75354
+ const writeResult = await writeWapkArchiveFromMemory(prepared.archiveHandle, currentHeader, memoryFiles, prepared.lock);
75355
+ currentHeader = writeResult.header;
75356
+ currentArchiveLabel = writeResult.label;
75357
+ lastArchiveSignature = writeResult.signature ?? await prepared.archiveHandle.getSignature();
75358
+ });
75359
+ return pendingOperation;
75360
+ };
75361
+ const scheduleFlush = () => {
75362
+ void flush().catch(reportSyncError);
75000
75363
  };
75001
75364
  if (prepared.useWatcher) {
75002
75365
  const watcher = (0, import_node_fs2.watch)(prepared.workDir, { recursive: true }, () => {
75003
- flush();
75366
+ scheduleFlush();
75004
75367
  });
75005
- const stop2 = () => {
75006
- flush();
75007
- stopped = true;
75368
+ const archiveTimer = watchArchive ? setInterval(() => {
75369
+ scheduleFlush();
75370
+ }, archiveSyncInterval) : void 0;
75371
+ archiveTimer?.unref?.();
75372
+ const stop2 = async () => {
75373
+ if (stopped) return pendingOperation;
75008
75374
  watcher.close();
75375
+ if (archiveTimer) {
75376
+ clearInterval(archiveTimer);
75377
+ }
75378
+ await flush();
75379
+ stopped = true;
75380
+ await pendingOperation;
75009
75381
  };
75010
75382
  return { flush, stop: stop2 };
75011
75383
  }
75012
- const timer = setInterval(flush, syncInterval);
75384
+ const timer = setInterval(scheduleFlush, watchArchive ? Math.min(syncInterval, archiveSyncInterval) : syncInterval);
75013
75385
  timer.unref?.();
75014
- const stop = () => {
75015
- flush();
75016
- stopped = true;
75386
+ const stop = async () => {
75387
+ if (stopped) return;
75017
75388
  clearInterval(timer);
75389
+ await flush();
75390
+ stopped = true;
75391
+ await pendingOperation;
75018
75392
  };
75019
75393
  return { flush, stop };
75020
75394
  }
@@ -75155,12 +75529,11 @@ function extractWapkArchive(wapkPath, outputDir = ".", options = {}) {
75155
75529
  console.log(`Extracted ${archive.files.length} files to: ${extractDirectory}`);
75156
75530
  return extractDirectory;
75157
75531
  }
75158
- function prepareWapkApp(wapkPath, options = {}) {
75159
- const archivePath = (0, import_node_path2.resolve)(wapkPath);
75160
- if (!(0, import_node_fs2.existsSync)(archivePath)) {
75161
- throw new Error(`WAPK file not found: ${archivePath}`);
75162
- }
75163
- const buffer = (0, import_node_fs2.readFileSync)(archivePath);
75532
+ async function prepareWapkApp(wapkPath, options = {}) {
75533
+ const archiveHandle = resolveArchiveHandle(wapkPath, options.googleDrive);
75534
+ const archivePath = archiveHandle.identifier;
75535
+ const snapshot = await archiveHandle.readSnapshot();
75536
+ const buffer = snapshot.buffer;
75164
75537
  const envelope = parseWapkEnvelope(buffer);
75165
75538
  const lock = envelope.version === WAPK_LOCKED_VERSION ? resolveArchiveCredentials(options) : void 0;
75166
75539
  const decoded = decodeWapk(buffer, options);
@@ -75175,12 +75548,17 @@ function prepareWapkApp(wapkPath, options = {}) {
75175
75548
  }
75176
75549
  return {
75177
75550
  archivePath,
75551
+ archiveLabel: snapshot.label ?? archiveHandle.label,
75552
+ archiveHandle,
75553
+ archiveSignature: snapshot.signature,
75178
75554
  workDir,
75179
75555
  entryPath,
75180
75556
  header: decoded.header,
75181
75557
  runtime: runtime2,
75182
75558
  syncInterval: options.syncInterval,
75183
75559
  useWatcher: options.useWatcher,
75560
+ watchArchive: options.watchArchive,
75561
+ archiveSyncInterval: options.archiveSyncInterval,
75184
75562
  lock
75185
75563
  };
75186
75564
  }
@@ -75219,7 +75597,7 @@ async function runPreparedWapkApp(prepared) {
75219
75597
  } finally {
75220
75598
  process.off("SIGINT", onSigInt);
75221
75599
  process.off("SIGTERM", onSigTerm);
75222
- sync.stop();
75600
+ await sync.stop();
75223
75601
  (0, import_node_fs2.rmSync)(prepared.workDir, { recursive: true, force: true });
75224
75602
  }
75225
75603
  }
@@ -75263,11 +75641,13 @@ function printWapkHelp() {
75263
75641
  "WAPK packaging for Elit",
75264
75642
  "",
75265
75643
  "Usage:",
75266
- " elit wapk <file.wapk>",
75267
- " elit wapk run <file.wapk>",
75268
- " elit wapk run <file.wapk> --runtime node|bun|deno",
75269
- " elit wapk run <file.wapk> --sync-interval 100",
75270
- " elit wapk run <file.wapk> --watcher",
75644
+ " elit wapk [file.wapk]",
75645
+ " elit wapk gdrive://<fileId>",
75646
+ " elit wapk run [file.wapk]",
75647
+ " elit wapk run --google-drive-file-id <fileId> --google-drive-token-env <env>",
75648
+ " elit wapk run [file.wapk] --runtime node|bun|deno",
75649
+ " elit wapk run [file.wapk] --sync-interval 100",
75650
+ " elit wapk run [file.wapk] --watcher",
75271
75651
  " elit wapk pack [directory]",
75272
75652
  " elit wapk pack [directory] --password secret-123",
75273
75653
  " elit wapk pack [directory] --include-deps",
@@ -75277,14 +75657,23 @@ function printWapkHelp() {
75277
75657
  "Options:",
75278
75658
  " -r, --runtime <name> Runtime override: node, bun, deno",
75279
75659
  " --sync-interval <ms> Polling interval for live sync (ms, default 300)",
75660
+ " --archive-sync-interval <ms> Polling interval for reading archive source changes",
75280
75661
  " --watcher, --use-watcher Use event-driven file watcher instead of polling",
75662
+ " --archive-watch Pull external archive changes back into the temp workdir",
75663
+ " --no-archive-watch Disable external archive read sync",
75664
+ " --google-drive-file-id <id> Run a remote .wapk directly from Google Drive",
75665
+ " --google-drive-token-env <name> Env var containing the Google Drive OAuth token",
75666
+ " --google-drive-access-token <value> OAuth token for Google Drive API calls",
75667
+ " --google-drive-shared-drive Include supportsAllDrives=true for shared drives",
75281
75668
  " --include-deps Include node_modules in the archive",
75282
75669
  " --password <value> Password for locking or unlocking the archive",
75283
75670
  " -h, --help Show this help",
75284
75671
  "",
75285
75672
  "Notes:",
75286
75673
  " - Pack reads wapk from elit.config.* and falls back to package.json.",
75287
- " - Run mode keeps files in RAM and syncs changes back to the .wapk file.",
75674
+ " - Run mode can read config.wapk.run for default file/runtime/live-sync options.",
75675
+ " - Run mode keeps files in RAM and syncs changes both to and from the archive source.",
75676
+ " - Google Drive mode talks to the Drive API directly; no local archive file is required.",
75288
75677
  " - Locked archives require the same password for run/extract/inspect.",
75289
75678
  " - Archives stay unlocked by default unless a password is provided.",
75290
75679
  " - Use --watcher for faster file change detection (less CPU usage).",
@@ -75325,9 +75714,12 @@ function parseArchiveAccessArgs(args, usage) {
75325
75714
  }
75326
75715
  function parseRunArgs(args) {
75327
75716
  let file;
75717
+ let googleDrive;
75328
75718
  let runtime2;
75329
75719
  let syncInterval;
75330
- let useWatcher = false;
75720
+ let useWatcher;
75721
+ let watchArchive;
75722
+ let archiveSyncInterval;
75331
75723
  let password;
75332
75724
  for (let index = 0; index < args.length; index++) {
75333
75725
  const arg = args[index];
@@ -75349,11 +75741,55 @@ function parseRunArgs(args) {
75349
75741
  syncInterval = value;
75350
75742
  break;
75351
75743
  }
75744
+ case "--archive-sync-interval": {
75745
+ const value = parseInt(readRequiredOptionValue(args, ++index, "--archive-sync-interval"), 10);
75746
+ if (Number.isNaN(value) || value < 50) {
75747
+ throw new Error("--archive-sync-interval must be a number >= 50 (milliseconds)");
75748
+ }
75749
+ archiveSyncInterval = value;
75750
+ break;
75751
+ }
75352
75752
  case "--use-watcher":
75353
75753
  case "--watcher": {
75354
75754
  useWatcher = true;
75355
75755
  break;
75356
75756
  }
75757
+ case "--archive-watch": {
75758
+ watchArchive = true;
75759
+ break;
75760
+ }
75761
+ case "--no-archive-watch": {
75762
+ watchArchive = false;
75763
+ break;
75764
+ }
75765
+ case "--google-drive-file-id": {
75766
+ googleDrive = {
75767
+ ...googleDrive,
75768
+ fileId: readRequiredOptionValue(args, ++index, "--google-drive-file-id")
75769
+ };
75770
+ break;
75771
+ }
75772
+ case "--google-drive-token-env": {
75773
+ googleDrive = {
75774
+ ...googleDrive,
75775
+ accessTokenEnv: readRequiredOptionValue(args, ++index, "--google-drive-token-env")
75776
+ };
75777
+ break;
75778
+ }
75779
+ case "--google-drive-access-token": {
75780
+ googleDrive = {
75781
+ ...googleDrive,
75782
+ accessToken: readRequiredOptionValue(args, ++index, "--google-drive-access-token")
75783
+ };
75784
+ break;
75785
+ }
75786
+ case "--google-drive-shared-drive": {
75787
+ googleDrive = {
75788
+ ...googleDrive,
75789
+ supportsAllDrives: true
75790
+ };
75791
+ break;
75792
+ }
75357
75793
  case "--password":
75358
75794
  password = readRequiredOptionValue(args, ++index, "--password");
75359
75795
  break;
@@ -75368,10 +75804,7 @@ function parseRunArgs(args) {
75368
75804
  break;
75369
75805
  }
75370
75806
  }
75371
- if (!file) {
75372
- throw new Error("Usage: elit wapk run <file.wapk>");
75373
- }
75374
- return { file, runtime: runtime2, syncInterval, useWatcher, password };
75807
+ return { file, googleDrive, runtime: runtime2, syncInterval, useWatcher, watchArchive, archiveSyncInterval, password };
75375
75808
  }
75376
75809
  function parsePackArgs(args) {
75377
75810
  let directory = ".";
@@ -75397,8 +75830,63 @@ function parsePackArgs(args) {
75397
75830
  }
75398
75831
  return { directory, includeDeps, password };
75399
75832
  }
75400
- async function runWapkCommand(args) {
75401
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
75833
+ async function readConfiguredWapkRunDefaults(cwd) {
75834
+ const config = await loadConfig(cwd);
75835
+ const runConfig = normalizeWapkRunConfig(config?.wapk?.run);
75836
+ const fallbackPassword = normalizeNonEmptyString(config?.wapk?.lock?.password);
75837
+ if (!runConfig) {
75838
+ return fallbackPassword ? { password: fallbackPassword } : void 0;
75839
+ }
75840
+ if (!runConfig.password && fallbackPassword) {
75841
+ runConfig.password = fallbackPassword;
75842
+ }
75843
+ if (runConfig.file && runConfig.googleDrive?.fileId) {
75844
+ throw new Error("config.wapk.run.file and config.wapk.run.googleDrive.fileId are mutually exclusive.");
75845
+ }
75846
+ return runConfig;
75847
+ }
75848
+ function mergeGoogleDriveRunConfig(cliConfig, defaultConfig) {
75849
+ if (!cliConfig && !defaultConfig) {
75850
+ return void 0;
75851
+ }
75852
+ const merged = {
75853
+ fileId: normalizeNonEmptyString(cliConfig?.fileId) ?? normalizeNonEmptyString(defaultConfig?.fileId),
75854
+ accessToken: normalizeNonEmptyString(cliConfig?.accessToken) ?? normalizeNonEmptyString(defaultConfig?.accessToken),
75855
+ accessTokenEnv: normalizeNonEmptyString(cliConfig?.accessTokenEnv) ?? normalizeNonEmptyString(defaultConfig?.accessTokenEnv),
75856
+ supportsAllDrives: cliConfig?.supportsAllDrives ?? defaultConfig?.supportsAllDrives
75857
+ };
75858
+ return Object.values(merged).some((entry) => entry !== void 0) ? merged : void 0;
75859
+ }
75860
+ function resolveConfiguredWapkRunOptions(options, defaults) {
75861
+ return {
75862
+ file: options.file ?? defaults?.file,
75863
+ googleDrive: mergeGoogleDriveRunConfig(options.googleDrive, defaults?.googleDrive),
75864
+ runtime: options.runtime ?? defaults?.runtime,
75865
+ syncInterval: options.syncInterval ?? defaults?.syncInterval,
75866
+ useWatcher: options.useWatcher ?? defaults?.useWatcher,
75867
+ watchArchive: options.watchArchive ?? defaults?.watchArchive,
75868
+ archiveSyncInterval: options.archiveSyncInterval ?? defaults?.archiveSyncInterval,
75869
+ password: options.password ?? defaults?.password
75870
+ };
75871
+ }
75872
+ function resolveRunArchivePath(file, cwd) {
75873
+ return (0, import_node_path2.isAbsolute)(file) ? file : (0, import_node_path2.resolve)(cwd, file);
75874
+ }
75875
+ function resolveRunArchiveSpecifier(file, googleDrive, cwd) {
75876
+ const googleDriveFileId = normalizeNonEmptyString(googleDrive?.fileId);
75877
+ if (googleDriveFileId) {
75878
+ if (file && !parseGoogleDriveArchiveSpecifier(file)) {
75879
+ throw new Error("WAPK run cannot use both a local archive file and googleDrive.fileId at the same time.");
75880
+ }
75881
+ return `gdrive://${googleDriveFileId}`;
75882
+ }
75883
+ if (!file) {
75884
+ return void 0;
75885
+ }
75886
+ return parseGoogleDriveArchiveSpecifier(file) ? file : resolveRunArchivePath(file, cwd);
75887
+ }
75888
+ async function runWapkCommand(args, cwd = process.cwd()) {
75889
+ if (args.includes("--help") || args.includes("-h")) {
75402
75890
  printWapkHelp();
75403
75891
  return;
75404
75892
  }
@@ -75420,11 +75908,24 @@ async function runWapkCommand(args) {
75420
75908
  extractWapkArchive(options.file, ".", options);
75421
75909
  return;
75422
75910
  }
75423
- const runOptions = args[0] === "run" ? parseRunArgs(args.slice(1)) : parseRunArgs(args);
75424
- const prepared = prepareWapkApp(runOptions.file, {
75911
+ const parsedRunOptions = args[0] === "run" ? parseRunArgs(args.slice(1)) : parseRunArgs(args);
75912
+ const configuredRunDefaults = await readConfiguredWapkRunDefaults(cwd);
75913
+ const runOptions = resolveConfiguredWapkRunOptions(parsedRunOptions, configuredRunDefaults);
75914
+ const archiveSpecifier = resolveRunArchiveSpecifier(runOptions.file, runOptions.googleDrive, cwd);
75915
+ if (!archiveSpecifier) {
75916
+ if (args.length === 0) {
75917
+ printWapkHelp();
75918
+ return;
75919
+ }
75920
+ throw new Error("Usage: elit wapk run <file.wapk>");
75921
+ }
75922
+ const prepared = await prepareWapkApp(archiveSpecifier, {
75923
+ googleDrive: runOptions.googleDrive,
75425
75924
  runtime: runOptions.runtime,
75426
75925
  syncInterval: runOptions.syncInterval,
75427
75926
  useWatcher: runOptions.useWatcher,
75927
+ watchArchive: runOptions.watchArchive,
75928
+ archiveSyncInterval: runOptions.archiveSyncInterval,
75428
75929
  password: runOptions.password
75429
75930
  });
75430
75931
  const exitCode = await runPreparedWapkApp(prepared);
@@ -75851,7 +76352,7 @@ async function runDesktopWapkCommand(args, config) {
75851
76352
  return;
75852
76353
  }
75853
76354
  const options = parseDesktopWapkRunArgs(args, config?.wapk);
75854
- const preparedApp = prepareWapkApp(options.file, {
76355
+ const preparedApp = await prepareWapkApp(options.file, {
75855
76356
  runtime: options.runtime,
75856
76357
  syncInterval: options.syncInterval,
75857
76358
  useWatcher: options.useWatcher,
@@ -75870,7 +76371,7 @@ async function runDesktopWapkCommand(args, config) {
75870
76371
  process.exit(exitCode);
75871
76372
  }
75872
76373
  } finally {
75873
- liveSync.stop();
76374
+ await liveSync.stop();
75874
76375
  (0, import_node_fs3.rmSync)(preparedApp.workDir, { recursive: true, force: true });
75875
76376
  cleanupPreparedEntry(preparedEntry);
75876
76377
  }
@@ -76953,7 +77454,7 @@ function openMobileProject(platform, options) {
76953
77454
  throw new Error(`Android project not found at ${projectPath}. Run "elit mobile init" first.`);
76954
77455
  }
76955
77456
  if (process.platform === "win32") {
76956
- runCommand("cmd", ["/c", "start", "", projectPath], options.cwd);
77457
+ runCommand("explorer.exe", [projectPath], options.cwd);
76957
77458
  return;
76958
77459
  }
76959
77460
  if (process.platform === "darwin") {
@@ -77159,10 +77660,11 @@ function commandExists(command, cwd) {
77159
77660
  });
77160
77661
  return result2.status === 0;
77161
77662
  }
77162
- function resolveCommandPath(command, cwd) {
77663
+ function resolveCommandPath(command, cwd, env) {
77163
77664
  const checker = process.platform === "win32" ? "where" : "which";
77164
77665
  const result2 = (0, import_node_child_process3.spawnSync)(checker, [command], {
77165
77666
  cwd,
77667
+ env,
77166
77668
  encoding: "utf8",
77167
77669
  shell: false
77168
77670
  });
@@ -77223,7 +77725,13 @@ function runGradle(cwd, args) {
77223
77725
  '[mobile] Gradle not found. Install Gradle and add it to PATH, or generate wrapper files in android/ with "gradle wrapper".'
77224
77726
  );
77225
77727
  }
77226
- runCommand(gradleCommand.command, args, androidRoot);
77728
+ const env = gradleCommand.prependPath ? prependCommandPath(gradleCommand.prependPath) : void 0;
77729
+ if (process.platform === "win32" && gradleCommand.useWindowsBatchShell) {
77730
+ const shellCommand = gradleCommand.batchCommandPath ?? resolveCommandPath(gradleCommand.command, androidRoot, env) ?? gradleCommand.command;
77731
+ runWindowsBatchCommand(shellCommand, args, androidRoot);
77732
+ return;
77733
+ }
77734
+ runCommand(gradleCommand.command, args, androidRoot, env);
77227
77735
  }
77228
77736
  function resolveGradleCommand(cwd) {
77229
77737
  const androidRoot = (0, import_node_path4.join)(cwd, "android");
@@ -77232,22 +77740,31 @@ function resolveGradleCommand(cwd) {
77232
77740
  if ((0, import_node_fs4.existsSync)(wrapperPath)) {
77233
77741
  return {
77234
77742
  command: wrapper,
77235
- details: "Using project gradle wrapper."
77743
+ batchCommandPath: wrapperPath,
77744
+ details: "Using project gradle wrapper.",
77745
+ useWindowsBatchShell: process.platform === "win32"
77236
77746
  };
77237
77747
  }
77238
77748
  if (commandExists("gradle", androidRoot)) {
77239
77749
  return {
77240
77750
  command: "gradle",
77241
- details: "Using Gradle from PATH."
77751
+ batchCommandPath: process.platform === "win32" ? resolveCommandPath("gradle", androidRoot) ?? "gradle" : void 0,
77752
+ details: "Using Gradle from PATH.",
77753
+ useWindowsBatchShell: process.platform === "win32"
77242
77754
  };
77243
77755
  }
77244
77756
  const fallbackGradle = resolveFallbackGradleExecutable();
77245
77757
  if (!fallbackGradle) {
77246
77758
  return void 0;
77247
77759
  }
77760
+ const prependPath = process.platform === "win32" ? (0, import_node_path4.dirname)(fallbackGradle) : void 0;
77761
+ const fallbackEnv = prependPath ? prependCommandPath(prependPath) : void 0;
77248
77762
  return {
77249
- command: fallbackGradle,
77250
- details: `Using fallback Gradle at ${fallbackGradle}.`
77763
+ command: process.platform === "win32" ? "gradle" : fallbackGradle,
77764
+ batchCommandPath: process.platform === "win32" ? resolveCommandPath("gradle", androidRoot, fallbackEnv) ?? void 0 : void 0,
77765
+ details: `Using fallback Gradle at ${fallbackGradle}.`,
77766
+ prependPath,
77767
+ useWindowsBatchShell: process.platform === "win32"
77251
77768
  };
77252
77769
  }
77253
77770
  function resolveFallbackGradleExecutable() {
@@ -77403,26 +77920,28 @@ function upsertXmlAttribute(tag, name, value) {
77403
77920
  }
77404
77921
  return `${tag.slice(0, -1)} ${name}='${value}'>`;
77405
77922
  }
77406
- var WIN_CMD_META = /([()%!^"\`<>&|;, *?])/g;
77407
- function escapeWindowsShellArg(value) {
77408
- const quoted = `"${value.replace(/(\\*)"/, '$1$1\\"').replace(/(\\*)$/, "$1$1")}"`;
77409
- return quoted.replace(WIN_CMD_META, "^$1");
77410
- }
77411
- function spawnWin32Safe(command, args, cwd, stdio) {
77412
- const safeCommand = (0, import_node_path4.normalize)(command).replace(WIN_CMD_META, "^$1");
77413
- const safeArgs = args.map(escapeWindowsShellArg);
77414
- const commandLine = `"${[safeCommand, ...safeArgs].join(" ")}"`;
77415
- const comSpec = process.env.ComSpec || "cmd.exe";
77416
- return (0, import_node_child_process3.spawnSync)(comSpec, ["/d", "/s", "/c", commandLine], {
77923
+ function prependCommandPath(pathEntry) {
77924
+ const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path") ?? "PATH";
77925
+ const currentPath = process.env[pathKey];
77926
+ const delimiter2 = process.platform === "win32" ? ";" : ":";
77927
+ return {
77928
+ ...process.env,
77929
+ [pathKey]: currentPath && currentPath.length > 0 ? `${pathEntry}${delimiter2}${currentPath}` : pathEntry
77930
+ };
77931
+ }
77932
+ function runWindowsBatchCommand(command, args, cwd) {
77933
+ const result2 = (0, import_node_child_process3.spawnSync)((0, import_node_path4.normalize)(command), args, {
77417
77934
  cwd,
77418
- stdio,
77419
- shell: false,
77420
- windowsVerbatimArguments: true
77935
+ stdio: "inherit",
77936
+ shell: false
77421
77937
  });
77938
+ if (typeof result2.status === "number" && result2.status !== 0) {
77939
+ process.exit(result2.status);
77940
+ }
77422
77941
  }
77423
- function runCommand(command, args, cwd) {
77942
+ function runCommand(command, args, cwd, env) {
77424
77943
  const normalizedCommand = (0, import_node_path4.normalize)(command);
77425
- const result2 = process.platform === "win32" ? spawnWin32Safe(normalizedCommand, args, cwd, "inherit") : (0, import_node_child_process3.spawnSync)(normalizedCommand, args, { cwd, stdio: "inherit", shell: false });
77944
+ const result2 = (0, import_node_child_process3.spawnSync)(normalizedCommand, args, { cwd, env, stdio: "inherit", shell: false });
77426
77945
  if (typeof result2.status === "number" && result2.status !== 0) {
77427
77946
  process.exit(result2.status);
77428
77947
  }
@@ -78555,8 +79074,1812 @@ Notes:
78555
79074
  `);
78556
79075
  }
78557
79076
 
79077
+ // src/pm-cli.ts
79078
+ var import_node_child_process4 = require("child_process");
79079
+ var import_node_fs5 = require("fs");
79080
+ var import_node_os2 = require("os");
79081
+ var import_node_path5 = require("path");
79082
+ var DEFAULT_PM_DATA_DIR = (0, import_node_path5.join)(".elit", "pm");
79083
+ var DEFAULT_PM_DUMP_FILE = "dump.json";
79084
+ var DEFAULT_RESTART_DELAY = 1e3;
79085
+ var DEFAULT_MAX_RESTARTS = 10;
79086
+ var DEFAULT_WATCH_DEBOUNCE = 250;
79087
+ var DEFAULT_MIN_UPTIME = 0;
79088
+ var DEFAULT_HEALTHCHECK_GRACE_PERIOD = 5e3;
79089
+ var DEFAULT_HEALTHCHECK_INTERVAL = 1e4;
79090
+ var DEFAULT_HEALTHCHECK_TIMEOUT = 3e3;
79091
+ var DEFAULT_HEALTHCHECK_MAX_FAILURES = 3;
79092
+ var DEFAULT_LOG_LINES = 40;
79093
+ var PM_RECORD_EXTENSION = ".json";
79094
+ var SUPPORTED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"]);
79095
+ var DEFAULT_WATCH_IGNORE = ["**/.git/**", "**/node_modules/**", "**/.elit/**"];
79096
+ function normalizePmRuntime(value, optionName = "--runtime") {
79097
+ if (value === void 0 || value === null || value === "") {
79098
+ return void 0;
79099
+ }
79100
+ if (typeof value !== "string") {
79101
+ throw new Error(`${optionName} must be one of: node, bun, deno`);
79102
+ }
79103
+ const runtime2 = value.trim().toLowerCase();
79104
+ if (runtime2 === "node" || runtime2 === "bun" || runtime2 === "deno") {
79105
+ return runtime2;
79106
+ }
79107
+ throw new Error(`${optionName} must be one of: node, bun, deno`);
79108
+ }
79109
+ function normalizePmRestartPolicy(value, optionName = "--restart-policy") {
79110
+ if (value === void 0 || value === null || value === "") {
79111
+ return void 0;
79112
+ }
79113
+ if (typeof value !== "string") {
79114
+ throw new Error(`${optionName} must be one of: always, on-failure, never`);
79115
+ }
79116
+ const policy = value.trim().toLowerCase();
79117
+ if (policy === "always" || policy === "on-failure" || policy === "never") {
79118
+ return policy;
79119
+ }
79120
+ throw new Error(`${optionName} must be one of: always, on-failure, never`);
79121
+ }
79122
+ function normalizeIntegerOption(value, optionName, min2 = 0) {
79123
+ const parsed = Number.parseInt(value, 10);
79124
+ if (!Number.isFinite(parsed) || parsed < min2) {
79125
+ throw new Error(`${optionName} must be a number >= ${min2}`);
79126
+ }
79127
+ return parsed;
79128
+ }
79129
+ function normalizeNonEmptyString2(value) {
79130
+ if (typeof value !== "string") {
79131
+ return void 0;
79132
+ }
79133
+ const normalized = value.trim();
79134
+ return normalized.length > 0 ? normalized : void 0;
79135
+ }
79136
+ function hasPmGoogleDriveConfig(config) {
79137
+ return Boolean(
79138
+ normalizeNonEmptyString2(config?.fileId) || normalizeNonEmptyString2(config?.accessToken) || normalizeNonEmptyString2(config?.accessTokenEnv) || typeof config?.supportsAllDrives === "boolean"
79139
+ );
79140
+ }
79141
+ function hasPmWapkRunConfig(config) {
79142
+ return Boolean(
79143
+ normalizeNonEmptyString2(config?.file) || hasPmGoogleDriveConfig(config?.googleDrive) || normalizeNonEmptyString2(config?.runtime) || typeof config?.syncInterval === "number" || typeof config?.useWatcher === "boolean" || typeof config?.watchArchive === "boolean" || typeof config?.archiveSyncInterval === "number" || normalizeNonEmptyString2(config?.password)
79144
+ );
79145
+ }
79146
+ function mergePmWapkRunConfig(base, override) {
79147
+ if (!base && !override) {
79148
+ return void 0;
79149
+ }
79150
+ const googleDrive = hasPmGoogleDriveConfig(base?.googleDrive) || hasPmGoogleDriveConfig(override?.googleDrive) ? {
79151
+ fileId: override?.googleDrive?.fileId ?? base?.googleDrive?.fileId,
79152
+ accessToken: override?.googleDrive?.accessToken ?? base?.googleDrive?.accessToken,
79153
+ accessTokenEnv: override?.googleDrive?.accessTokenEnv ?? base?.googleDrive?.accessTokenEnv,
79154
+ supportsAllDrives: override?.googleDrive?.supportsAllDrives ?? base?.googleDrive?.supportsAllDrives
79155
+ } : void 0;
79156
+ const merged = {
79157
+ file: override?.file ?? base?.file,
79158
+ googleDrive,
79159
+ runtime: override?.runtime ?? base?.runtime,
79160
+ syncInterval: override?.syncInterval ?? base?.syncInterval,
79161
+ useWatcher: override?.useWatcher ?? base?.useWatcher,
79162
+ watchArchive: override?.watchArchive ?? base?.watchArchive,
79163
+ archiveSyncInterval: override?.archiveSyncInterval ?? base?.archiveSyncInterval,
79164
+ password: override?.password ?? base?.password
79165
+ };
79166
+ return hasPmWapkRunConfig(merged) ? merged : void 0;
79167
+ }
79168
+ function stripPmWapkSourceFromRunConfig(config) {
79169
+ if (!config) {
79170
+ return void 0;
79171
+ }
79172
+ const googleDrive = hasPmGoogleDriveConfig({
79173
+ ...config.googleDrive,
79174
+ fileId: void 0
79175
+ }) ? {
79176
+ ...config.googleDrive,
79177
+ fileId: void 0
79178
+ } : void 0;
79179
+ const stripped = {
79180
+ file: void 0,
79181
+ googleDrive,
79182
+ runtime: void 0,
79183
+ syncInterval: config.syncInterval,
79184
+ useWatcher: config.useWatcher,
79185
+ watchArchive: config.watchArchive,
79186
+ archiveSyncInterval: config.archiveSyncInterval,
79187
+ password: void 0
79188
+ };
79189
+ return hasPmWapkRunConfig(stripped) ? stripped : void 0;
79190
+ }
79191
+ function isRemoteWapkArchiveSpecifier(value) {
79192
+ return /^(?:gdrive|google-drive):\/\/.+/i.test(value.trim());
79193
+ }
79194
+ function isWapkArchiveSpecifier(value) {
79195
+ const normalized = value.trim();
79196
+ return normalized.toLowerCase().endsWith(".wapk") || isRemoteWapkArchiveSpecifier(normalized);
79197
+ }
79198
+ function buildGoogleDriveWapkSpecifier(fileId) {
79199
+ return `gdrive://${fileId}`;
79200
+ }
79201
+ function resolvePmWapkSource(value, cwd) {
79202
+ const normalized = normalizeNonEmptyString2(value);
79203
+ if (!normalized) {
79204
+ return void 0;
79205
+ }
79206
+ return isRemoteWapkArchiveSpecifier(normalized) ? normalized : (0, import_node_path5.resolve)(cwd, normalized);
79207
+ }
79208
+ function resolvePmWapkSourceToken(wapk, wapkRun) {
79209
+ const googleDriveFileId = normalizeNonEmptyString2(wapkRun?.googleDrive?.fileId);
79210
+ return normalizeNonEmptyString2(wapk) ?? normalizeNonEmptyString2(wapkRun?.file) ?? (googleDriveFileId ? buildGoogleDriveWapkSpecifier(googleDriveFileId) : void 0);
79211
+ }
79212
+ function countDefinedPmWapkSources(wapk, wapkRun) {
79213
+ const values = [
79214
+ normalizeNonEmptyString2(wapk),
79215
+ normalizeNonEmptyString2(wapkRun?.file),
79216
+ normalizeNonEmptyString2(wapkRun?.googleDrive?.fileId)
79217
+ ].filter((entry) => Boolean(entry));
79218
+ return new Set(values).size;
79219
+ }
79220
+ function appendPmWapkRunArgs(args, previewParts, wapkRun) {
79221
+ if (!wapkRun) {
79222
+ return;
79223
+ }
79224
+ if (typeof wapkRun.syncInterval === "number" && Number.isFinite(wapkRun.syncInterval) && wapkRun.syncInterval >= 50) {
79225
+ const value = String(Math.trunc(wapkRun.syncInterval));
79226
+ args.push("--sync-interval", value);
79227
+ previewParts.push("--sync-interval", value);
79228
+ }
79229
+ if (wapkRun.useWatcher) {
79230
+ args.push("--watcher");
79231
+ previewParts.push("--watcher");
79232
+ }
79233
+ if (typeof wapkRun.watchArchive === "boolean") {
79234
+ const flag = wapkRun.watchArchive ? "--archive-watch" : "--no-archive-watch";
79235
+ args.push(flag);
79236
+ previewParts.push(flag);
79237
+ }
79238
+ if (typeof wapkRun.archiveSyncInterval === "number" && Number.isFinite(wapkRun.archiveSyncInterval) && wapkRun.archiveSyncInterval >= 50) {
79239
+ const value = String(Math.trunc(wapkRun.archiveSyncInterval));
79240
+ args.push("--archive-sync-interval", value);
79241
+ previewParts.push("--archive-sync-interval", value);
79242
+ }
79243
+ const tokenEnv = normalizeNonEmptyString2(wapkRun.googleDrive?.accessTokenEnv);
79244
+ if (tokenEnv) {
79245
+ args.push("--google-drive-token-env", tokenEnv);
79246
+ previewParts.push("--google-drive-token-env", tokenEnv);
79247
+ }
79248
+ const accessToken = normalizeNonEmptyString2(wapkRun.googleDrive?.accessToken);
79249
+ if (accessToken) {
79250
+ args.push("--google-drive-access-token", accessToken);
79251
+ previewParts.push("--google-drive-access-token", "******");
79252
+ }
79253
+ if (wapkRun.googleDrive?.supportsAllDrives) {
79254
+ args.push("--google-drive-shared-drive");
79255
+ previewParts.push("--google-drive-shared-drive");
79256
+ }
79257
+ }
79258
+ function buildPmWapkPreview(wapk, runtime2, password, wapkRun) {
79259
+ const previewParts = ["elit", "wapk", "run", quoteCommandSegment(wapk)];
79260
+ if (runtime2) {
79261
+ previewParts.push("--runtime", runtime2);
79262
+ }
79263
+ if (password) {
79264
+ previewParts.push("--password", "******");
79265
+ }
79266
+ appendPmWapkRunArgs([], previewParts, wapkRun);
79267
+ return previewParts.join(" ");
79268
+ }
79269
+ function sanitizePmProcessName(name) {
79270
+ const sanitized = name.trim().toLowerCase().replace(/[<>:"/\\|?*\x00-\x1f]+/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-");
79271
+ return sanitized.length > 0 ? sanitized : "process";
79272
+ }
79273
+ function isTypescriptFile(filePath) {
79274
+ const extension = (0, import_node_path5.extname)(filePath).toLowerCase();
79275
+ return extension === ".ts" || extension === ".mts" || extension === ".cts";
79276
+ }
79277
+ function normalizeStringArray(value) {
79278
+ if (!Array.isArray(value)) {
79279
+ return [];
79280
+ }
79281
+ return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
79282
+ }
79283
+ function toWatchGlob(candidatePath) {
79284
+ if (!(0, import_node_fs5.existsSync)(candidatePath)) {
79285
+ return candidatePath;
79286
+ }
79287
+ try {
79288
+ return (0, import_node_fs5.statSync)(candidatePath).isDirectory() ? (0, import_node_path5.join)(candidatePath, "**", "*").replace(/\\/g, "/") : candidatePath;
79289
+ } catch {
79290
+ return candidatePath;
79291
+ }
79292
+ }
79293
+ function normalizeWatchPatterns(paths, cwd) {
79294
+ return paths.map((entry) => (0, import_node_path5.resolve)(cwd, entry)).map(toWatchGlob).map((entry) => entry.replace(/\\/g, "/"));
79295
+ }
79296
+ function normalizeWatchIgnorePatterns(paths, cwd) {
79297
+ return paths.map((entry) => entry.trim()).filter((entry) => entry.length > 0).map((entry) => {
79298
+ if (entry.includes("*") || entry.includes("?")) {
79299
+ return entry.replace(/\\/g, "/");
79300
+ }
79301
+ const resolvedPath = (0, import_node_path5.resolve)(cwd, entry);
79302
+ return toWatchGlob(resolvedPath).replace(/\\/g, "/");
79303
+ });
79304
+ }
79305
+ function matchesGlobPattern(filePath, pattern) {
79306
+ const normalizedPath = filePath.replace(/\\/g, "/");
79307
+ const normalizedPattern = pattern.replace(/\\/g, "/");
79308
+ const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
79309
+ return new RegExp(`^${regexPattern}$`).test(normalizedPath);
79310
+ }
79311
+ function isIgnoredWatchPath(filePath, patterns) {
79312
+ return patterns.some((pattern) => matchesGlobPattern(filePath, pattern));
79313
+ }
79314
+ function normalizeHealthCheckConfig(value) {
79315
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
79316
+ return void 0;
79317
+ }
79318
+ const config = value;
79319
+ if (typeof config.url !== "string" || config.url.trim().length === 0) {
79320
+ return void 0;
79321
+ }
79322
+ return {
79323
+ url: config.url.trim(),
79324
+ gracePeriod: typeof config.gracePeriod === "number" && Number.isFinite(config.gracePeriod) ? Math.max(0, Math.trunc(config.gracePeriod)) : DEFAULT_HEALTHCHECK_GRACE_PERIOD,
79325
+ interval: typeof config.interval === "number" && Number.isFinite(config.interval) ? Math.max(250, Math.trunc(config.interval)) : DEFAULT_HEALTHCHECK_INTERVAL,
79326
+ timeout: typeof config.timeout === "number" && Number.isFinite(config.timeout) ? Math.max(250, Math.trunc(config.timeout)) : DEFAULT_HEALTHCHECK_TIMEOUT,
79327
+ maxFailures: typeof config.maxFailures === "number" && Number.isFinite(config.maxFailures) ? Math.max(1, Math.trunc(config.maxFailures)) : DEFAULT_HEALTHCHECK_MAX_FAILURES
79328
+ };
79329
+ }
79330
+ function looksLikeManagedFile(value, cwd) {
79331
+ const normalized = value.trim();
79332
+ if (!normalized) {
79333
+ return false;
79334
+ }
79335
+ if (isRemoteWapkArchiveSpecifier(normalized)) {
79336
+ return false;
79337
+ }
79338
+ if (normalized.toLowerCase().endsWith(".wapk")) {
79339
+ return true;
79340
+ }
79341
+ const extension = (0, import_node_path5.extname)(normalized).toLowerCase();
79342
+ if (SUPPORTED_FILE_EXTENSIONS.has(extension)) {
79343
+ return true;
79344
+ }
79345
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.startsWith(".")) {
79346
+ return (0, import_node_fs5.existsSync)((0, import_node_path5.resolve)(cwd, normalized));
79347
+ }
79348
+ return false;
79349
+ }
79350
+ function normalizeEnvMap(value) {
79351
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
79352
+ return {};
79353
+ }
79354
+ const normalized = {};
79355
+ for (const [key, entryValue] of Object.entries(value)) {
79356
+ if (typeof entryValue === "string") {
79357
+ normalized[key] = entryValue;
79358
+ continue;
79359
+ }
79360
+ if (typeof entryValue === "number" || typeof entryValue === "boolean") {
79361
+ normalized[key] = String(entryValue);
79362
+ }
79363
+ }
79364
+ return normalized;
79365
+ }
79366
+ function parsePmEnvEntry(input) {
79367
+ const separatorIndex = input.indexOf("=");
79368
+ if (separatorIndex <= 0) {
79369
+ throw new Error("--env expects KEY=VALUE");
79370
+ }
79371
+ const key = input.slice(0, separatorIndex).trim();
79372
+ const value = input.slice(separatorIndex + 1);
79373
+ if (!key) {
79374
+ throw new Error("--env expects KEY=VALUE");
79375
+ }
79376
+ return [key, value];
79377
+ }
79378
+ function readRequiredValue(args, index, optionName) {
79379
+ const value = args[index];
79380
+ if (value === void 0) {
79381
+ throw new Error(`${optionName} requires a value.`);
79382
+ }
79383
+ return value;
79384
+ }
79385
+ function parsePmTarget(parsed, workspaceRoot) {
79386
+ if (parsed.script) {
79387
+ return { script: parsed.script };
79388
+ }
79389
+ if (parsed.file) {
79390
+ return { file: parsed.file };
79391
+ }
79392
+ if (parsed.wapk) {
79393
+ return { wapk: parsed.wapk };
79394
+ }
79395
+ if (!parsed.targetToken) {
79396
+ return {};
79397
+ }
79398
+ if (isWapkArchiveSpecifier(parsed.targetToken)) {
79399
+ return { wapk: parsed.targetToken };
79400
+ }
79401
+ if (looksLikeManagedFile(parsed.targetToken, (0, import_node_path5.resolve)(workspaceRoot, parsed.cwd ?? "."))) {
79402
+ return { file: parsed.targetToken };
79403
+ }
79404
+ return { configName: parsed.targetToken };
79405
+ }
79406
+ function getConfiguredPmApps(config) {
79407
+ return Array.isArray(config?.pm?.apps) ? config.pm.apps : [];
79408
+ }
79409
+ function defaultProcessName(base, explicitName) {
79410
+ if (explicitName && explicitName.trim()) {
79411
+ return explicitName.trim();
79412
+ }
79413
+ if (base.file) {
79414
+ const fileName = (0, import_node_path5.basename)(base.file, (0, import_node_path5.extname)(base.file));
79415
+ return fileName || "process";
79416
+ }
79417
+ if (base.wapk) {
79418
+ const fileName = (0, import_node_path5.basename)(base.wapk, (0, import_node_path5.extname)(base.wapk));
79419
+ return fileName || "wapk-app";
79420
+ }
79421
+ if (base.script) {
79422
+ const candidate = base.script.trim().split(/\s+/).slice(0, 2).join("-");
79423
+ return candidate || "process";
79424
+ }
79425
+ return "process";
79426
+ }
79427
+ function countDefinedTargets(app) {
79428
+ return [app.script, app.file, app.wapk].filter(Boolean).length;
79429
+ }
79430
+ function resolvePmPaths(config, workspaceRoot) {
79431
+ const dataDir = (0, import_node_path5.resolve)(workspaceRoot, config?.dataDir ?? DEFAULT_PM_DATA_DIR);
79432
+ const dumpFile = config?.dumpFile ? (0, import_node_path5.resolve)(workspaceRoot, config.dumpFile) : (0, import_node_path5.join)(dataDir, DEFAULT_PM_DUMP_FILE);
79433
+ return {
79434
+ dataDir,
79435
+ appsDir: (0, import_node_path5.join)(dataDir, "apps"),
79436
+ logsDir: (0, import_node_path5.join)(dataDir, "logs"),
79437
+ dumpFile
79438
+ };
79439
+ }
79440
+ function ensurePmDirectories(paths) {
79441
+ (0, import_node_fs5.mkdirSync)(paths.dataDir, { recursive: true });
79442
+ (0, import_node_fs5.mkdirSync)(paths.appsDir, { recursive: true });
79443
+ (0, import_node_fs5.mkdirSync)(paths.logsDir, { recursive: true });
79444
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(paths.dumpFile), { recursive: true });
79445
+ }
79446
+ function getPmRecordPath(paths, id) {
79447
+ return (0, import_node_path5.join)(paths.appsDir, `${id}${PM_RECORD_EXTENSION}`);
79448
+ }
79449
+ function readPmRecord(filePath) {
79450
+ return JSON.parse((0, import_node_fs5.readFileSync)(filePath, "utf8"));
79451
+ }
79452
+ function writePmRecord(filePath, record) {
79453
+ (0, import_node_fs5.writeFileSync)(filePath, JSON.stringify(record, null, 2));
79454
+ }
79455
+ function toSavedAppDefinition(record) {
79456
+ return {
79457
+ name: record.name,
79458
+ type: record.type,
79459
+ cwd: record.cwd,
79460
+ runtime: record.runtime,
79461
+ env: record.env,
79462
+ script: record.script,
79463
+ file: record.file,
79464
+ wapk: record.wapk,
79465
+ password: record.password,
79466
+ wapkRun: record.wapkRun,
79467
+ restartPolicy: record.restartPolicy,
79468
+ autorestart: record.autorestart,
79469
+ restartDelay: record.restartDelay,
79470
+ maxRestarts: record.maxRestarts,
79471
+ minUptime: record.minUptime,
79472
+ watch: record.watch,
79473
+ watchPaths: record.watchPaths,
79474
+ watchIgnore: record.watchIgnore,
79475
+ watchDebounce: record.watchDebounce,
79476
+ healthCheck: record.healthCheck
79477
+ };
79478
+ }
79479
+ function writePmDumpFile(filePath, apps) {
79480
+ const dump = {
79481
+ version: 1,
79482
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
79483
+ apps
79484
+ };
79485
+ (0, import_node_fs5.writeFileSync)(filePath, JSON.stringify(dump, null, 2));
79486
+ }
79487
+ function readPmDumpFile(filePath) {
79488
+ const parsed = JSON.parse((0, import_node_fs5.readFileSync)(filePath, "utf8"));
79489
+ if (parsed.version !== 1 || !Array.isArray(parsed.apps)) {
79490
+ throw new Error(`Invalid PM dump file: ${filePath}`);
79491
+ }
79492
+ return {
79493
+ version: 1,
79494
+ savedAt: typeof parsed.savedAt === "string" ? parsed.savedAt : (/* @__PURE__ */ new Date(0)).toISOString(),
79495
+ apps: parsed.apps
79496
+ };
79497
+ }
79498
+ function deriveDefaultWatchPaths(type, cwd, file, wapk) {
79499
+ if (type === "file" && file) {
79500
+ return [file];
79501
+ }
79502
+ if (type === "wapk" && wapk) {
79503
+ return [isRemoteWapkArchiveSpecifier(wapk) ? cwd : wapk];
79504
+ }
79505
+ return [cwd];
79506
+ }
79507
+ function normalizeResolvedWatchPaths(paths, cwd, type, file, wapk) {
79508
+ const sourcePaths = paths.length > 0 ? paths : deriveDefaultWatchPaths(type, cwd, file, wapk);
79509
+ return normalizeWatchPatterns(sourcePaths, cwd);
79510
+ }
79511
+ function listPmRecordMatches(paths) {
79512
+ if (!(0, import_node_fs5.existsSync)(paths.appsDir)) {
79513
+ return [];
79514
+ }
79515
+ return (0, import_node_fs5.readdirSync)(paths.appsDir).filter((entry) => entry.endsWith(PM_RECORD_EXTENSION)).map((entry) => {
79516
+ const filePath = (0, import_node_path5.join)(paths.appsDir, entry);
79517
+ return {
79518
+ filePath,
79519
+ record: readPmRecord(filePath)
79520
+ };
79521
+ }).sort((left, right) => left.record.name.localeCompare(right.record.name));
79522
+ }
79523
+ function findPmRecordMatch(paths, nameOrId) {
79524
+ const directPath = getPmRecordPath(paths, sanitizePmProcessName(nameOrId));
79525
+ if ((0, import_node_fs5.existsSync)(directPath)) {
79526
+ return {
79527
+ filePath: directPath,
79528
+ record: readPmRecord(directPath)
79529
+ };
79530
+ }
79531
+ return listPmRecordMatches(paths).find((match) => match.record.name === nameOrId);
79532
+ }
79533
+ function isProcessAlive(pid) {
79534
+ if (!pid || pid <= 0) {
79535
+ return false;
79536
+ }
79537
+ try {
79538
+ process.kill(pid, 0);
79539
+ return true;
79540
+ } catch (error) {
79541
+ const code = error.code;
79542
+ return code === "EPERM";
79543
+ }
79544
+ }
79545
+ function syncPmRecordLiveness(match) {
79546
+ const { record } = match;
79547
+ if (record.desiredState === "running" && record.runnerPid && !isProcessAlive(record.runnerPid)) {
79548
+ const updated = {
79549
+ ...record,
79550
+ status: record.status === "stopping" ? "stopped" : record.status === "errored" ? "errored" : "exited",
79551
+ runnerPid: void 0,
79552
+ childPid: void 0,
79553
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
79554
+ };
79555
+ writePmRecord(match.filePath, updated);
79556
+ return { ...match, record: updated };
79557
+ }
79558
+ if (record.childPid && !isProcessAlive(record.childPid)) {
79559
+ const updated = {
79560
+ ...record,
79561
+ childPid: void 0,
79562
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
79563
+ };
79564
+ writePmRecord(match.filePath, updated);
79565
+ return { ...match, record: updated };
79566
+ }
79567
+ return match;
79568
+ }
79569
+ function readCurrentCliInvocation() {
79570
+ const cliEntry = process.argv[1];
79571
+ if (!cliEntry) {
79572
+ throw new Error("Unable to resolve the current Elit CLI entrypoint for pm runner startup.");
79573
+ }
79574
+ return {
79575
+ command: process.execPath,
79576
+ args: [...process.execArgv, cliEntry]
79577
+ };
79578
+ }
79579
+ function preferCurrentExecutable(runtime2) {
79580
+ const executableName = (0, import_node_path5.basename)(process.execPath).toLowerCase();
79581
+ if (runtime2 === "node" && process.release?.name === "node" && executableName.startsWith("node")) {
79582
+ return process.execPath;
79583
+ }
79584
+ if (runtime2 === "bun" && process.versions?.bun && executableName.startsWith("bun")) {
79585
+ return process.execPath;
79586
+ }
79587
+ return runtime2;
79588
+ }
79589
+ function commandExists2(command) {
79590
+ if (command.includes("\\") || command.includes("/")) {
79591
+ return (0, import_node_fs5.existsSync)(command);
79592
+ }
79593
+ const result2 = (0, import_node_child_process4.spawnSync)(command, ["--version"], {
79594
+ stdio: "ignore",
79595
+ windowsHide: true
79596
+ });
79597
+ return !result2.error;
79598
+ }
79599
+ function ensureCommandAvailable(command, displayName) {
79600
+ if (commandExists2(command)) {
79601
+ return;
79602
+ }
79603
+ throw new Error(`${displayName} was not found in PATH.`);
79604
+ }
79605
+ function resolveTsxExecutable(cwd) {
79606
+ const localPath = (0, import_node_path5.join)(cwd, "node_modules", ".bin", process.platform === "win32" ? "tsx.cmd" : "tsx");
79607
+ if ((0, import_node_fs5.existsSync)(localPath)) {
79608
+ return localPath;
79609
+ }
79610
+ const globalCommand = process.platform === "win32" ? "tsx.cmd" : "tsx";
79611
+ return commandExists2(globalCommand) ? globalCommand : void 0;
79612
+ }
79613
+ function inferRuntimeFromFile(filePath) {
79614
+ if (isTypescriptFile(filePath) && commandExists2("bun")) {
79615
+ return "bun";
79616
+ }
79617
+ return "node";
79618
+ }
79619
+ var SIMPLE_PREVIEW_SEGMENT = /^[A-Za-z0-9_./:=+-]+$/;
79620
+ function quoteCommandSegment(value) {
79621
+ return SIMPLE_PREVIEW_SEGMENT.test(value) ? value : JSON.stringify(value);
79622
+ }
79623
+ function buildPmCommand(record) {
79624
+ if (record.type === "script") {
79625
+ return {
79626
+ command: record.script,
79627
+ args: [],
79628
+ shell: true,
79629
+ runtime: record.runtime,
79630
+ preview: record.script
79631
+ };
79632
+ }
79633
+ if (record.type === "wapk") {
79634
+ const cliInvocation = readCurrentCliInvocation();
79635
+ const args = [
79636
+ ...cliInvocation.args,
79637
+ "wapk",
79638
+ "run",
79639
+ record.wapk
79640
+ ];
79641
+ const previewParts = ["elit", "wapk", "run", quoteCommandSegment(record.wapk)];
79642
+ if (record.runtime) {
79643
+ args.push("--runtime", record.runtime);
79644
+ previewParts.push("--runtime", record.runtime);
79645
+ }
79646
+ if (record.password) {
79647
+ args.push("--password", record.password);
79648
+ previewParts.push("--password", "******");
79649
+ }
79650
+ appendPmWapkRunArgs(args, previewParts, record.wapkRun);
79651
+ return {
79652
+ command: cliInvocation.command,
79653
+ args,
79654
+ preview: previewParts.join(" "),
79655
+ runtime: record.runtime
79656
+ };
79657
+ }
79658
+ const runtime2 = record.runtime ?? inferRuntimeFromFile(record.file);
79659
+ if (runtime2 === "bun") {
79660
+ const executable2 = preferCurrentExecutable("bun");
79661
+ ensureCommandAvailable(executable2, "Bun runtime");
79662
+ return {
79663
+ command: executable2,
79664
+ args: ["run", record.file],
79665
+ runtime: runtime2,
79666
+ preview: `${(0, import_node_path5.basename)(executable2)} run ${quoteCommandSegment(record.file)}`
79667
+ };
79668
+ }
79669
+ if (runtime2 === "deno") {
79670
+ const executable2 = preferCurrentExecutable("deno");
79671
+ ensureCommandAvailable(executable2, "Deno runtime");
79672
+ return {
79673
+ command: executable2,
79674
+ args: ["run", "--allow-all", record.file],
79675
+ runtime: runtime2,
79676
+ preview: `${(0, import_node_path5.basename)(executable2)} run --allow-all ${quoteCommandSegment(record.file)}`
79677
+ };
79678
+ }
79679
+ if (isTypescriptFile(record.file)) {
79680
+ const tsxExecutable = resolveTsxExecutable(record.cwd);
79681
+ if (!tsxExecutable) {
79682
+ throw new Error('TypeScript file execution with runtime "node" requires tsx to be installed, or use --runtime bun.');
79683
+ }
79684
+ return {
79685
+ command: tsxExecutable,
79686
+ args: [record.file],
79687
+ runtime: runtime2,
79688
+ preview: `${(0, import_node_path5.basename)(tsxExecutable)} ${quoteCommandSegment(record.file)}`
79689
+ };
79690
+ }
79691
+ const executable = preferCurrentExecutable("node");
79692
+ ensureCommandAvailable(executable, "Node.js runtime");
79693
+ return {
79694
+ command: executable,
79695
+ args: [record.file],
79696
+ runtime: runtime2,
79697
+ preview: `${(0, import_node_path5.basename)(executable)} ${quoteCommandSegment(record.file)}`
79698
+ };
79699
+ }
79700
+ function createRecordFromDefinition(definition, paths, existing) {
79701
+ const id = sanitizePmProcessName(definition.name);
79702
+ const now = (/* @__PURE__ */ new Date()).toISOString();
79703
+ const preview = definition.type === "script" ? definition.script : definition.type === "wapk" ? buildPmWapkPreview(definition.wapk, definition.runtime, definition.password, definition.wapkRun) : `${definition.runtime ?? "auto"} ${quoteCommandSegment(definition.file)}`;
79704
+ return {
79705
+ id,
79706
+ name: definition.name,
79707
+ type: definition.type,
79708
+ source: definition.source,
79709
+ cwd: definition.cwd,
79710
+ runtime: definition.runtime,
79711
+ env: definition.env,
79712
+ script: definition.script,
79713
+ file: definition.file,
79714
+ wapk: definition.wapk,
79715
+ wapkRun: definition.wapkRun,
79716
+ autorestart: definition.autorestart,
79717
+ restartDelay: definition.restartDelay,
79718
+ maxRestarts: definition.maxRestarts,
79719
+ password: definition.password,
79720
+ restartPolicy: definition.restartPolicy,
79721
+ minUptime: definition.minUptime,
79722
+ watch: definition.watch,
79723
+ watchPaths: definition.watchPaths,
79724
+ watchIgnore: definition.watchIgnore,
79725
+ watchDebounce: definition.watchDebounce,
79726
+ healthCheck: definition.healthCheck,
79727
+ desiredState: "running",
79728
+ status: "starting",
79729
+ commandPreview: preview,
79730
+ createdAt: existing?.createdAt ?? now,
79731
+ updatedAt: now,
79732
+ startedAt: void 0,
79733
+ stoppedAt: void 0,
79734
+ runnerPid: void 0,
79735
+ childPid: void 0,
79736
+ restartCount: existing?.restartCount ?? 0,
79737
+ lastExitCode: existing?.lastExitCode,
79738
+ error: void 0,
79739
+ logFiles: existing?.logFiles ?? {
79740
+ out: (0, import_node_path5.join)(paths.logsDir, `${id}.out.log`),
79741
+ err: (0, import_node_path5.join)(paths.logsDir, `${id}.err.log`)
79742
+ }
79743
+ };
79744
+ }
79745
+ function terminateProcessTree(pid) {
79746
+ if (process.platform === "win32") {
79747
+ const result2 = (0, import_node_child_process4.spawnSync)("taskkill", ["/PID", String(pid), "/T", "/F"], {
79748
+ stdio: "ignore",
79749
+ windowsHide: true
79750
+ });
79751
+ if (result2.error && result2.error.code !== "ENOENT") {
79752
+ throw result2.error;
79753
+ }
79754
+ return;
79755
+ }
79756
+ try {
79757
+ process.kill(pid, "SIGTERM");
79758
+ } catch (error) {
79759
+ const code = error.code;
79760
+ if (code !== "ESRCH") {
79761
+ throw error;
79762
+ }
79763
+ }
79764
+ }
79765
+ async function startManagedProcess(definition, paths) {
79766
+ ensurePmDirectories(paths);
79767
+ const id = sanitizePmProcessName(definition.name);
79768
+ const recordPath = getPmRecordPath(paths, id);
79769
+ const existingMatch = (0, import_node_fs5.existsSync)(recordPath) ? syncPmRecordLiveness({ filePath: recordPath, record: readPmRecord(recordPath) }) : void 0;
79770
+ if (existingMatch?.record.runnerPid && isProcessAlive(existingMatch.record.runnerPid)) {
79771
+ throw new Error(`Process "${definition.name}" is already running.`);
79772
+ }
79773
+ const record = createRecordFromDefinition(definition, paths, existingMatch?.record);
79774
+ writePmRecord(recordPath, record);
79775
+ const cliInvocation = readCurrentCliInvocation();
79776
+ const runner = (0, import_node_child_process4.spawn)(cliInvocation.command, [
79777
+ ...cliInvocation.args,
79778
+ "pm",
79779
+ "__run",
79780
+ "--data-dir",
79781
+ paths.dataDir,
79782
+ "--id",
79783
+ record.id
79784
+ ], {
79785
+ cwd: definition.cwd,
79786
+ detached: true,
79787
+ stdio: "ignore",
79788
+ windowsHide: true,
79789
+ env: {
79790
+ ...process.env,
79791
+ ELIT_PM_INTERNAL: "1"
79792
+ }
79793
+ });
79794
+ if (!runner.pid) {
79795
+ throw new Error(`Failed to start process runner for "${definition.name}".`);
79796
+ }
79797
+ runner.unref();
79798
+ const startedRecord = {
79799
+ ...record,
79800
+ runnerPid: runner.pid,
79801
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
79802
+ };
79803
+ writePmRecord(recordPath, startedRecord);
79804
+ return startedRecord;
79805
+ }
79806
+ function readLatestPmRecord(filePath, fallback) {
79807
+ return (0, import_node_fs5.existsSync)(filePath) ? readPmRecord(filePath) : fallback;
79808
+ }
79809
+ function writePmLog(stream, message) {
79810
+ stream.write(`[elit pm] ${(/* @__PURE__ */ new Date()).toISOString()} ${message}${import_node_os2.EOL}`);
79811
+ }
79812
+ function waitForExit(code, signal) {
79813
+ if (typeof code === "number") {
79814
+ return code;
79815
+ }
79816
+ if (signal === "SIGINT" || signal === "SIGTERM") {
79817
+ return 0;
79818
+ }
79819
+ return 1;
79820
+ }
79821
+ async function delay(milliseconds) {
79822
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
79823
+ }
79824
+ async function waitForManagedChildExit(child) {
79825
+ return await new Promise((resolvePromise) => {
79826
+ let resolved = false;
79827
+ child.once("error", (error) => {
79828
+ if (resolved) {
79829
+ return;
79830
+ }
79831
+ resolved = true;
79832
+ resolvePromise({ code: 1, signal: null, error: error instanceof Error ? error.message : String(error) });
79833
+ });
79834
+ child.once("close", (code, signal) => {
79835
+ if (resolved) {
79836
+ return;
79837
+ }
79838
+ resolved = true;
79839
+ resolvePromise({ code, signal });
79840
+ });
79841
+ });
79842
+ }
79843
+ async function createPmWatchController(record, onChange, onError) {
79844
+ if (!record.watch || record.watchPaths.length === 0) {
79845
+ return {
79846
+ async close() {
79847
+ }
79848
+ };
79849
+ }
79850
+ const watcher = watch(record.watchPaths);
79851
+ let debounceTimer = null;
79852
+ const scheduleRestart = (filePath) => {
79853
+ const normalizedPath = filePath.replace(/\\/g, "/");
79854
+ if (isIgnoredWatchPath(normalizedPath, record.watchIgnore)) {
79855
+ return;
79856
+ }
79857
+ if (debounceTimer) {
79858
+ clearTimeout(debounceTimer);
79859
+ }
79860
+ debounceTimer = setTimeout(() => {
79861
+ debounceTimer = null;
79862
+ onChange(normalizedPath);
79863
+ }, record.watchDebounce);
79864
+ debounceTimer.unref?.();
79865
+ };
79866
+ watcher.on("add", scheduleRestart);
79867
+ watcher.on("change", scheduleRestart);
79868
+ watcher.on("unlink", scheduleRestart);
79869
+ watcher.on("error", (error) => onError(error instanceof Error ? error.message : String(error)));
79870
+ return {
79871
+ async close() {
79872
+ if (debounceTimer) {
79873
+ clearTimeout(debounceTimer);
79874
+ debounceTimer = null;
79875
+ }
79876
+ await watcher.close();
79877
+ }
79878
+ };
79879
+ }
79880
+ function createPmHealthMonitor(record, onFailure, onLog) {
79881
+ if (!record.healthCheck) {
79882
+ return {
79883
+ stop() {
79884
+ }
79885
+ };
79886
+ }
79887
+ const healthCheck = record.healthCheck;
79888
+ let stopped = false;
79889
+ let timer = null;
79890
+ let initialDelay = null;
79891
+ let inFlight = false;
79892
+ let failureCount = 0;
79893
+ const runHealthCheck = async () => {
79894
+ if (stopped || inFlight) {
79895
+ return;
79896
+ }
79897
+ inFlight = true;
79898
+ const controller = new AbortController();
79899
+ const timeoutId = setTimeout(() => controller.abort(), healthCheck.timeout);
79900
+ timeoutId.unref?.();
79901
+ try {
79902
+ const response = await fetch(healthCheck.url, {
79903
+ method: "GET",
79904
+ signal: controller.signal
79905
+ });
79906
+ if (!response.ok) {
79907
+ throw new Error(`health check returned ${response.status}`);
79908
+ }
79909
+ failureCount = 0;
79910
+ } catch (error) {
79911
+ failureCount += 1;
79912
+ const message = error instanceof Error ? error.message : String(error);
79913
+ onLog(`health check failed (${failureCount}/${healthCheck.maxFailures}): ${message}`);
79914
+ if (failureCount >= healthCheck.maxFailures) {
79915
+ stopped = true;
79916
+ onFailure(`health check failed ${failureCount} times: ${message}`);
79917
+ }
79918
+ } finally {
79919
+ clearTimeout(timeoutId);
79920
+ inFlight = false;
79921
+ }
79922
+ };
79923
+ initialDelay = setTimeout(() => {
79924
+ void runHealthCheck();
79925
+ timer = setInterval(() => {
79926
+ void runHealthCheck();
79927
+ }, healthCheck.interval);
79928
+ timer.unref?.();
79929
+ }, healthCheck.gracePeriod);
79930
+ initialDelay.unref?.();
79931
+ return {
79932
+ stop() {
79933
+ stopped = true;
79934
+ if (initialDelay) {
79935
+ clearTimeout(initialDelay);
79936
+ initialDelay = null;
79937
+ }
79938
+ if (timer) {
79939
+ clearInterval(timer);
79940
+ timer = null;
79941
+ }
79942
+ }
79943
+ };
79944
+ }
79945
+ function readPlannedRestartRequest(state) {
79946
+ return state.request;
79947
+ }
79948
+ async function runManagedProcessLoop(filePath, initialRecord) {
79949
+ let record = initialRecord;
79950
+ let activeChild = null;
79951
+ let stopRequested = false;
79952
+ const restartState = { request: null };
79953
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(initialRecord.logFiles.out), { recursive: true });
79954
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(initialRecord.logFiles.err), { recursive: true });
79955
+ const stdoutLog = (0, import_node_fs5.createWriteStream)(initialRecord.logFiles.out, { flags: "a" });
79956
+ const stderrLog = (0, import_node_fs5.createWriteStream)(initialRecord.logFiles.err, { flags: "a" });
79957
+ const persist = (mutator) => {
79958
+ const current = readLatestPmRecord(filePath, record);
79959
+ record = mutator(current);
79960
+ writePmRecord(filePath, record);
79961
+ return record;
79962
+ };
79963
+ const stopActiveChild = () => {
79964
+ if (activeChild?.pid && isProcessAlive(activeChild.pid)) {
79965
+ terminateProcessTree(activeChild.pid);
79966
+ }
79967
+ };
79968
+ const handleStopSignal = (signal) => {
79969
+ stopRequested = true;
79970
+ persist((current) => ({
79971
+ ...current,
79972
+ desiredState: "stopped",
79973
+ status: "stopping",
79974
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
79975
+ }));
79976
+ writePmLog(stdoutLog, `received ${signal}, stopping managed process`);
79977
+ stopActiveChild();
79978
+ };
79979
+ process.on("SIGINT", handleStopSignal);
79980
+ process.on("SIGTERM", handleStopSignal);
79981
+ persist((current) => ({
79982
+ ...current,
79983
+ runnerPid: process.pid,
79984
+ desiredState: "running",
79985
+ status: "starting",
79986
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
79987
+ }));
79988
+ try {
79989
+ while (!stopRequested) {
79990
+ restartState.request = null;
79991
+ const latest = readLatestPmRecord(filePath, record);
79992
+ if (latest.desiredState === "stopped") {
79993
+ break;
79994
+ }
79995
+ let command;
79996
+ try {
79997
+ command = buildPmCommand(latest);
79998
+ } catch (error) {
79999
+ const message = error instanceof Error ? error.message : String(error);
80000
+ writePmLog(stderrLog, message);
80001
+ persist((current2) => ({
80002
+ ...current2,
80003
+ status: "errored",
80004
+ error: message,
80005
+ runnerPid: void 0,
80006
+ childPid: void 0,
80007
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80008
+ }));
80009
+ return;
80010
+ }
80011
+ const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
80012
+ cwd: latest.cwd,
80013
+ env: {
80014
+ ...process.env,
80015
+ ...latest.env,
80016
+ ELIT_PM_NAME: latest.name,
80017
+ ELIT_PM_ID: latest.id
80018
+ },
80019
+ stdio: ["ignore", "pipe", "pipe"],
80020
+ windowsHide: true,
80021
+ shell: command.shell
80022
+ });
80023
+ const childStartedAt = Date.now();
80024
+ activeChild = child;
80025
+ if (child.stdout) {
80026
+ child.stdout.pipe(stdoutLog, { end: false });
80027
+ }
80028
+ if (child.stderr) {
80029
+ child.stderr.pipe(stderrLog, { end: false });
80030
+ }
80031
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
80032
+ persist((current2) => ({
80033
+ ...current2,
80034
+ status: "online",
80035
+ commandPreview: command.preview,
80036
+ runtime: command.runtime ?? current2.runtime,
80037
+ runnerPid: process.pid,
80038
+ childPid: child.pid,
80039
+ startedAt,
80040
+ stoppedAt: void 0,
80041
+ error: void 0,
80042
+ updatedAt: startedAt
80043
+ }));
80044
+ writePmLog(stdoutLog, `started ${command.preview}${child.pid ? ` (pid ${child.pid})` : ""}`);
80045
+ const requestPlannedRestart = (kind, detail) => {
80046
+ if (stopRequested || restartState.request) {
80047
+ return;
80048
+ }
80049
+ restartState.request = { kind, detail };
80050
+ writePmLog(kind === "health" ? stderrLog : stdoutLog, `${kind} restart requested: ${detail}`);
80051
+ persist((current2) => ({
80052
+ ...current2,
80053
+ status: "restarting",
80054
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80055
+ }));
80056
+ stopActiveChild();
80057
+ };
80058
+ const watchController = await createPmWatchController(
80059
+ latest,
80060
+ (changedPath) => requestPlannedRestart("watch", changedPath),
80061
+ (message) => writePmLog(stderrLog, `watch error: ${message}`)
80062
+ );
80063
+ const healthMonitor = createPmHealthMonitor(
80064
+ latest,
80065
+ (message) => requestPlannedRestart("health", message),
80066
+ (message) => writePmLog(stdoutLog, message)
80067
+ );
80068
+ const exitResult = await waitForManagedChildExit(child);
80069
+ await watchController.close();
80070
+ healthMonitor.stop();
80071
+ activeChild = null;
80072
+ const exitCode = waitForExit(exitResult.code, exitResult.signal);
80073
+ const current = readLatestPmRecord(filePath, record);
80074
+ const plannedRestart = readPlannedRestartRequest(restartState);
80075
+ const uptime = Math.max(0, Date.now() - childStartedAt);
80076
+ const wasStable = current.minUptime > 0 && uptime >= current.minUptime;
80077
+ if (exitResult.error) {
80078
+ writePmLog(stderrLog, exitResult.error);
80079
+ } else if (!plannedRestart) {
80080
+ writePmLog(stdoutLog, `process exited with code ${exitCode}`);
80081
+ }
80082
+ if (stopRequested || current.desiredState === "stopped") {
80083
+ break;
80084
+ }
80085
+ const shouldRestartForExit = plannedRestart ? true : current.restartPolicy === "always" ? true : current.restartPolicy === "on-failure" ? exitCode !== 0 || Boolean(exitResult.error) : false;
80086
+ if (!shouldRestartForExit) {
80087
+ persist((latestRecord) => ({
80088
+ ...latestRecord,
80089
+ status: exitCode === 0 && !exitResult.error ? "exited" : "errored",
80090
+ childPid: void 0,
80091
+ runnerPid: void 0,
80092
+ lastExitCode: exitCode,
80093
+ error: exitCode === 0 && !exitResult.error ? void 0 : exitResult.error ?? `Process exited with code ${exitCode}.`,
80094
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
80095
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80096
+ }));
80097
+ return;
80098
+ }
80099
+ const shouldCountRestart = plannedRestart?.kind !== "watch";
80100
+ const baseRestartCount = wasStable ? 0 : current.restartCount ?? 0;
80101
+ const nextRestartCount = shouldCountRestart ? baseRestartCount + 1 : current.restartCount ?? 0;
80102
+ if (nextRestartCount > current.maxRestarts) {
80103
+ persist((latestRecord) => ({
80104
+ ...latestRecord,
80105
+ status: "errored",
80106
+ childPid: void 0,
80107
+ runnerPid: void 0,
80108
+ restartCount: nextRestartCount,
80109
+ lastExitCode: exitCode,
80110
+ error: plannedRestart ? `Reached max restart attempts (${current.maxRestarts}) after ${plannedRestart.kind} restart requests.` : `Reached max restart attempts (${current.maxRestarts}).`,
80111
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
80112
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80113
+ }));
80114
+ writePmLog(stderrLog, `max restart attempts reached (${current.maxRestarts})`);
80115
+ return;
80116
+ }
80117
+ persist((latestRecord) => ({
80118
+ ...latestRecord,
80119
+ status: "restarting",
80120
+ childPid: void 0,
80121
+ lastExitCode: exitCode,
80122
+ restartCount: nextRestartCount,
80123
+ error: void 0,
80124
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80125
+ }));
80126
+ if (plannedRestart) {
80127
+ writePmLog(
80128
+ plannedRestart.kind === "health" ? stderrLog : stdoutLog,
80129
+ `restarting in ${current.restartDelay}ms after ${plannedRestart.kind}: ${plannedRestart.detail}`
80130
+ );
80131
+ } else {
80132
+ writePmLog(stdoutLog, `restarting in ${current.restartDelay}ms`);
80133
+ }
80134
+ await delay(current.restartDelay);
80135
+ }
80136
+ } finally {
80137
+ stopRequested = true;
80138
+ stopActiveChild();
80139
+ const finalRecord = readLatestPmRecord(filePath, record);
80140
+ writePmRecord(filePath, {
80141
+ ...finalRecord,
80142
+ desiredState: "stopped",
80143
+ status: finalRecord.status === "errored" ? "errored" : finalRecord.status === "exited" ? "exited" : "stopped",
80144
+ runnerPid: void 0,
80145
+ childPid: void 0,
80146
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
80147
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80148
+ });
80149
+ process.off("SIGINT", handleStopSignal);
80150
+ process.off("SIGTERM", handleStopSignal);
80151
+ await new Promise((resolvePromise) => stdoutLog.end(resolvePromise));
80152
+ await new Promise((resolvePromise) => stderrLog.end(resolvePromise));
80153
+ }
80154
+ }
80155
+ function resolveStartSelection(configApps, parsed, workspaceRoot) {
80156
+ const target = parsePmTarget(parsed, workspaceRoot);
80157
+ const hasExplicitWapkSource = Boolean(resolvePmWapkSourceToken(parsed.wapk, parsed.wapkRun));
80158
+ const selectedName = target.configName ?? (!target.script && !target.file && !target.wapk && !hasExplicitWapkSource ? parsed.name : void 0);
80159
+ const selected = selectedName ? configApps.find((app) => app.name === selectedName) : void 0;
80160
+ return {
80161
+ selected,
80162
+ startAll: !target.script && !target.file && !target.wapk && !hasExplicitWapkSource && !selectedName,
80163
+ target
80164
+ };
80165
+ }
80166
+ function toPmAppConfig(record) {
80167
+ return {
80168
+ name: record.name,
80169
+ script: record.script,
80170
+ file: record.file,
80171
+ wapk: record.wapk,
80172
+ wapkRun: record.wapkRun,
80173
+ runtime: record.runtime,
80174
+ cwd: record.cwd,
80175
+ env: record.env,
80176
+ autorestart: record.autorestart,
80177
+ restartDelay: record.restartDelay,
80178
+ maxRestarts: record.maxRestarts,
80179
+ password: record.password,
80180
+ restartPolicy: record.restartPolicy,
80181
+ minUptime: record.minUptime,
80182
+ watch: record.watch,
80183
+ watchPaths: record.watchPaths,
80184
+ watchIgnore: record.watchIgnore,
80185
+ watchDebounce: record.watchDebounce,
80186
+ healthCheck: record.healthCheck
80187
+ };
80188
+ }
80189
+ function toSavedPmAppConfig(app) {
80190
+ return {
80191
+ name: app.name,
80192
+ script: app.script,
80193
+ file: app.file,
80194
+ wapk: app.wapk,
80195
+ wapkRun: app.wapkRun,
80196
+ runtime: app.runtime,
80197
+ cwd: app.cwd,
80198
+ env: app.env,
80199
+ autorestart: app.autorestart,
80200
+ restartDelay: app.restartDelay,
80201
+ maxRestarts: app.maxRestarts,
80202
+ password: app.password,
80203
+ restartPolicy: app.restartPolicy,
80204
+ minUptime: app.minUptime,
80205
+ watch: app.watch,
80206
+ watchPaths: app.watchPaths,
80207
+ watchIgnore: app.watchIgnore,
80208
+ watchDebounce: app.watchDebounce,
80209
+ healthCheck: app.healthCheck
80210
+ };
80211
+ }
80212
+ function resolvePmAppDefinition(base, parsed, workspaceRoot, source) {
80213
+ const target = parsePmTarget(parsed, workspaceRoot);
80214
+ const resolvedCwd = (0, import_node_path5.resolve)(workspaceRoot, parsed.cwd ?? base?.cwd ?? ".");
80215
+ if (countDefinedPmWapkSources(parsed.wapk, parsed.wapkRun) > 1) {
80216
+ throw new Error("Use only one WAPK archive source per pm start: --wapk or --google-drive-file-id.");
80217
+ }
80218
+ if (countDefinedPmWapkSources(base?.wapk, base?.wapkRun) > 1) {
80219
+ throw new Error(`Configured pm app "${base?.name ?? parsed.name ?? "app"}" must define only one WAPK archive source.`);
80220
+ }
80221
+ const explicitWapk = resolvePmWapkSource(resolvePmWapkSourceToken(target.wapk, parsed.wapkRun), resolvedCwd);
80222
+ const baseWapk = resolvePmWapkSource(resolvePmWapkSourceToken(base?.wapk, base?.wapkRun), resolvedCwd);
80223
+ const hasExplicitTarget = Boolean(target.script || target.file || explicitWapk);
80224
+ const script = target.script ?? (hasExplicitTarget ? void 0 : base?.script);
80225
+ const file = target.file ? (0, import_node_path5.resolve)(resolvedCwd, target.file) : hasExplicitTarget ? void 0 : base?.file ? (0, import_node_path5.resolve)(resolvedCwd, base.file) : void 0;
80226
+ const wapk = explicitWapk ?? (hasExplicitTarget ? void 0 : baseWapk);
80227
+ const targetCount = countDefinedTargets({ script, file, wapk });
80228
+ if (targetCount === 0) {
80229
+ throw new Error("pm start requires one target: --script, --file, --wapk, or a configured app name.");
80230
+ }
80231
+ if (targetCount > 1) {
80232
+ throw new Error("A pm app must define exactly one of script, file, or wapk.");
80233
+ }
80234
+ const name = defaultProcessName({ script, file, wapk }, parsed.name ?? base?.name);
80235
+ const mergedWapkRun = mergePmWapkRunConfig(base?.wapkRun, parsed.wapkRun);
80236
+ const runtime2 = normalizePmRuntime(parsed.runtime ?? mergedWapkRun?.runtime ?? base?.runtime, "--runtime");
80237
+ let restartPolicy = normalizePmRestartPolicy(parsed.restartPolicy ?? base?.restartPolicy, "--restart-policy") ?? (base?.autorestart ?? true ? "always" : "never");
80238
+ if (parsed.autorestart === false) {
80239
+ restartPolicy = "never";
80240
+ }
80241
+ const autorestart = restartPolicy !== "never";
80242
+ const watch4 = parsed.watch ?? base?.watch ?? false;
80243
+ const configuredWatchPaths = parsed.watchPaths.length > 0 ? parsed.watchPaths : normalizeStringArray(base?.watchPaths);
80244
+ const configuredWatchIgnore = [
80245
+ ...DEFAULT_WATCH_IGNORE,
80246
+ ...normalizeStringArray(base?.watchIgnore),
80247
+ ...parsed.watchIgnore
80248
+ ];
80249
+ const healthCheck = normalizeHealthCheckConfig(parsed.healthCheckUrl ? {
80250
+ url: parsed.healthCheckUrl,
80251
+ gracePeriod: parsed.healthCheckGracePeriod,
80252
+ interval: parsed.healthCheckInterval,
80253
+ timeout: parsed.healthCheckTimeout,
80254
+ maxFailures: parsed.healthCheckMaxFailures
80255
+ } : base?.healthCheck);
80256
+ const password = parsed.password ?? mergedWapkRun?.password ?? base?.password;
80257
+ const wapkRun = stripPmWapkSourceFromRunConfig(mergedWapkRun);
80258
+ if (password && !wapk) {
80259
+ throw new Error("--password is only supported when starting a WAPK app.");
80260
+ }
80261
+ if (wapkRun && !wapk) {
80262
+ throw new Error("WAPK run options are only supported when starting a WAPK app.");
80263
+ }
80264
+ return {
80265
+ name,
80266
+ type: script ? "script" : wapk ? "wapk" : "file",
80267
+ source,
80268
+ cwd: resolvedCwd,
80269
+ runtime: runtime2,
80270
+ env: {
80271
+ ...normalizeEnvMap(base?.env),
80272
+ ...parsed.env
80273
+ },
80274
+ script,
80275
+ file,
80276
+ wapk,
80277
+ wapkRun,
80278
+ autorestart,
80279
+ restartDelay: parsed.restartDelay ?? base?.restartDelay ?? DEFAULT_RESTART_DELAY,
80280
+ maxRestarts: parsed.maxRestarts ?? base?.maxRestarts ?? DEFAULT_MAX_RESTARTS,
80281
+ password,
80282
+ restartPolicy,
80283
+ minUptime: parsed.minUptime ?? base?.minUptime ?? DEFAULT_MIN_UPTIME,
80284
+ watch: watch4,
80285
+ watchPaths: watch4 ? normalizeResolvedWatchPaths(configuredWatchPaths, resolvedCwd, script ? "script" : wapk ? "wapk" : "file", file, wapk) : [],
80286
+ watchIgnore: watch4 ? normalizeWatchIgnorePatterns(configuredWatchIgnore, resolvedCwd) : [],
80287
+ watchDebounce: parsed.watchDebounce ?? base?.watchDebounce ?? DEFAULT_WATCH_DEBOUNCE,
80288
+ healthCheck
80289
+ };
80290
+ }
80291
+ function resolvePmStartDefinitions(parsed, config, workspaceRoot) {
80292
+ const configApps = getConfiguredPmApps(config);
80293
+ const selection = resolveStartSelection(configApps, parsed, workspaceRoot);
80294
+ if (selection.startAll) {
80295
+ if (configApps.length === 0) {
80296
+ throw new Error("No pm apps configured in elit.config.* and no start target was provided.");
80297
+ }
80298
+ return configApps.map((app) => resolvePmAppDefinition(app, { ...parsed, name: app.name }, workspaceRoot, "config"));
80299
+ }
80300
+ if (selection.selected) {
80301
+ return [resolvePmAppDefinition(selection.selected, parsed, workspaceRoot, "config")];
80302
+ }
80303
+ return [resolvePmAppDefinition(void 0, parsed, workspaceRoot, "cli")];
80304
+ }
80305
+ function parsePmStartArgs(args) {
80306
+ const parsed = {
80307
+ env: {},
80308
+ watchPaths: [],
80309
+ watchIgnore: []
80310
+ };
80311
+ for (let index = 0; index < args.length; index++) {
80312
+ const arg = args[index];
80313
+ switch (arg) {
80314
+ case "--script":
80315
+ parsed.script = readRequiredValue(args, ++index, "--script");
80316
+ break;
80317
+ case "--file":
80318
+ case "-f":
80319
+ parsed.file = readRequiredValue(args, ++index, arg);
80320
+ break;
80321
+ case "--wapk":
80322
+ parsed.wapk = readRequiredValue(args, ++index, "--wapk");
80323
+ break;
80324
+ case "--google-drive-file-id":
80325
+ parsed.wapkRun = {
80326
+ ...parsed.wapkRun,
80327
+ googleDrive: {
80328
+ ...parsed.wapkRun?.googleDrive,
80329
+ fileId: readRequiredValue(args, ++index, "--google-drive-file-id")
80330
+ }
80331
+ };
80332
+ break;
80333
+ case "--google-drive-token-env":
80334
+ parsed.wapkRun = {
80335
+ ...parsed.wapkRun,
80336
+ googleDrive: {
80337
+ ...parsed.wapkRun?.googleDrive,
80338
+ accessTokenEnv: readRequiredValue(args, ++index, "--google-drive-token-env")
80339
+ }
80340
+ };
80341
+ break;
80342
+ case "--google-drive-access-token":
80343
+ parsed.wapkRun = {
80344
+ ...parsed.wapkRun,
80345
+ googleDrive: {
80346
+ ...parsed.wapkRun?.googleDrive,
80347
+ accessToken: readRequiredValue(args, ++index, "--google-drive-access-token")
80348
+ }
80349
+ };
80350
+ break;
80351
+ case "--google-drive-shared-drive":
80352
+ parsed.wapkRun = {
80353
+ ...parsed.wapkRun,
80354
+ googleDrive: {
80355
+ ...parsed.wapkRun?.googleDrive,
80356
+ supportsAllDrives: true
80357
+ }
80358
+ };
80359
+ break;
80360
+ case "--runtime":
80361
+ case "-r":
80362
+ parsed.runtime = normalizePmRuntime(readRequiredValue(args, ++index, arg), arg);
80363
+ break;
80364
+ case "--name":
80365
+ case "-n":
80366
+ parsed.name = readRequiredValue(args, ++index, arg);
80367
+ break;
80368
+ case "--cwd":
80369
+ parsed.cwd = readRequiredValue(args, ++index, "--cwd");
80370
+ break;
80371
+ case "--env": {
80372
+ const [key, value] = parsePmEnvEntry(readRequiredValue(args, ++index, "--env"));
80373
+ parsed.env[key] = value;
80374
+ break;
80375
+ }
80376
+ case "--password":
80377
+ parsed.password = readRequiredValue(args, ++index, "--password");
80378
+ break;
80379
+ case "--sync-interval":
80380
+ parsed.wapkRun = {
80381
+ ...parsed.wapkRun,
80382
+ syncInterval: normalizeIntegerOption(readRequiredValue(args, ++index, "--sync-interval"), "--sync-interval", 50)
80383
+ };
80384
+ break;
80385
+ case "--watcher":
80386
+ case "--use-watcher":
80387
+ parsed.wapkRun = {
80388
+ ...parsed.wapkRun,
80389
+ useWatcher: true
80390
+ };
80391
+ break;
80392
+ case "--archive-watch":
80393
+ parsed.wapkRun = {
80394
+ ...parsed.wapkRun,
80395
+ watchArchive: true
80396
+ };
80397
+ break;
80398
+ case "--no-archive-watch":
80399
+ parsed.wapkRun = {
80400
+ ...parsed.wapkRun,
80401
+ watchArchive: false
80402
+ };
80403
+ break;
80404
+ case "--archive-sync-interval":
80405
+ parsed.wapkRun = {
80406
+ ...parsed.wapkRun,
80407
+ archiveSyncInterval: normalizeIntegerOption(readRequiredValue(args, ++index, "--archive-sync-interval"), "--archive-sync-interval", 50)
80408
+ };
80409
+ break;
80410
+ case "--restart-policy":
80411
+ parsed.restartPolicy = normalizePmRestartPolicy(readRequiredValue(args, ++index, "--restart-policy"));
80412
+ break;
80413
+ case "--min-uptime":
80414
+ parsed.minUptime = normalizeIntegerOption(readRequiredValue(args, ++index, "--min-uptime"), "--min-uptime");
80415
+ break;
80416
+ case "--watch":
80417
+ parsed.watch = true;
80418
+ break;
80419
+ case "--watch-path":
80420
+ parsed.watch = true;
80421
+ parsed.watchPaths.push(readRequiredValue(args, ++index, "--watch-path"));
80422
+ break;
80423
+ case "--watch-ignore":
80424
+ parsed.watch = true;
80425
+ parsed.watchIgnore.push(readRequiredValue(args, ++index, "--watch-ignore"));
80426
+ break;
80427
+ case "--watch-debounce":
80428
+ parsed.watch = true;
80429
+ parsed.watchDebounce = normalizeIntegerOption(readRequiredValue(args, ++index, "--watch-debounce"), "--watch-debounce");
80430
+ break;
80431
+ case "--health-url":
80432
+ parsed.healthCheckUrl = readRequiredValue(args, ++index, "--health-url");
80433
+ break;
80434
+ case "--health-grace-period":
80435
+ parsed.healthCheckGracePeriod = normalizeIntegerOption(readRequiredValue(args, ++index, "--health-grace-period"), "--health-grace-period");
80436
+ break;
80437
+ case "--health-interval":
80438
+ parsed.healthCheckInterval = normalizeIntegerOption(readRequiredValue(args, ++index, "--health-interval"), "--health-interval", 250);
80439
+ break;
80440
+ case "--health-timeout":
80441
+ parsed.healthCheckTimeout = normalizeIntegerOption(readRequiredValue(args, ++index, "--health-timeout"), "--health-timeout", 250);
80442
+ break;
80443
+ case "--health-max-failures":
80444
+ parsed.healthCheckMaxFailures = normalizeIntegerOption(readRequiredValue(args, ++index, "--health-max-failures"), "--health-max-failures", 1);
80445
+ break;
80446
+ case "--no-autorestart":
80447
+ parsed.autorestart = false;
80448
+ break;
80449
+ case "--restart-delay":
80450
+ parsed.restartDelay = normalizeIntegerOption(readRequiredValue(args, ++index, "--restart-delay"), "--restart-delay");
80451
+ break;
80452
+ case "--max-restarts":
80453
+ parsed.maxRestarts = normalizeIntegerOption(readRequiredValue(args, ++index, "--max-restarts"), "--max-restarts");
80454
+ break;
80455
+ default:
80456
+ if (arg.startsWith("-")) {
80457
+ throw new Error(`Unknown pm option: ${arg}`);
80458
+ }
80459
+ if (parsed.targetToken) {
80460
+ throw new Error("pm start accepts at most one positional target.");
80461
+ }
80462
+ parsed.targetToken = arg;
80463
+ break;
80464
+ }
80465
+ }
80466
+ if (countDefinedPmWapkSources(parsed.wapk, parsed.wapkRun) > 1) {
80467
+ throw new Error("Use only one WAPK archive source per pm start: --wapk or --google-drive-file-id.");
80468
+ }
80469
+ const explicitTargets = [parsed.script, parsed.file, resolvePmWapkSourceToken(parsed.wapk, parsed.wapkRun)].filter(Boolean);
80470
+ if (explicitTargets.length > 1) {
80471
+ throw new Error("Use only one target type per pm start: --script, --file, or --wapk.");
80472
+ }
80473
+ if (parsed.healthCheckUrl && !/^https?:\/\//i.test(parsed.healthCheckUrl)) {
80474
+ throw new Error("--health-url must be an absolute http:// or https:// URL");
80475
+ }
80476
+ return parsed;
80477
+ }
80478
+ function padCell(value, width) {
80479
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
80480
+ }
80481
+ function tailLogFile(filePath, lineCount) {
80482
+ if (!(0, import_node_fs5.existsSync)(filePath)) {
80483
+ return "";
80484
+ }
80485
+ const lines = (0, import_node_fs5.readFileSync)(filePath, "utf8").split(/\r?\n/).filter((line) => line.length > 0);
80486
+ return lines.slice(-lineCount).join(import_node_os2.EOL);
80487
+ }
80488
+ function parseRunnerArgs(args) {
80489
+ let dataDir;
80490
+ let id;
80491
+ for (let index = 0; index < args.length; index++) {
80492
+ const arg = args[index];
80493
+ switch (arg) {
80494
+ case "--data-dir":
80495
+ dataDir = readRequiredValue(args, ++index, "--data-dir");
80496
+ break;
80497
+ case "--id":
80498
+ id = readRequiredValue(args, ++index, "--id");
80499
+ break;
80500
+ default:
80501
+ throw new Error(`Unknown internal pm runner option: ${arg}`);
80502
+ }
80503
+ }
80504
+ if (!dataDir || !id) {
80505
+ throw new Error("Usage: elit pm __run --data-dir <dir> --id <name>");
80506
+ }
80507
+ return {
80508
+ dataDir: (0, import_node_path5.resolve)(dataDir),
80509
+ id
80510
+ };
80511
+ }
80512
+ async function runPmRunner(args) {
80513
+ const options = parseRunnerArgs(args);
80514
+ const paths = {
80515
+ dataDir: options.dataDir,
80516
+ appsDir: (0, import_node_path5.join)(options.dataDir, "apps"),
80517
+ logsDir: (0, import_node_path5.join)(options.dataDir, "logs"),
80518
+ dumpFile: (0, import_node_path5.join)(options.dataDir, DEFAULT_PM_DUMP_FILE)
80519
+ };
80520
+ const match = findPmRecordMatch(paths, options.id);
80521
+ if (!match) {
80522
+ throw new Error(`PM record not found: ${options.id}`);
80523
+ }
80524
+ await runManagedProcessLoop(match.filePath, match.record);
80525
+ }
80526
+ async function runPmStart(args) {
80527
+ const parsed = parsePmStartArgs(args);
80528
+ const workspaceRoot = process.cwd();
80529
+ const config = await loadConfig(workspaceRoot);
80530
+ const paths = resolvePmPaths(config?.pm, workspaceRoot);
80531
+ const definitions = resolvePmStartDefinitions(parsed, config, workspaceRoot);
80532
+ const errors = [];
80533
+ for (const definition of definitions) {
80534
+ try {
80535
+ const record = await startManagedProcess(definition, paths);
80536
+ console.log(`[pm] started ${record.name} (${record.type})`);
80537
+ } catch (error) {
80538
+ const message = error instanceof Error ? error.message : String(error);
80539
+ errors.push(`[pm] ${definition.name}: ${message}`);
80540
+ }
80541
+ }
80542
+ if (errors.length > 0) {
80543
+ throw new Error(errors.join(import_node_os2.EOL));
80544
+ }
80545
+ }
80546
+ async function loadPmContext() {
80547
+ const workspaceRoot = process.cwd();
80548
+ const config = await loadConfig(workspaceRoot);
80549
+ return {
80550
+ config,
80551
+ paths: resolvePmPaths(config?.pm, workspaceRoot)
80552
+ };
80553
+ }
80554
+ function resolveNamedMatches(paths, value) {
80555
+ if (value === "all") {
80556
+ return listPmRecordMatches(paths).map(syncPmRecordLiveness);
80557
+ }
80558
+ const match = findPmRecordMatch(paths, value);
80559
+ return match ? [syncPmRecordLiveness(match)] : [];
80560
+ }
80561
+ function printPmList(paths) {
80562
+ const matches2 = listPmRecordMatches(paths).map(syncPmRecordLiveness);
80563
+ if (matches2.length === 0) {
80564
+ console.log("No managed processes found.");
80565
+ return;
80566
+ }
80567
+ const headers = [
80568
+ padCell("name", 20),
80569
+ padCell("status", 12),
80570
+ padCell("pid", 8),
80571
+ padCell("restarts", 10),
80572
+ padCell("type", 8),
80573
+ "runtime"
80574
+ ];
80575
+ console.log(headers.join(" "));
80576
+ for (const { record } of matches2) {
80577
+ console.log([
80578
+ padCell(record.name, 20),
80579
+ padCell(record.status, 12),
80580
+ padCell(record.childPid ? String(record.childPid) : "-", 8),
80581
+ padCell(String(record.restartCount ?? 0), 10),
80582
+ padCell(record.type, 8),
80583
+ record.runtime ?? "-"
80584
+ ].join(" "));
80585
+ }
80586
+ }
80587
+ function stopPmMatches(matches2) {
80588
+ let stopped = 0;
80589
+ for (const match of matches2) {
80590
+ const current = syncPmRecordLiveness(match);
80591
+ const updated = {
80592
+ ...current.record,
80593
+ desiredState: "stopped",
80594
+ status: current.record.runnerPid ? "stopping" : "stopped",
80595
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
80596
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString()
80597
+ };
80598
+ writePmRecord(current.filePath, updated);
80599
+ if (current.record.runnerPid && isProcessAlive(current.record.runnerPid)) {
80600
+ terminateProcessTree(current.record.runnerPid);
80601
+ } else if (current.record.childPid && isProcessAlive(current.record.childPid)) {
80602
+ terminateProcessTree(current.record.childPid);
80603
+ }
80604
+ writePmRecord(current.filePath, {
80605
+ ...updated,
80606
+ runnerPid: void 0,
80607
+ childPid: void 0,
80608
+ status: "stopped",
80609
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
80610
+ });
80611
+ stopped += 1;
80612
+ }
80613
+ return stopped;
80614
+ }
80615
+ async function runPmStop(args) {
80616
+ const target = args[0];
80617
+ if (!target) {
80618
+ throw new Error("Usage: elit pm stop <name|all>");
80619
+ }
80620
+ const { paths } = await loadPmContext();
80621
+ const matches2 = resolveNamedMatches(paths, target);
80622
+ if (matches2.length === 0) {
80623
+ throw new Error(`No managed process found for: ${target}`);
80624
+ }
80625
+ const count = stopPmMatches(matches2);
80626
+ console.log(`[pm] stopped ${count} process${count === 1 ? "" : "es"}`);
80627
+ }
80628
+ async function runPmRestart(args) {
80629
+ const target = args[0];
80630
+ if (!target) {
80631
+ throw new Error("Usage: elit pm restart <name|all>");
80632
+ }
80633
+ const { paths } = await loadPmContext();
80634
+ const matches2 = resolveNamedMatches(paths, target);
80635
+ if (matches2.length === 0) {
80636
+ throw new Error(`No managed process found for: ${target}`);
80637
+ }
80638
+ stopPmMatches(matches2);
80639
+ const restarted = [];
80640
+ for (const match of matches2) {
80641
+ const definition = resolvePmAppDefinition(
80642
+ toPmAppConfig(match.record),
80643
+ { name: match.record.name, env: {}, watchPaths: [], watchIgnore: [] },
80644
+ process.cwd(),
80645
+ match.record.source
80646
+ );
80647
+ await startManagedProcess(definition, paths);
80648
+ restarted.push(match.record.name);
80649
+ }
80650
+ console.log(`[pm] restarted ${restarted.join(", ")}`);
80651
+ }
80652
+ async function runPmSave() {
80653
+ const { paths } = await loadPmContext();
80654
+ ensurePmDirectories(paths);
80655
+ const runningApps = listPmRecordMatches(paths).map(syncPmRecordLiveness).filter((match) => match.record.desiredState === "running" && (match.record.status === "starting" || match.record.status === "online" || match.record.status === "restarting")).map((match) => toSavedAppDefinition(match.record));
80656
+ writePmDumpFile(paths.dumpFile, runningApps);
80657
+ console.log(`[pm] saved ${runningApps.length} process${runningApps.length === 1 ? "" : "es"} to ${paths.dumpFile}`);
80658
+ }
80659
+ async function runPmResurrect() {
80660
+ const { paths } = await loadPmContext();
80661
+ if (!(0, import_node_fs5.existsSync)(paths.dumpFile)) {
80662
+ throw new Error(`PM dump file not found: ${paths.dumpFile}`);
80663
+ }
80664
+ const dump = readPmDumpFile(paths.dumpFile);
80665
+ if (dump.apps.length === 0) {
80666
+ console.log("[pm] dump file is empty, nothing to resurrect");
80667
+ return;
80668
+ }
80669
+ const errors = [];
80670
+ let restored = 0;
80671
+ for (const app of dump.apps) {
80672
+ try {
80673
+ const definition = resolvePmAppDefinition(
80674
+ toSavedPmAppConfig(app),
80675
+ { name: app.name, env: {}, watchPaths: [], watchIgnore: [] },
80676
+ process.cwd(),
80677
+ "cli"
80678
+ );
80679
+ await startManagedProcess(definition, paths);
80680
+ restored += 1;
80681
+ } catch (error) {
80682
+ const message = error instanceof Error ? error.message : String(error);
80683
+ errors.push(`[pm] ${app.name}: ${message}`);
80684
+ }
80685
+ }
80686
+ if (errors.length > 0) {
80687
+ throw new Error([`[pm] resurrected ${restored} process${restored === 1 ? "" : "es"}`, ...errors].join(import_node_os2.EOL));
80688
+ }
80689
+ console.log(`[pm] resurrected ${restored} process${restored === 1 ? "" : "es"} from ${paths.dumpFile}`);
80690
+ }
80691
+ async function runPmDelete(args) {
80692
+ const target = args[0];
80693
+ if (!target) {
80694
+ throw new Error("Usage: elit pm delete <name|all>");
80695
+ }
80696
+ const { paths } = await loadPmContext();
80697
+ const matches2 = resolveNamedMatches(paths, target);
80698
+ if (matches2.length === 0) {
80699
+ throw new Error(`No managed process found for: ${target}`);
80700
+ }
80701
+ stopPmMatches(matches2);
80702
+ for (const match of matches2) {
80703
+ if ((0, import_node_fs5.existsSync)(match.record.logFiles.out)) {
80704
+ (0, import_node_fs5.rmSync)(match.record.logFiles.out, { force: true });
80705
+ }
80706
+ if ((0, import_node_fs5.existsSync)(match.record.logFiles.err)) {
80707
+ (0, import_node_fs5.rmSync)(match.record.logFiles.err, { force: true });
80708
+ }
80709
+ (0, import_node_fs5.rmSync)(match.filePath, { force: true });
80710
+ }
80711
+ console.log(`[pm] deleted ${matches2.length} process${matches2.length === 1 ? "" : "es"}`);
80712
+ }
80713
+ async function runPmLogs(args) {
80714
+ if (args.length === 0) {
80715
+ throw new Error("Usage: elit pm logs <name> [--lines <n>] [--stderr]");
80716
+ }
80717
+ let name;
80718
+ let lineCount = DEFAULT_LOG_LINES;
80719
+ let stderrOnly = false;
80720
+ for (let index = 0; index < args.length; index++) {
80721
+ const arg = args[index];
80722
+ switch (arg) {
80723
+ case "--lines":
80724
+ lineCount = normalizeIntegerOption(readRequiredValue(args, ++index, "--lines"), "--lines", 1);
80725
+ break;
80726
+ case "--stderr":
80727
+ stderrOnly = true;
80728
+ break;
80729
+ default:
80730
+ if (arg.startsWith("-")) {
80731
+ throw new Error(`Unknown pm logs option: ${arg}`);
80732
+ }
80733
+ if (name) {
80734
+ throw new Error("pm logs accepts exactly one process name.");
80735
+ }
80736
+ name = arg;
80737
+ break;
80738
+ }
80739
+ }
80740
+ if (!name) {
80741
+ throw new Error("Usage: elit pm logs <name> [--lines <n>] [--stderr]");
80742
+ }
80743
+ const { paths } = await loadPmContext();
80744
+ const match = findPmRecordMatch(paths, name);
80745
+ if (!match) {
80746
+ throw new Error(`No managed process found for: ${name}`);
80747
+ }
80748
+ const stdoutContent = stderrOnly ? "" : tailLogFile(match.record.logFiles.out, lineCount);
80749
+ const stderrContent = tailLogFile(match.record.logFiles.err, lineCount);
80750
+ if (!stderrOnly) {
80751
+ console.log(`== stdout: ${match.record.logFiles.out} ==`);
80752
+ console.log(stdoutContent || "(empty)");
80753
+ }
80754
+ console.log(`== stderr: ${match.record.logFiles.err} ==`);
80755
+ console.log(stderrContent || "(empty)");
80756
+ }
80757
+ function printPmHelp() {
80758
+ console.log([
80759
+ "",
80760
+ "Elit PM - lightweight process manager",
80761
+ "",
80762
+ "Usage:",
80763
+ ' elit pm start --script "npm start" --name my-app --runtime node',
80764
+ " elit pm start --wapk ./test.wapk --name my-app",
80765
+ " elit pm start --wapk gdrive://<fileId> --name my-app",
80766
+ " elit pm start --google-drive-file-id <fileId> --name my-app",
80767
+ " elit pm start ./app.ts --name my-app",
80768
+ " elit pm start --file ./app.js --name my-app",
80769
+ " elit pm start my-app",
80770
+ " elit pm start",
80771
+ " elit pm list",
80772
+ " elit pm stop <name|all>",
80773
+ " elit pm restart <name|all>",
80774
+ " elit pm delete <name|all>",
80775
+ " elit pm save",
80776
+ " elit pm resurrect",
80777
+ " elit pm logs <name> --lines 100",
80778
+ "",
80779
+ "Start Options:",
80780
+ " --script <command> Run a shell command, for example: npm start",
80781
+ " --file, -f <path> Run a .js/.mjs/.cjs/.ts file",
80782
+ " --wapk <source> Run a local .wapk file or a remote source like gdrive://<fileId>",
80783
+ " --google-drive-file-id <id> Run a WAPK archive directly from Google Drive",
80784
+ " --google-drive-token-env <name> Env var containing the Google Drive OAuth token",
80785
+ " --google-drive-access-token <value> OAuth token forwarded to elit wapk run",
80786
+ " --google-drive-shared-drive Forward supportsAllDrives=true for shared drives",
80787
+ " --runtime, -r <name> Runtime override: node, bun, deno",
80788
+ " --name, -n <name> Process name used by list/stop/restart",
80789
+ " --cwd <dir> Working directory for the managed process",
80790
+ " --env KEY=VALUE Add or override an environment variable",
80791
+ " --password <value> Password for locked WAPK archives",
80792
+ " --sync-interval <ms> Forward WAPK live-sync write interval (>= 50ms)",
80793
+ " --watcher, --use-watcher Forward event-driven WAPK file watching",
80794
+ " --archive-watch Pull archive source changes back into the temp WAPK workdir",
80795
+ " --no-archive-watch Disable archive-source read sync for WAPK apps",
80796
+ " --archive-sync-interval <ms> Forward WAPK archive read-sync interval (>= 50ms)",
80797
+ " --restart-policy <mode> Restart policy: always, on-failure, never",
80798
+ " --min-uptime <ms> Reset crash counter after this healthy uptime",
80799
+ " --watch Restart when watched files change",
80800
+ " --watch-path <path> Add a file or directory to watch",
80801
+ " --watch-ignore <pattern> Ignore watched paths matching this glob-like pattern",
80802
+ " --watch-debounce <ms> Debounce file-triggered restarts (default 250)",
80803
+ " --health-url <url> Poll an HTTP endpoint and restart after repeated failures",
80804
+ " --health-grace-period <ms> Delay before the first health check (default 5000)",
80805
+ " --health-interval <ms> Health check interval (default 10000)",
80806
+ " --health-timeout <ms> Per-request health check timeout (default 3000)",
80807
+ " --health-max-failures <n> Consecutive failures before restart (default 3)",
80808
+ " --no-autorestart Disable automatic restart",
80809
+ " --restart-delay <ms> Delay between restart attempts (default 1000)",
80810
+ " --max-restarts <count> Maximum restart attempts (default 10)",
80811
+ "",
80812
+ "Config:",
80813
+ " Add pm.apps[] to elit.config.* and run elit pm start to boot all configured apps.",
80814
+ "",
80815
+ "Example:",
80816
+ " export default {",
80817
+ " pm: {",
80818
+ " apps: [",
80819
+ ' { name: "api", script: "npm start", cwd: ".", runtime: "node" },',
80820
+ ' { name: "worker", file: "./src/worker.ts", runtime: "bun" },',
80821
+ ' { name: "desktop-app", wapk: "./dist/app.wapk", runtime: "node" },',
80822
+ ' { name: "drive-app", wapkRun: { googleDrive: { fileId: "1AbCdEfGhIjKlMnOp", accessTokenEnv: "GOOGLE_DRIVE_ACCESS_TOKEN" }, useWatcher: true, watchArchive: true } }',
80823
+ " ]",
80824
+ " }",
80825
+ " }",
80826
+ "",
80827
+ "Notes:",
80828
+ " - PM state and logs are stored in ./.elit/pm by default.",
80829
+ " - elit pm save persists running apps to pm.dumpFile or ./.elit/pm/dump.json.",
80830
+ " - elit pm resurrect restarts whatever was last saved by elit pm save.",
80831
+ " - elit pm start <name> starts a configured app by name.",
80832
+ " - TypeScript files with runtime node require tsx, otherwise use --runtime bun.",
80833
+ " - WAPK processes are executed through elit wapk run inside the manager.",
80834
+ " - WAPK PM apps can use local archives, gdrive://<fileId>, or pm.apps[].wapkRun.googleDrive."
80835
+ ].join("\n"));
80836
+ }
80837
+ async function runPmCommand(args) {
80838
+ if (args.length === 0 || args[0] === "help" || args.includes("--help") || args.includes("-h")) {
80839
+ printPmHelp();
80840
+ return;
80841
+ }
80842
+ const command = args[0];
80843
+ switch (command) {
80844
+ case "start":
80845
+ await runPmStart(args.slice(1));
80846
+ return;
80847
+ case "list":
80848
+ case "ls": {
80849
+ const { paths } = await loadPmContext();
80850
+ printPmList(paths);
80851
+ return;
80852
+ }
80853
+ case "stop":
80854
+ await runPmStop(args.slice(1));
80855
+ return;
80856
+ case "restart":
80857
+ await runPmRestart(args.slice(1));
80858
+ return;
80859
+ case "delete":
80860
+ case "remove":
80861
+ case "rm":
80862
+ await runPmDelete(args.slice(1));
80863
+ return;
80864
+ case "save":
80865
+ await runPmSave();
80866
+ return;
80867
+ case "resurrect":
80868
+ await runPmResurrect();
80869
+ return;
80870
+ case "logs":
80871
+ await runPmLogs(args.slice(1));
80872
+ return;
80873
+ case "__run":
80874
+ await runPmRunner(args.slice(1));
80875
+ return;
80876
+ default:
80877
+ throw new Error(`Unknown pm command: ${command}`);
80878
+ }
80879
+ }
80880
+
78558
80881
  // src/cli.ts
78559
- var COMMANDS = ["dev", "build", "preview", "test", "desktop", "mobile", "native", "wapk", "help", "version"];
80882
+ var COMMANDS = ["dev", "build", "preview", "test", "desktop", "mobile", "native", "pm", "wapk", "help", "version"];
78560
80883
  function setupShutdownHandlers(closeFunc) {
78561
80884
  const shutdown = async () => {
78562
80885
  console.log("\n[Server] Shutting down...");
@@ -78629,6 +80952,9 @@ async function main() {
78629
80952
  case "native":
78630
80953
  await runNative(args.slice(1));
78631
80954
  break;
80955
+ case "pm":
80956
+ await runPm(args.slice(1));
80957
+ break;
78632
80958
  case "wapk":
78633
80959
  await runWapk(args.slice(1));
78634
80960
  break;
@@ -78849,6 +81175,14 @@ async function runWapk(args) {
78849
81175
  process.exit(1);
78850
81176
  }
78851
81177
  }
81178
+ async function runPm(args) {
81179
+ try {
81180
+ await runPmCommand(args);
81181
+ } catch (error) {
81182
+ console.error(error instanceof Error ? error.message : error);
81183
+ process.exit(1);
81184
+ }
81185
+ }
78852
81186
  function parseTestArgs(args) {
78853
81187
  const options = {};
78854
81188
  for (let i = 0; i < args.length; i++) {
@@ -79046,6 +81380,7 @@ Commands:
79046
81380
  desktop Run or build a native desktop app
79047
81381
  mobile Run native mobile workflow commands
79048
81382
  native Generate native target code from an Elit entry
81383
+ pm Manage background processes and packaged apps
79049
81384
  wapk Pack, inspect, extract, or run a .wapk app
79050
81385
  version Show version number
79051
81386
  help Show this help message
@@ -79092,18 +81427,38 @@ Native Options:
79092
81427
  elit native generate ... --export <name> Select a specific module export
79093
81428
 
79094
81429
  WAPK Options:
79095
- elit wapk <file.wapk> Run a packaged app
79096
- elit wapk run <file.wapk> Run a packaged app
81430
+ elit wapk [file.wapk] Run a packaged app or the configured default archive
81431
+ elit wapk gdrive://<fileId> Run a packaged app directly from Google Drive
81432
+ elit wapk run [file.wapk] Run a packaged app or the configured default archive
81433
+ elit wapk run --google-drive-file-id <id> Run a packaged app directly from Google Drive
79097
81434
  elit wapk pack [directory] Pack a directory into a .wapk archive
79098
81435
  elit wapk inspect <file.wapk> Inspect a .wapk archive
79099
81436
  elit wapk extract <file.wapk> Extract a .wapk archive
79100
- elit wapk --runtime node|bun|deno <file> Override the packaged runtime
81437
+ elit wapk --runtime node|bun|deno [file] Override the packaged runtime
81438
+
81439
+ PM Options:
81440
+ elit pm start --script "npm start" -n my-app Start a shell command in the background
81441
+ elit pm start ./app.ts -n my-app Start a file with inferred runtime
81442
+ elit pm start --wapk ./app.wapk -n my-app Start a WAPK app through the manager
81443
+ elit pm start --wapk gdrive://<fileId> -n my-app Start a Google Drive WAPK app through the manager
81444
+ elit pm start --google-drive-file-id <id> -n my-app Start a Google Drive WAPK app without a positional source
81445
+ elit pm start my-app --watch Start one configured app with file watching enabled
81446
+ elit pm start Start all pm.apps[] entries from elit.config.*
81447
+ elit pm start my-app Start one configured app by name
81448
+ elit pm list Show managed process status
81449
+ elit pm stop <name|all> Stop one or all managed processes
81450
+ elit pm restart <name|all> Restart one or all managed processes
81451
+ elit pm delete <name|all> Remove process metadata and logs
81452
+ elit pm save Persist the running process list to pm.dumpFile
81453
+ elit pm resurrect Restart the last saved process list
81454
+ elit pm logs <name> --lines 100 Show recent stdout/stderr logs
79101
81455
 
79102
81456
  Note: Build configuration supports both single and multiple builds:
79103
81457
  - Single build: build: { entry: 'src/app.ts', outDir: 'dist' }
79104
81458
  - Multiple builds: build: [{ entry: 'src/app1.ts' }, { entry: 'src/app2.ts' }]
79105
81459
  When using array, all builds run sequentially.
79106
81460
  Desktop commands can read desktop.entry or desktop.native.entry from elit.config.ts when [entry] is omitted, depending on desktop.mode.
81461
+ PM commands read pm.apps[], pm.dataDir, and pm.dumpFile from elit.config.* when present.
79107
81462
 
79108
81463
  Preview Options:
79109
81464
  -p, --port <number> Port to run server on (default: 4173)
@@ -79419,6 +81774,7 @@ main().catch((error) => {
79419
81774
  runDev,
79420
81775
  runMobile,
79421
81776
  runNative,
81777
+ runPm,
79422
81778
  runPreview,
79423
81779
  runTest,
79424
81780
  runWapk