@serviceme/devtools-cli 0.1.3 → 0.1.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.
@@ -4,8 +4,9 @@
4
4
  var readline = require('readline');
5
5
  var child_process = require('child_process');
6
6
  require('fs/promises');
7
- require('path');
8
- require('fs');
7
+ var path5 = require('path');
8
+ var fs6 = require('fs');
9
+ require('os');
9
10
  require('crypto');
10
11
 
11
12
  function _interopNamespace(e) {
@@ -27,6 +28,8 @@ function _interopNamespace(e) {
27
28
  }
28
29
 
29
30
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
31
+ var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
32
+ var fs6__namespace = /*#__PURE__*/_interopNamespace(fs6);
30
33
 
31
34
  var __create = Object.create;
32
35
  var __defProp = Object.defineProperty;
@@ -297,9 +300,9 @@ var require_esprima = __commonJS({
297
300
  });
298
301
  };
299
302
  CommentHandler2.prototype.visitComment = function(node, metadata) {
300
- var type = node.type[0] === "L" ? "Line" : "Block";
303
+ var type2 = node.type[0] === "L" ? "Line" : "Block";
301
304
  var comment = {
302
- type,
305
+ type: type2,
303
306
  value: node.value
304
307
  };
305
308
  if (node.range) {
@@ -312,7 +315,7 @@ var require_esprima = __commonJS({
312
315
  if (this.attach) {
313
316
  var entry = {
314
317
  comment: {
315
- type,
318
+ type: type2,
316
319
  value: node.value,
317
320
  range: [metadata.start.offset, metadata.end.offset]
318
321
  },
@@ -321,7 +324,7 @@ var require_esprima = __commonJS({
321
324
  if (node.loc) {
322
325
  entry.comment.loc = node.loc;
323
326
  }
324
- node.type = type;
327
+ node.type = type2;
325
328
  this.leading.push(entry);
326
329
  this.trailing.push(entry);
327
330
  }
@@ -5136,28 +5139,28 @@ var require_esprima = __commonJS({
5136
5139
  };
5137
5140
  };
5138
5141
  Scanner2.prototype.scanIdentifier = function() {
5139
- var type;
5142
+ var type2;
5140
5143
  var start = this.index;
5141
5144
  var id = this.source.charCodeAt(start) === 92 ? this.getComplexIdentifier() : this.getIdentifier();
5142
5145
  if (id.length === 1) {
5143
- type = 3;
5146
+ type2 = 3;
5144
5147
  } else if (this.isKeyword(id)) {
5145
- type = 4;
5148
+ type2 = 4;
5146
5149
  } else if (id === "null") {
5147
- type = 5;
5150
+ type2 = 5;
5148
5151
  } else if (id === "true" || id === "false") {
5149
- type = 1;
5152
+ type2 = 1;
5150
5153
  } else {
5151
- type = 3;
5154
+ type2 = 3;
5152
5155
  }
5153
- if (type !== 3 && start + id.length !== this.index) {
5156
+ if (type2 !== 3 && start + id.length !== this.index) {
5154
5157
  var restore = this.index;
5155
5158
  this.index = start;
5156
5159
  this.tolerateUnexpectedToken(messages_1.Messages.InvalidEscapedReservedWord);
5157
5160
  this.index = restore;
5158
5161
  }
5159
5162
  return {
5160
- type,
5163
+ type: type2,
5161
5164
  value: id,
5162
5165
  lineNumber: this.lineNumber,
5163
5166
  lineStart: this.lineStart,
@@ -7608,13 +7611,13 @@ var require_parse = __commonJS({
7608
7611
  last = current;
7609
7612
  current = new_token;
7610
7613
  };
7611
- var type = () => {
7614
+ var type2 = () => {
7612
7615
  if (!current) {
7613
7616
  unexpected_end();
7614
7617
  }
7615
7618
  return current.type === "Punctuator" ? current.value : current.type;
7616
7619
  };
7617
- var is = (t) => type() === t;
7620
+ var is = (t) => type2() === t;
7618
7621
  var expect = (a) => {
7619
7622
  if (!is(a)) {
7620
7623
  unexpected();
@@ -7769,7 +7772,7 @@ var require_parse = __commonJS({
7769
7772
  return array;
7770
7773
  };
7771
7774
  function walk() {
7772
- let tt = type();
7775
+ let tt = type2();
7773
7776
  if (tt === CURLY_BRACKET_OPEN) {
7774
7777
  next();
7775
7778
  return {
@@ -7785,7 +7788,7 @@ var require_parse = __commonJS({
7785
7788
  let negative = EMPTY;
7786
7789
  if (tt === MINUS) {
7787
7790
  next();
7788
- tt = type();
7791
+ tt = type2();
7789
7792
  negative = MINUS;
7790
7793
  }
7791
7794
  let v;
@@ -7911,11 +7914,11 @@ var require_stringify = __commonJS({
7911
7914
  let is_line_comment = false;
7912
7915
  const str = comments.reduce((prev, {
7913
7916
  inline,
7914
- type,
7917
+ type: type2,
7915
7918
  value
7916
7919
  }) => {
7917
7920
  const delimiter = inline ? SPACE : LF + deeper_gap;
7918
- is_line_comment = type === "LineComment";
7921
+ is_line_comment = type2 === "LineComment";
7919
7922
  return prev + delimiter + comment_stringify(value, is_line_comment);
7920
7923
  }, EMPTY);
7921
7924
  return display_block || is_line_comment ? str + LF + deeper_gap : str;
@@ -8143,7 +8146,7 @@ var require_pend = __commonJS({
8143
8146
  // ../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/fd-slicer.js
8144
8147
  var require_fd_slicer = __commonJS({
8145
8148
  "../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/fd-slicer.js"(exports$1) {
8146
- var fs8 = __require("fs");
8149
+ var fs10 = __require("fs");
8147
8150
  var util = __require("util");
8148
8151
  var stream = __require("stream");
8149
8152
  var Readable = stream.Readable;
@@ -8168,7 +8171,7 @@ var require_fd_slicer = __commonJS({
8168
8171
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
8169
8172
  var self = this;
8170
8173
  self.pend.go(function(cb) {
8171
- fs8.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
8174
+ fs10.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
8172
8175
  cb();
8173
8176
  callback(err, bytesRead, buffer2);
8174
8177
  });
@@ -8177,7 +8180,7 @@ var require_fd_slicer = __commonJS({
8177
8180
  FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
8178
8181
  var self = this;
8179
8182
  self.pend.go(function(cb) {
8180
- fs8.write(self.fd, buffer, offset, length, position, function(err, written, buffer2) {
8183
+ fs10.write(self.fd, buffer, offset, length, position, function(err, written, buffer2) {
8181
8184
  cb();
8182
8185
  callback(err, written, buffer2);
8183
8186
  });
@@ -8198,7 +8201,7 @@ var require_fd_slicer = __commonJS({
8198
8201
  if (self.refCount > 0) return;
8199
8202
  if (self.refCount < 0) throw new Error("invalid unref");
8200
8203
  if (self.autoClose) {
8201
- fs8.close(self.fd, onCloseDone);
8204
+ fs10.close(self.fd, onCloseDone);
8202
8205
  }
8203
8206
  function onCloseDone(err) {
8204
8207
  if (err) {
@@ -8235,7 +8238,7 @@ var require_fd_slicer = __commonJS({
8235
8238
  self.context.pend.go(function(cb) {
8236
8239
  if (self.destroyed) return cb();
8237
8240
  var buffer = Buffer.allocUnsafe(toRead);
8238
- fs8.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
8241
+ fs10.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
8239
8242
  if (err) {
8240
8243
  self.destroy(err);
8241
8244
  } else if (bytesRead === 0) {
@@ -8282,7 +8285,7 @@ var require_fd_slicer = __commonJS({
8282
8285
  }
8283
8286
  self.context.pend.go(function(cb) {
8284
8287
  if (self.destroyed) return cb();
8285
- fs8.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err2, bytes) {
8288
+ fs10.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err2, bytes) {
8286
8289
  if (err2) {
8287
8290
  self.destroy();
8288
8291
  cb();
@@ -8720,7 +8723,7 @@ var require_buffer_crc32 = __commonJS({
8720
8723
  // ../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/index.js
8721
8724
  var require_yauzl = __commonJS({
8722
8725
  "../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/index.js"(exports$1) {
8723
- var fs8 = __require("fs");
8726
+ var fs10 = __require("fs");
8724
8727
  var zlib = __require("zlib");
8725
8728
  var fd_slicer = require_fd_slicer();
8726
8729
  var crc32 = require_buffer_crc32();
@@ -8741,7 +8744,7 @@ var require_yauzl = __commonJS({
8741
8744
  exports$1.Entry = Entry;
8742
8745
  exports$1.LocalFileHeader = LocalFileHeader;
8743
8746
  exports$1.RandomAccessReader = RandomAccessReader;
8744
- function open2(path7, options2, callback) {
8747
+ function open2(path8, options2, callback) {
8745
8748
  if (typeof options2 === "function") {
8746
8749
  callback = options2;
8747
8750
  options2 = null;
@@ -8753,10 +8756,10 @@ var require_yauzl = __commonJS({
8753
8756
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
8754
8757
  if (options2.strictFileNames == null) options2.strictFileNames = false;
8755
8758
  if (callback == null) callback = defaultCallback;
8756
- fs8.open(path7, "r", function(err, fd) {
8759
+ fs10.open(path8, "r", function(err, fd) {
8757
8760
  if (err) return callback(err);
8758
8761
  fromFd(fd, options2, function(err2, zipfile) {
8759
- if (err2) fs8.close(fd, defaultCallback);
8762
+ if (err2) fs10.close(fd, defaultCallback);
8760
8763
  callback(err2, zipfile);
8761
8764
  });
8762
8765
  });
@@ -8773,7 +8776,7 @@ var require_yauzl = __commonJS({
8773
8776
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
8774
8777
  if (options2.strictFileNames == null) options2.strictFileNames = false;
8775
8778
  if (callback == null) callback = defaultCallback;
8776
- fs8.fstat(fd, function(err, stats) {
8779
+ fs10.fstat(fd, function(err, stats) {
8777
8780
  if (err) return callback(err);
8778
8781
  var reader = fd_slicer.createFromFd(fd, { autoClose: true });
8779
8782
  fromRandomAccessReader(reader, stats.size, options2, callback);
@@ -9597,7 +9600,7 @@ function normalizeServicemeError(error, fallbackCode = "internal_error") {
9597
9600
  }
9598
9601
 
9599
9602
  // src/version.ts
9600
- var SERVICEME_CLI_VERSION = "0.1.3";
9603
+ var SERVICEME_CLI_VERSION = "0.1.4";
9601
9604
 
9602
9605
  // src/bridge/ndjson.ts
9603
9606
  function writeBridgeMessage(message) {
@@ -9630,7 +9633,8 @@ async function runCommand(command, options2 = {}) {
9630
9633
  cwd: options2.cwd,
9631
9634
  env: options2.env,
9632
9635
  shell: options2.shell,
9633
- stdio: "pipe"
9636
+ stdio: "pipe",
9637
+ windowsHide: true
9634
9638
  });
9635
9639
  let stdout = "";
9636
9640
  let stderr = "";
@@ -9717,8 +9721,45 @@ __toESM(require_src2());
9717
9721
 
9718
9722
  // ../../packages/serviceme-core/src/utils/fileUtils.ts
9719
9723
  __toESM(require_yauzl());
9720
- var DEFAULT_TIMEOUT = 3e5;
9724
+
9725
+ // ../../packages/serviceme-core/src/scheduled-tasks/executors/timeout.ts
9726
+ function resolveConfiguredTimeoutMs(timeoutSeconds, defaultTimeoutMs) {
9727
+ if (timeoutSeconds === 0) {
9728
+ return void 0;
9729
+ }
9730
+ if (typeof timeoutSeconds !== "number" || !Number.isFinite(timeoutSeconds) || timeoutSeconds < 0) {
9731
+ return defaultTimeoutMs;
9732
+ }
9733
+ return timeoutSeconds * 1e3;
9734
+ }
9735
+
9736
+ // ../../packages/serviceme-core/src/scheduled-tasks/executors/GithubCopilotCliExecutor.ts
9721
9737
  var MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
9738
+ var DEFAULT_TIMEOUT_MS = 3e5;
9739
+ function redactArgs(args) {
9740
+ const redacted = [];
9741
+ let redactNext = false;
9742
+ for (const arg of args) {
9743
+ if (redactNext) {
9744
+ redacted.push("<redacted>");
9745
+ redactNext = false;
9746
+ continue;
9747
+ }
9748
+ redacted.push(arg);
9749
+ if (arg === "--prompt") {
9750
+ redactNext = true;
9751
+ }
9752
+ }
9753
+ return redacted;
9754
+ }
9755
+ function writeDiagnostic(message) {
9756
+ const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
9757
+ if (logPath) {
9758
+ fs6__namespace.appendFileSync(logPath, message);
9759
+ return;
9760
+ }
9761
+ process.stderr.write(message);
9762
+ }
9722
9763
  var GithubCopilotCliExecutor = class {
9723
9764
  async execute(payload, abortSignal) {
9724
9765
  const authenticated = await isCopilotAuthenticated();
@@ -9741,7 +9782,7 @@ var GithubCopilotCliExecutor = class {
9741
9782
  }
9742
9783
  executeStreaming(payload, onOutput, abortSignal) {
9743
9784
  const p = payload;
9744
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT;
9785
+ const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS);
9745
9786
  let resolve;
9746
9787
  const resultPromise = new Promise((r) => {
9747
9788
  resolve = r;
@@ -9750,7 +9791,7 @@ var GithubCopilotCliExecutor = class {
9750
9791
  const settle = (result) => {
9751
9792
  if (settled) return;
9752
9793
  settled = true;
9753
- clearTimeout(timer);
9794
+ if (timer) clearTimeout(timer);
9754
9795
  resolve?.(result);
9755
9796
  };
9756
9797
  if (abortSignal?.aborted) {
@@ -9776,23 +9817,32 @@ var GithubCopilotCliExecutor = class {
9776
9817
  if (p.agent) {
9777
9818
  args.push("--agent", p.agent);
9778
9819
  }
9779
- if (p.timeout != null) {
9780
- args.push("--timeout", String(p.timeout));
9781
- }
9820
+ args.push("--timeout", String(p.timeout ?? 0));
9821
+ writeDiagnostic(
9822
+ `[GithubCopilotCliExecutor] spawn: command=serviceme, args=${JSON.stringify(redactArgs(args))}, promptLen=${p.prompt.length}, cwd=${p.workspace ?? "(default)"}, platform=${process.platform}, windowsHide=true, pid=${process.pid}
9823
+ `
9824
+ );
9782
9825
  const child = child_process.spawn("serviceme", args, {
9783
9826
  cwd: p.workspace,
9784
- stdio: ["ignore", "pipe", "pipe"]
9827
+ stdio: ["ignore", "pipe", "pipe"],
9828
+ windowsHide: true
9785
9829
  });
9786
- const timer = setTimeout(() => {
9830
+ if (child.pid) {
9831
+ writeDiagnostic(
9832
+ `[GithubCopilotCliExecutor] spawned child PID=${child.pid}
9833
+ `
9834
+ );
9835
+ }
9836
+ const timer = timeoutMs != null ? setTimeout(() => {
9787
9837
  child.kill("SIGTERM");
9788
9838
  setTimeout(() => {
9789
9839
  if (!child.killed) child.kill("SIGKILL");
9790
9840
  }, 5e3);
9791
9841
  settle({
9792
9842
  status: "timeout",
9793
- error: `Copilot CLI execution timed out after ${timeout / 1e3}s`
9843
+ error: `Copilot CLI execution timed out after ${timeoutMs / 1e3}s`
9794
9844
  });
9795
- }, timeout);
9845
+ }, timeoutMs) : void 0;
9796
9846
  let stdoutBuf = "";
9797
9847
  let stderrBuf = "";
9798
9848
  child.stdout.on("data", (chunk) => {
@@ -9836,17 +9886,19 @@ var GithubCopilotCliExecutor = class {
9836
9886
  };
9837
9887
 
9838
9888
  // ../../packages/serviceme-core/src/scheduled-tasks/executors/HttpRequestExecutor.ts
9839
- var DEFAULT_TIMEOUT2 = 3e4;
9889
+ var DEFAULT_TIMEOUT_MS2 = 3e4;
9840
9890
  var HttpRequestExecutor = class {
9841
9891
  async execute(payload, abortSignal) {
9842
9892
  const p = payload;
9843
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT2;
9893
+ const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS2);
9844
9894
  const ac = new AbortController();
9845
- const timer = setTimeout(() => {
9895
+ let timedOut = false;
9896
+ const timer = timeoutMs != null ? setTimeout(() => {
9897
+ timedOut = true;
9846
9898
  ac.abort();
9847
- }, timeout);
9899
+ }, timeoutMs) : void 0;
9848
9900
  if (abortSignal?.aborted) {
9849
- clearTimeout(timer);
9901
+ if (timer) clearTimeout(timer);
9850
9902
  return { status: "cancelled", error: "Execution aborted" };
9851
9903
  }
9852
9904
  let externalAbort = false;
@@ -9854,7 +9906,7 @@ var HttpRequestExecutor = class {
9854
9906
  "abort",
9855
9907
  () => {
9856
9908
  externalAbort = true;
9857
- clearTimeout(timer);
9909
+ if (timer) clearTimeout(timer);
9858
9910
  ac.abort();
9859
9911
  },
9860
9912
  { once: true }
@@ -9866,7 +9918,7 @@ var HttpRequestExecutor = class {
9866
9918
  body: p.body,
9867
9919
  signal: ac.signal
9868
9920
  });
9869
- clearTimeout(timer);
9921
+ if (timer) clearTimeout(timer);
9870
9922
  const body = await response.text();
9871
9923
  if (response.ok) {
9872
9924
  return {
@@ -9881,14 +9933,17 @@ ${body}`.trim()
9881
9933
  ${body}`.trim()
9882
9934
  };
9883
9935
  } catch (err) {
9884
- clearTimeout(timer);
9936
+ if (timer) clearTimeout(timer);
9885
9937
  if (err instanceof Error && err.name === "AbortError") {
9886
9938
  if (externalAbort) {
9887
9939
  return { status: "cancelled", error: "Execution cancelled" };
9888
9940
  }
9941
+ if (!timedOut || timeoutMs == null) {
9942
+ return { status: "failure", error: err.message };
9943
+ }
9889
9944
  return {
9890
9945
  status: "timeout",
9891
- error: `HTTP request timed out after ${timeout / 1e3}s`
9946
+ error: `HTTP request timed out after ${timeoutMs / 1e3}s`
9892
9947
  };
9893
9948
  }
9894
9949
  const message = err instanceof Error ? err.message : String(err);
@@ -9896,8 +9951,80 @@ ${body}`.trim()
9896
9951
  }
9897
9952
  }
9898
9953
  };
9899
- var DEFAULT_TIMEOUT3 = 6e4;
9900
9954
  var MAX_OUTPUT_BYTES2 = 1024 * 1024;
9955
+ var DEFAULT_TIMEOUT_MS3 = 6e4;
9956
+ var POSIX_SHELL_CANDIDATES = ["bash.exe", "sh.exe"];
9957
+ function resolveShellExecution(script, options2 = {}) {
9958
+ const platform = options2.platform ?? process.platform;
9959
+ const env = options2.env ?? process.env;
9960
+ const fileExists = options2.fileExists ?? fs6__namespace.existsSync;
9961
+ if (platform === "win32") {
9962
+ const posixShell = usesPosixShellSyntax(script) ? findWindowsPosixShell(env, fileExists) : null;
9963
+ if (posixShell) {
9964
+ return {
9965
+ command: posixShell,
9966
+ args: ["-s"],
9967
+ stdinScript: script,
9968
+ outputEncoding: "utf8",
9969
+ shellKind: "posix"
9970
+ };
9971
+ }
9972
+ return {
9973
+ command: env.ComSpec ?? env.COMSPEC ?? "cmd.exe",
9974
+ args: ["/d", "/s", "/c", script],
9975
+ outputEncoding: "utf8",
9976
+ shellKind: "cmd"
9977
+ };
9978
+ }
9979
+ return {
9980
+ command: "sh",
9981
+ args: ["-s"],
9982
+ stdinScript: script,
9983
+ outputEncoding: "utf8",
9984
+ shellKind: "posix"
9985
+ };
9986
+ }
9987
+ function usesPosixShellSyntax(script) {
9988
+ return /\$\([^)]*\)|`[^`]*`/.test(script);
9989
+ }
9990
+ function findWindowsPosixShell(env, fileExists) {
9991
+ const explicitShell = env.SERVICEME_POSIX_SHELL;
9992
+ if (explicitShell && fileExists(explicitShell)) {
9993
+ return explicitShell;
9994
+ }
9995
+ const knownGitBashPaths = [
9996
+ "C:\\Program Files\\Git\\bin\\bash.exe",
9997
+ "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
9998
+ "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
9999
+ "C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
10000
+ ];
10001
+ for (const candidate of knownGitBashPaths) {
10002
+ if (fileExists(candidate)) return candidate;
10003
+ }
10004
+ const pathValue = env.Path ?? env.PATH ?? "";
10005
+ for (const dir of pathValue.split(path5__namespace.win32.delimiter)) {
10006
+ if (!dir) continue;
10007
+ for (const executable of POSIX_SHELL_CANDIDATES) {
10008
+ const candidate = path5__namespace.win32.join(dir, executable);
10009
+ if (fileExists(candidate) && !isWindowsWslLauncher(candidate)) {
10010
+ return candidate;
10011
+ }
10012
+ }
10013
+ }
10014
+ return null;
10015
+ }
10016
+ function isWindowsWslLauncher(candidate) {
10017
+ const normalized = path5__namespace.win32.normalize(candidate).toLowerCase();
10018
+ return normalized.endsWith("\\windows\\system32\\bash.exe") || normalized.endsWith("\\windows\\syswow64\\bash.exe");
10019
+ }
10020
+ function writeDiagnostic2(message) {
10021
+ const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
10022
+ if (logPath) {
10023
+ fs6__namespace.appendFileSync(logPath, message);
10024
+ return;
10025
+ }
10026
+ process.stderr.write(message);
10027
+ }
9901
10028
  var ShellExecutor = class {
9902
10029
  async execute(payload, abortSignal) {
9903
10030
  let output = "";
@@ -9913,7 +10040,7 @@ var ShellExecutor = class {
9913
10040
  }
9914
10041
  executeStreaming(payload, onOutput, abortSignal) {
9915
10042
  const p = payload;
9916
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT3;
10043
+ const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS3);
9917
10044
  let resolve;
9918
10045
  const resultPromise = new Promise((r) => {
9919
10046
  resolve = r;
@@ -9922,7 +10049,7 @@ var ShellExecutor = class {
9922
10049
  const settle = (result) => {
9923
10050
  if (settled) return;
9924
10051
  settled = true;
9925
- clearTimeout(timer);
10052
+ if (timer) clearTimeout(timer);
9926
10053
  resolve?.(result);
9927
10054
  };
9928
10055
  if (abortSignal?.aborted) {
@@ -9935,37 +10062,65 @@ var ShellExecutor = class {
9935
10062
  }
9936
10063
  };
9937
10064
  }
9938
- const child = child_process.spawn("sh", ["-c", p.script], {
10065
+ const shellExecution = resolveShellExecution(p.script);
10066
+ const spawnOpts = {
9939
10067
  cwd: p.cwd,
9940
- stdio: ["ignore", "pipe", "pipe"]
9941
- });
9942
- const timer = setTimeout(() => {
10068
+ stdio: [shellExecution.stdinScript ? "pipe" : "ignore", "pipe", "pipe"],
10069
+ windowsHide: true
10070
+ };
10071
+ writeDiagnostic2(
10072
+ `[ShellExecutor] spawn:
10073
+ platform=${process.platform}
10074
+ shell=${shellExecution.shellKind}
10075
+ command=${shellExecution.command}
10076
+ args=${JSON.stringify(shellExecution.args.filter((a) => a !== p.script))}
10077
+ stdin=${shellExecution.stdinScript ? "true" : "false"}
10078
+ cwd=${p.cwd ?? "(default)"}
10079
+ timeout=${timeoutMs != null ? `${timeoutMs}ms` : "unlimited"}
10080
+ scriptLen=${p.script.length}
10081
+ windowsHide=true
10082
+ daemonPid=${process.pid}
10083
+ `
10084
+ );
10085
+ const child = child_process.spawn(shellExecution.command, shellExecution.args, spawnOpts);
10086
+ if (shellExecution.stdinScript && child.stdin) {
10087
+ child.stdin.end(shellExecution.stdinScript);
10088
+ }
10089
+ if (child.pid) {
10090
+ writeDiagnostic2(`[ShellExecutor] spawned child PID=${child.pid}
10091
+ `);
10092
+ }
10093
+ const timer = timeoutMs != null ? setTimeout(() => {
9943
10094
  child.kill("SIGTERM");
9944
10095
  setTimeout(() => {
9945
10096
  if (!child.killed) child.kill("SIGKILL");
9946
10097
  }, 5e3);
9947
10098
  settle({
9948
10099
  status: "timeout",
9949
- error: `Shell execution timed out after ${timeout / 1e3}s`
10100
+ error: `Shell execution timed out after ${timeoutMs / 1e3}s`
9950
10101
  });
9951
- }, timeout);
10102
+ }, timeoutMs) : void 0;
9952
10103
  let stdoutBuf = "";
9953
10104
  let stderrBuf = "";
9954
- child.stdout.on("data", (chunk) => {
9955
- const data = chunk.toString();
10105
+ child.stdout?.on("data", (chunk) => {
10106
+ const data = chunk.toString(shellExecution.outputEncoding);
9956
10107
  stdoutBuf += data;
9957
10108
  if (stdoutBuf.length > MAX_OUTPUT_BYTES2)
9958
10109
  stdoutBuf = stdoutBuf.slice(-MAX_OUTPUT_BYTES2);
9959
10110
  onOutput("stdout", data);
9960
10111
  });
9961
- child.stderr.on("data", (chunk) => {
9962
- const data = chunk.toString();
10112
+ child.stderr?.on("data", (chunk) => {
10113
+ const data = chunk.toString(shellExecution.outputEncoding);
9963
10114
  stderrBuf += data;
9964
10115
  if (stderrBuf.length > MAX_OUTPUT_BYTES2)
9965
10116
  stderrBuf = stderrBuf.slice(-MAX_OUTPUT_BYTES2);
9966
10117
  onOutput("stderr", data);
9967
10118
  });
9968
10119
  child.on("close", (code) => {
10120
+ writeDiagnostic2(
10121
+ `[ShellExecutor] child PID=${child.pid} exited: code=${code}
10122
+ `
10123
+ );
9969
10124
  if (code === 0) {
9970
10125
  settle({ status: "success", output: stdoutBuf || void 0 });
9971
10126
  } else {
@@ -10009,8 +10164,59 @@ function getExecutor(taskType) {
10009
10164
  }
10010
10165
  return executor;
10011
10166
  }
10167
+ function isRecord3(value) {
10168
+ return value !== null && typeof value === "object" && !Array.isArray(value);
10169
+ }
10170
+ function requireNonEmptyString(payload, field, taskType) {
10171
+ if (!isRecord3(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
10172
+ throw createServicemeError(
10173
+ "invalid_payload",
10174
+ `${taskType} payload ${field} is required`
10175
+ );
10176
+ }
10177
+ }
10178
+ function validateTaskPayload(taskType, payload) {
10179
+ switch (taskType) {
10180
+ case "command":
10181
+ requireNonEmptyString(payload, "command", taskType);
10182
+ return;
10183
+ case "shell":
10184
+ requireNonEmptyString(payload, "script", taskType);
10185
+ return;
10186
+ case "http_request":
10187
+ requireNonEmptyString(payload, "url", taskType);
10188
+ requireNonEmptyString(payload, "method", taskType);
10189
+ return;
10190
+ case "github_copilot_cli":
10191
+ requireNonEmptyString(payload, "prompt", taskType);
10192
+ return;
10193
+ }
10194
+ }
10012
10195
 
10013
10196
  // ../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts
10197
+ function hasNonEmptyString(value) {
10198
+ return typeof value === "string" && value.trim().length > 0;
10199
+ }
10200
+ function resolveTaskExecutionPayload(taskType, payload, workspacePath) {
10201
+ if (!hasNonEmptyString(workspacePath)) {
10202
+ return payload;
10203
+ }
10204
+ if (taskType === "shell") {
10205
+ const shellPayload = payload;
10206
+ if (hasNonEmptyString(shellPayload.cwd)) {
10207
+ return shellPayload;
10208
+ }
10209
+ return { ...shellPayload, cwd: workspacePath };
10210
+ }
10211
+ if (taskType === "github_copilot_cli") {
10212
+ const copilotPayload = payload;
10213
+ if (hasNonEmptyString(copilotPayload.workspace)) {
10214
+ return copilotPayload;
10215
+ }
10216
+ return { ...copilotPayload, workspace: workspacePath };
10217
+ }
10218
+ return payload;
10219
+ }
10014
10220
  var TaskExecutionEngine = class {
10015
10221
  constructor(getExecutor2) {
10016
10222
  this.getExecutor = getExecutor2;
@@ -10031,7 +10237,6 @@ var TaskExecutionEngine = class {
10031
10237
  );
10032
10238
  }
10033
10239
  }
10034
- const executor = this.getExecutor(snapshot.type);
10035
10240
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
10036
10241
  if (!this.taskExecutions.has(snapshot.taskId)) {
10037
10242
  this.taskExecutions.set(snapshot.taskId, /* @__PURE__ */ new Set());
@@ -10051,10 +10256,17 @@ var TaskExecutionEngine = class {
10051
10256
  startedAt
10052
10257
  });
10053
10258
  try {
10259
+ const executionPayload = resolveTaskExecutionPayload(
10260
+ snapshot.type,
10261
+ snapshot.payload,
10262
+ snapshot.workspacePath
10263
+ );
10264
+ validateTaskPayload(snapshot.type, executionPayload);
10265
+ const executor = this.getExecutor(snapshot.type);
10054
10266
  let result;
10055
10267
  if (isStreamingTaskExecutor(executor)) {
10056
10268
  const handle = executor.executeStreaming(
10057
- snapshot.payload,
10269
+ executionPayload,
10058
10270
  (stream, data) => {
10059
10271
  this.listener?.onOutput({
10060
10272
  executionId: snapshot.executionId,
@@ -10070,7 +10282,7 @@ var TaskExecutionEngine = class {
10070
10282
  };
10071
10283
  result = await handle.result;
10072
10284
  } else {
10073
- result = await executor.execute(snapshot.payload, ac.signal);
10285
+ result = await executor.execute(executionPayload, ac.signal);
10074
10286
  }
10075
10287
  const log = {
10076
10288
  id: snapshot.executionId,