@serviceme/devtools-cli 0.1.3 → 0.1.5

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.5";
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,69 @@ __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
+ }
9763
+ function resolveGithubCopilotCliExecution(payload) {
9764
+ const args = ["copilot", "prompt", "--prompt", payload.prompt];
9765
+ if (payload.autopilot) {
9766
+ args.push("--autopilot");
9767
+ }
9768
+ if (payload.allowTools && payload.allowTools.length > 0) {
9769
+ args.push("--allow-tools", payload.allowTools.join(","));
9770
+ }
9771
+ if (payload.model) {
9772
+ args.push("--model", payload.model);
9773
+ }
9774
+ if (payload.agent) {
9775
+ args.push("--agent", payload.agent);
9776
+ }
9777
+ args.push("--timeout", String(payload.timeout ?? 0));
9778
+ return {
9779
+ command: "serviceme",
9780
+ args,
9781
+ cwd: payload.workspace,
9782
+ timeoutMs: resolveConfiguredTimeoutMs(payload.timeout, DEFAULT_TIMEOUT_MS),
9783
+ diagnosticArgs: redactArgs(args),
9784
+ promptLen: payload.prompt.length
9785
+ };
9786
+ }
9722
9787
  var GithubCopilotCliExecutor = class {
9723
9788
  async execute(payload, abortSignal) {
9724
9789
  const authenticated = await isCopilotAuthenticated();
@@ -9741,7 +9806,7 @@ var GithubCopilotCliExecutor = class {
9741
9806
  }
9742
9807
  executeStreaming(payload, onOutput, abortSignal) {
9743
9808
  const p = payload;
9744
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT;
9809
+ const execution = resolveGithubCopilotCliExecution(p);
9745
9810
  let resolve;
9746
9811
  const resultPromise = new Promise((r) => {
9747
9812
  resolve = r;
@@ -9750,7 +9815,7 @@ var GithubCopilotCliExecutor = class {
9750
9815
  const settle = (result) => {
9751
9816
  if (settled) return;
9752
9817
  settled = true;
9753
- clearTimeout(timer);
9818
+ if (timer) clearTimeout(timer);
9754
9819
  resolve?.(result);
9755
9820
  };
9756
9821
  if (abortSignal?.aborted) {
@@ -9763,36 +9828,32 @@ var GithubCopilotCliExecutor = class {
9763
9828
  }
9764
9829
  };
9765
9830
  }
9766
- const args = ["copilot", "prompt", "--prompt", p.prompt];
9767
- if (p.autopilot) {
9768
- args.push("--autopilot");
9769
- }
9770
- if (p.allowTools && p.allowTools.length > 0) {
9771
- args.push("--allow-tools", p.allowTools.join(","));
9772
- }
9773
- if (p.model) {
9774
- args.push("--model", p.model);
9775
- }
9776
- if (p.agent) {
9777
- args.push("--agent", p.agent);
9778
- }
9779
- if (p.timeout != null) {
9780
- args.push("--timeout", String(p.timeout));
9781
- }
9782
- const child = child_process.spawn("serviceme", args, {
9783
- cwd: p.workspace,
9784
- stdio: ["ignore", "pipe", "pipe"]
9831
+ writeDiagnostic(
9832
+ `[GithubCopilotCliExecutor] spawn: command=${execution.command}, args=${JSON.stringify(execution.diagnosticArgs)}, promptLen=${execution.promptLen}, cwd=${execution.cwd ?? "(default)"}, platform=${process.platform}, windowsHide=true, pid=${process.pid}
9833
+ `
9834
+ );
9835
+ const child = child_process.spawn(execution.command, execution.args, {
9836
+ cwd: execution.cwd,
9837
+ stdio: ["ignore", "pipe", "pipe"],
9838
+ windowsHide: true
9785
9839
  });
9786
- const timer = setTimeout(() => {
9840
+ if (child.pid) {
9841
+ writeDiagnostic(
9842
+ `[GithubCopilotCliExecutor] spawned child PID=${child.pid}
9843
+ `
9844
+ );
9845
+ }
9846
+ const timeoutMs = execution.timeoutMs;
9847
+ const timer = timeoutMs != null ? setTimeout(() => {
9787
9848
  child.kill("SIGTERM");
9788
9849
  setTimeout(() => {
9789
9850
  if (!child.killed) child.kill("SIGKILL");
9790
9851
  }, 5e3);
9791
9852
  settle({
9792
9853
  status: "timeout",
9793
- error: `Copilot CLI execution timed out after ${timeout / 1e3}s`
9854
+ error: `Copilot CLI execution timed out after ${timeoutMs / 1e3}s`
9794
9855
  });
9795
- }, timeout);
9856
+ }, timeoutMs) : void 0;
9796
9857
  let stdoutBuf = "";
9797
9858
  let stderrBuf = "";
9798
9859
  child.stdout.on("data", (chunk) => {
@@ -9836,17 +9897,19 @@ var GithubCopilotCliExecutor = class {
9836
9897
  };
9837
9898
 
9838
9899
  // ../../packages/serviceme-core/src/scheduled-tasks/executors/HttpRequestExecutor.ts
9839
- var DEFAULT_TIMEOUT2 = 3e4;
9900
+ var DEFAULT_TIMEOUT_MS2 = 3e4;
9840
9901
  var HttpRequestExecutor = class {
9841
9902
  async execute(payload, abortSignal) {
9842
9903
  const p = payload;
9843
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT2;
9904
+ const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS2);
9844
9905
  const ac = new AbortController();
9845
- const timer = setTimeout(() => {
9906
+ let timedOut = false;
9907
+ const timer = timeoutMs != null ? setTimeout(() => {
9908
+ timedOut = true;
9846
9909
  ac.abort();
9847
- }, timeout);
9910
+ }, timeoutMs) : void 0;
9848
9911
  if (abortSignal?.aborted) {
9849
- clearTimeout(timer);
9912
+ if (timer) clearTimeout(timer);
9850
9913
  return { status: "cancelled", error: "Execution aborted" };
9851
9914
  }
9852
9915
  let externalAbort = false;
@@ -9854,7 +9917,7 @@ var HttpRequestExecutor = class {
9854
9917
  "abort",
9855
9918
  () => {
9856
9919
  externalAbort = true;
9857
- clearTimeout(timer);
9920
+ if (timer) clearTimeout(timer);
9858
9921
  ac.abort();
9859
9922
  },
9860
9923
  { once: true }
@@ -9866,7 +9929,7 @@ var HttpRequestExecutor = class {
9866
9929
  body: p.body,
9867
9930
  signal: ac.signal
9868
9931
  });
9869
- clearTimeout(timer);
9932
+ if (timer) clearTimeout(timer);
9870
9933
  const body = await response.text();
9871
9934
  if (response.ok) {
9872
9935
  return {
@@ -9881,14 +9944,17 @@ ${body}`.trim()
9881
9944
  ${body}`.trim()
9882
9945
  };
9883
9946
  } catch (err) {
9884
- clearTimeout(timer);
9947
+ if (timer) clearTimeout(timer);
9885
9948
  if (err instanceof Error && err.name === "AbortError") {
9886
9949
  if (externalAbort) {
9887
9950
  return { status: "cancelled", error: "Execution cancelled" };
9888
9951
  }
9952
+ if (!timedOut || timeoutMs == null) {
9953
+ return { status: "failure", error: err.message };
9954
+ }
9889
9955
  return {
9890
9956
  status: "timeout",
9891
- error: `HTTP request timed out after ${timeout / 1e3}s`
9957
+ error: `HTTP request timed out after ${timeoutMs / 1e3}s`
9892
9958
  };
9893
9959
  }
9894
9960
  const message = err instanceof Error ? err.message : String(err);
@@ -9896,8 +9962,80 @@ ${body}`.trim()
9896
9962
  }
9897
9963
  }
9898
9964
  };
9899
- var DEFAULT_TIMEOUT3 = 6e4;
9900
9965
  var MAX_OUTPUT_BYTES2 = 1024 * 1024;
9966
+ var DEFAULT_TIMEOUT_MS3 = 6e4;
9967
+ var POSIX_SHELL_CANDIDATES = ["bash.exe", "sh.exe"];
9968
+ function resolveShellExecution(script, options2 = {}) {
9969
+ const platform = options2.platform ?? process.platform;
9970
+ const env = options2.env ?? process.env;
9971
+ const fileExists = options2.fileExists ?? fs6__namespace.existsSync;
9972
+ if (platform === "win32") {
9973
+ const posixShell = usesPosixShellSyntax(script) ? findWindowsPosixShell(env, fileExists) : null;
9974
+ if (posixShell) {
9975
+ return {
9976
+ command: posixShell,
9977
+ args: ["-s"],
9978
+ stdinScript: script,
9979
+ outputEncoding: "utf8",
9980
+ shellKind: "posix"
9981
+ };
9982
+ }
9983
+ return {
9984
+ command: env.ComSpec ?? env.COMSPEC ?? "cmd.exe",
9985
+ args: ["/d", "/s", "/c", script],
9986
+ outputEncoding: "utf8",
9987
+ shellKind: "cmd"
9988
+ };
9989
+ }
9990
+ return {
9991
+ command: "sh",
9992
+ args: ["-s"],
9993
+ stdinScript: script,
9994
+ outputEncoding: "utf8",
9995
+ shellKind: "posix"
9996
+ };
9997
+ }
9998
+ function usesPosixShellSyntax(script) {
9999
+ return /\$\([^)]*\)|`[^`]*`/.test(script);
10000
+ }
10001
+ function findWindowsPosixShell(env, fileExists) {
10002
+ const explicitShell = env.SERVICEME_POSIX_SHELL;
10003
+ if (explicitShell && fileExists(explicitShell)) {
10004
+ return explicitShell;
10005
+ }
10006
+ const knownGitBashPaths = [
10007
+ "C:\\Program Files\\Git\\bin\\bash.exe",
10008
+ "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
10009
+ "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
10010
+ "C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
10011
+ ];
10012
+ for (const candidate of knownGitBashPaths) {
10013
+ if (fileExists(candidate)) return candidate;
10014
+ }
10015
+ const pathValue = env.Path ?? env.PATH ?? "";
10016
+ for (const dir of pathValue.split(path5__namespace.win32.delimiter)) {
10017
+ if (!dir) continue;
10018
+ for (const executable of POSIX_SHELL_CANDIDATES) {
10019
+ const candidate = path5__namespace.win32.join(dir, executable);
10020
+ if (fileExists(candidate) && !isWindowsWslLauncher(candidate)) {
10021
+ return candidate;
10022
+ }
10023
+ }
10024
+ }
10025
+ return null;
10026
+ }
10027
+ function isWindowsWslLauncher(candidate) {
10028
+ const normalized = path5__namespace.win32.normalize(candidate).toLowerCase();
10029
+ return normalized.endsWith("\\windows\\system32\\bash.exe") || normalized.endsWith("\\windows\\syswow64\\bash.exe");
10030
+ }
10031
+ function writeDiagnostic2(message) {
10032
+ const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
10033
+ if (logPath) {
10034
+ fs6__namespace.appendFileSync(logPath, message);
10035
+ return;
10036
+ }
10037
+ process.stderr.write(message);
10038
+ }
9901
10039
  var ShellExecutor = class {
9902
10040
  async execute(payload, abortSignal) {
9903
10041
  let output = "";
@@ -9913,7 +10051,7 @@ var ShellExecutor = class {
9913
10051
  }
9914
10052
  executeStreaming(payload, onOutput, abortSignal) {
9915
10053
  const p = payload;
9916
- const timeout = (p.timeout != null ? p.timeout * 1e3 : null) ?? DEFAULT_TIMEOUT3;
10054
+ const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS3);
9917
10055
  let resolve;
9918
10056
  const resultPromise = new Promise((r) => {
9919
10057
  resolve = r;
@@ -9922,7 +10060,7 @@ var ShellExecutor = class {
9922
10060
  const settle = (result) => {
9923
10061
  if (settled) return;
9924
10062
  settled = true;
9925
- clearTimeout(timer);
10063
+ if (timer) clearTimeout(timer);
9926
10064
  resolve?.(result);
9927
10065
  };
9928
10066
  if (abortSignal?.aborted) {
@@ -9935,37 +10073,65 @@ var ShellExecutor = class {
9935
10073
  }
9936
10074
  };
9937
10075
  }
9938
- const child = child_process.spawn("sh", ["-c", p.script], {
10076
+ const shellExecution = resolveShellExecution(p.script);
10077
+ const spawnOpts = {
9939
10078
  cwd: p.cwd,
9940
- stdio: ["ignore", "pipe", "pipe"]
9941
- });
9942
- const timer = setTimeout(() => {
10079
+ stdio: [shellExecution.stdinScript ? "pipe" : "ignore", "pipe", "pipe"],
10080
+ windowsHide: true
10081
+ };
10082
+ writeDiagnostic2(
10083
+ `[ShellExecutor] spawn:
10084
+ platform=${process.platform}
10085
+ shell=${shellExecution.shellKind}
10086
+ command=${shellExecution.command}
10087
+ args=${JSON.stringify(shellExecution.args.filter((a) => a !== p.script))}
10088
+ stdin=${shellExecution.stdinScript ? "true" : "false"}
10089
+ cwd=${p.cwd ?? "(default)"}
10090
+ timeout=${timeoutMs != null ? `${timeoutMs}ms` : "unlimited"}
10091
+ scriptLen=${p.script.length}
10092
+ windowsHide=true
10093
+ daemonPid=${process.pid}
10094
+ `
10095
+ );
10096
+ const child = child_process.spawn(shellExecution.command, shellExecution.args, spawnOpts);
10097
+ if (shellExecution.stdinScript && child.stdin) {
10098
+ child.stdin.end(shellExecution.stdinScript);
10099
+ }
10100
+ if (child.pid) {
10101
+ writeDiagnostic2(`[ShellExecutor] spawned child PID=${child.pid}
10102
+ `);
10103
+ }
10104
+ const timer = timeoutMs != null ? setTimeout(() => {
9943
10105
  child.kill("SIGTERM");
9944
10106
  setTimeout(() => {
9945
10107
  if (!child.killed) child.kill("SIGKILL");
9946
10108
  }, 5e3);
9947
10109
  settle({
9948
10110
  status: "timeout",
9949
- error: `Shell execution timed out after ${timeout / 1e3}s`
10111
+ error: `Shell execution timed out after ${timeoutMs / 1e3}s`
9950
10112
  });
9951
- }, timeout);
10113
+ }, timeoutMs) : void 0;
9952
10114
  let stdoutBuf = "";
9953
10115
  let stderrBuf = "";
9954
- child.stdout.on("data", (chunk) => {
9955
- const data = chunk.toString();
10116
+ child.stdout?.on("data", (chunk) => {
10117
+ const data = chunk.toString(shellExecution.outputEncoding);
9956
10118
  stdoutBuf += data;
9957
10119
  if (stdoutBuf.length > MAX_OUTPUT_BYTES2)
9958
10120
  stdoutBuf = stdoutBuf.slice(-MAX_OUTPUT_BYTES2);
9959
10121
  onOutput("stdout", data);
9960
10122
  });
9961
- child.stderr.on("data", (chunk) => {
9962
- const data = chunk.toString();
10123
+ child.stderr?.on("data", (chunk) => {
10124
+ const data = chunk.toString(shellExecution.outputEncoding);
9963
10125
  stderrBuf += data;
9964
10126
  if (stderrBuf.length > MAX_OUTPUT_BYTES2)
9965
10127
  stderrBuf = stderrBuf.slice(-MAX_OUTPUT_BYTES2);
9966
10128
  onOutput("stderr", data);
9967
10129
  });
9968
10130
  child.on("close", (code) => {
10131
+ writeDiagnostic2(
10132
+ `[ShellExecutor] child PID=${child.pid} exited: code=${code}
10133
+ `
10134
+ );
9969
10135
  if (code === 0) {
9970
10136
  settle({ status: "success", output: stdoutBuf || void 0 });
9971
10137
  } else {
@@ -10009,8 +10175,59 @@ function getExecutor(taskType) {
10009
10175
  }
10010
10176
  return executor;
10011
10177
  }
10178
+ function isRecord3(value) {
10179
+ return value !== null && typeof value === "object" && !Array.isArray(value);
10180
+ }
10181
+ function requireNonEmptyString(payload, field, taskType) {
10182
+ if (!isRecord3(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
10183
+ throw createServicemeError(
10184
+ "invalid_payload",
10185
+ `${taskType} payload ${field} is required`
10186
+ );
10187
+ }
10188
+ }
10189
+ function validateTaskPayload(taskType, payload) {
10190
+ switch (taskType) {
10191
+ case "command":
10192
+ requireNonEmptyString(payload, "command", taskType);
10193
+ return;
10194
+ case "shell":
10195
+ requireNonEmptyString(payload, "script", taskType);
10196
+ return;
10197
+ case "http_request":
10198
+ requireNonEmptyString(payload, "url", taskType);
10199
+ requireNonEmptyString(payload, "method", taskType);
10200
+ return;
10201
+ case "github_copilot_cli":
10202
+ requireNonEmptyString(payload, "prompt", taskType);
10203
+ return;
10204
+ }
10205
+ }
10012
10206
 
10013
10207
  // ../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts
10208
+ function hasNonEmptyString(value) {
10209
+ return typeof value === "string" && value.trim().length > 0;
10210
+ }
10211
+ function resolveTaskExecutionPayload(taskType, payload, workspacePath) {
10212
+ if (!hasNonEmptyString(workspacePath)) {
10213
+ return payload;
10214
+ }
10215
+ if (taskType === "shell") {
10216
+ const shellPayload = payload;
10217
+ if (hasNonEmptyString(shellPayload.cwd)) {
10218
+ return shellPayload;
10219
+ }
10220
+ return { ...shellPayload, cwd: workspacePath };
10221
+ }
10222
+ if (taskType === "github_copilot_cli") {
10223
+ const copilotPayload = payload;
10224
+ if (hasNonEmptyString(copilotPayload.workspace)) {
10225
+ return copilotPayload;
10226
+ }
10227
+ return { ...copilotPayload, workspace: workspacePath };
10228
+ }
10229
+ return payload;
10230
+ }
10014
10231
  var TaskExecutionEngine = class {
10015
10232
  constructor(getExecutor2) {
10016
10233
  this.getExecutor = getExecutor2;
@@ -10031,7 +10248,6 @@ var TaskExecutionEngine = class {
10031
10248
  );
10032
10249
  }
10033
10250
  }
10034
- const executor = this.getExecutor(snapshot.type);
10035
10251
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
10036
10252
  if (!this.taskExecutions.has(snapshot.taskId)) {
10037
10253
  this.taskExecutions.set(snapshot.taskId, /* @__PURE__ */ new Set());
@@ -10051,10 +10267,17 @@ var TaskExecutionEngine = class {
10051
10267
  startedAt
10052
10268
  });
10053
10269
  try {
10270
+ const executionPayload = resolveTaskExecutionPayload(
10271
+ snapshot.type,
10272
+ snapshot.payload,
10273
+ snapshot.workspacePath
10274
+ );
10275
+ validateTaskPayload(snapshot.type, executionPayload);
10276
+ const executor = this.getExecutor(snapshot.type);
10054
10277
  let result;
10055
10278
  if (isStreamingTaskExecutor(executor)) {
10056
10279
  const handle = executor.executeStreaming(
10057
- snapshot.payload,
10280
+ executionPayload,
10058
10281
  (stream, data) => {
10059
10282
  this.listener?.onOutput({
10060
10283
  executionId: snapshot.executionId,
@@ -10070,7 +10293,7 @@ var TaskExecutionEngine = class {
10070
10293
  };
10071
10294
  result = await handle.result;
10072
10295
  } else {
10073
- result = await executor.execute(snapshot.payload, ac.signal);
10296
+ result = await executor.execute(executionPayload, ac.signal);
10074
10297
  }
10075
10298
  const log = {
10076
10299
  id: snapshot.executionId,