@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.
- package/dist/bridgeServer.js +306 -83
- package/dist/cli.js +715 -327
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
var child_process = require('child_process');
|
|
5
5
|
var fs2 = require('fs/promises');
|
|
6
6
|
var path = require('path');
|
|
7
|
-
var
|
|
7
|
+
var fs8 = require('fs');
|
|
8
8
|
var crypto = require('crypto');
|
|
9
|
+
var os = require('os');
|
|
9
10
|
var readline = require('readline');
|
|
10
11
|
|
|
11
12
|
function _interopNamespace(e) {
|
|
@@ -28,7 +29,8 @@ function _interopNamespace(e) {
|
|
|
28
29
|
|
|
29
30
|
var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
|
|
30
31
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
31
|
-
var
|
|
32
|
+
var fs8__namespace = /*#__PURE__*/_interopNamespace(fs8);
|
|
33
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
32
34
|
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
33
35
|
|
|
34
36
|
var __create = Object.create;
|
|
@@ -157,6 +159,7 @@ var init_env = __esm({
|
|
|
157
159
|
"pnpm",
|
|
158
160
|
"nvm",
|
|
159
161
|
"nrm",
|
|
162
|
+
"rtk",
|
|
160
163
|
"dotnet",
|
|
161
164
|
"nuget"
|
|
162
165
|
];
|
|
@@ -360,7 +363,8 @@ async function runCommand(command, options2 = {}) {
|
|
|
360
363
|
cwd: options2.cwd,
|
|
361
364
|
env: options2.env,
|
|
362
365
|
shell: options2.shell,
|
|
363
|
-
stdio: "pipe"
|
|
366
|
+
stdio: "pipe",
|
|
367
|
+
windowsHide: true
|
|
364
368
|
});
|
|
365
369
|
let stdout = "";
|
|
366
370
|
let stderr = "";
|
|
@@ -582,13 +586,19 @@ var init_copilot2 = __esm({
|
|
|
582
586
|
});
|
|
583
587
|
|
|
584
588
|
// ../../packages/serviceme-core/src/env/environmentInspector.ts
|
|
585
|
-
var TOOL_CHECK_TIMEOUT_MS, ERROR_CODE_NOT_FOUND, EnvironmentInspector;
|
|
589
|
+
var DEFAULT_TOOL_CHECK_TIMEOUT_MS, TOOL_CHECK_TIMEOUT_MS, ERROR_CODE_NOT_FOUND, ERROR_CODE_TIMEOUT, EnvironmentInspector;
|
|
586
590
|
var init_environmentInspector = __esm({
|
|
587
591
|
"../../packages/serviceme-core/src/env/environmentInspector.ts"() {
|
|
588
592
|
init_src();
|
|
589
593
|
init_runCommand();
|
|
590
|
-
|
|
594
|
+
DEFAULT_TOOL_CHECK_TIMEOUT_MS = 5e3;
|
|
595
|
+
TOOL_CHECK_TIMEOUT_MS = {
|
|
596
|
+
nuget: 12e3,
|
|
597
|
+
nvm: 8e3,
|
|
598
|
+
dotnet: 8e3
|
|
599
|
+
};
|
|
591
600
|
ERROR_CODE_NOT_FOUND = 127;
|
|
601
|
+
ERROR_CODE_TIMEOUT = "ETIMEDOUT";
|
|
592
602
|
EnvironmentInspector = class {
|
|
593
603
|
async checkEnvironment() {
|
|
594
604
|
const results = await Promise.all(
|
|
@@ -625,19 +635,18 @@ var init_environmentInspector = __esm({
|
|
|
625
635
|
const isWindows = process.platform === "win32";
|
|
626
636
|
const result = await runCommand(isWindows ? "where" : "which", {
|
|
627
637
|
args: [toolName],
|
|
628
|
-
timeoutMs:
|
|
638
|
+
timeoutMs: this.getToolTimeout(toolName)
|
|
629
639
|
});
|
|
630
|
-
return result.stdout.trim().
|
|
640
|
+
return result.stdout.split(/\r?\n/).map((line2) => line2.trim()).find((line2) => line2.length > 0);
|
|
631
641
|
} catch {
|
|
632
642
|
return void 0;
|
|
633
643
|
}
|
|
634
644
|
}
|
|
635
645
|
async getToolVersion(toolName) {
|
|
636
|
-
const
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
timeoutMs: TOOL_CHECK_TIMEOUT_MS
|
|
646
|
+
const invocation = this.getVersionInvocation(toolName);
|
|
647
|
+
const result = await runCommand(invocation.command, {
|
|
648
|
+
args: invocation.args,
|
|
649
|
+
timeoutMs: this.getToolTimeout(toolName)
|
|
641
650
|
});
|
|
642
651
|
return this.parseVersion(toolName, result.stdout || result.stderr);
|
|
643
652
|
}
|
|
@@ -646,7 +655,7 @@ var init_environmentInspector = __esm({
|
|
|
646
655
|
try {
|
|
647
656
|
const result = await runCommand("cmd.exe", {
|
|
648
657
|
args: ["/c", "nvm version"],
|
|
649
|
-
timeoutMs:
|
|
658
|
+
timeoutMs: this.getToolTimeout("nvm")
|
|
650
659
|
});
|
|
651
660
|
return {
|
|
652
661
|
installed: true,
|
|
@@ -666,7 +675,7 @@ var init_environmentInspector = __esm({
|
|
|
666
675
|
"-lc",
|
|
667
676
|
'export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; nvm --version'
|
|
668
677
|
],
|
|
669
|
-
timeoutMs:
|
|
678
|
+
timeoutMs: this.getToolTimeout("nvm")
|
|
670
679
|
});
|
|
671
680
|
return {
|
|
672
681
|
installed: true,
|
|
@@ -691,7 +700,7 @@ var init_environmentInspector = __esm({
|
|
|
691
700
|
try {
|
|
692
701
|
const result = await runCommand("dotnet", {
|
|
693
702
|
args: ["nuget", "list", "source"],
|
|
694
|
-
timeoutMs:
|
|
703
|
+
timeoutMs: this.getToolTimeout("nuget")
|
|
695
704
|
});
|
|
696
705
|
const privateSourceUrl = "http://192.168.20.209:10010/nuget";
|
|
697
706
|
if (result.stdout.includes(privateSourceUrl)) {
|
|
@@ -709,17 +718,28 @@ var init_environmentInspector = __esm({
|
|
|
709
718
|
return this.handleToolCheckError(error);
|
|
710
719
|
}
|
|
711
720
|
}
|
|
712
|
-
|
|
721
|
+
getVersionInvocation(toolName) {
|
|
722
|
+
const isWindows = process.platform === "win32";
|
|
723
|
+
if (isWindows && ["npm", "pnpm", "nrm"].includes(toolName)) {
|
|
724
|
+
return {
|
|
725
|
+
command: "cmd.exe",
|
|
726
|
+
args: ["/d", "/s", "/c", `${toolName} --version`]
|
|
727
|
+
};
|
|
728
|
+
}
|
|
713
729
|
const commands = {
|
|
714
|
-
git: "git --version",
|
|
715
|
-
node: "node --version",
|
|
716
|
-
npm: "npm --version",
|
|
717
|
-
pnpm: "pnpm --version",
|
|
718
|
-
nvm: "nvm --version",
|
|
719
|
-
nrm: "nrm --version",
|
|
720
|
-
|
|
730
|
+
git: { command: "git", args: ["--version"] },
|
|
731
|
+
node: { command: "node", args: ["--version"] },
|
|
732
|
+
npm: { command: "npm", args: ["--version"] },
|
|
733
|
+
pnpm: { command: "pnpm", args: ["--version"] },
|
|
734
|
+
nvm: { command: "nvm", args: ["--version"] },
|
|
735
|
+
nrm: { command: "nrm", args: ["--version"] },
|
|
736
|
+
rtk: { command: "rtk", args: ["--version"] },
|
|
737
|
+
dotnet: { command: "dotnet", args: ["--version"] }
|
|
721
738
|
};
|
|
722
|
-
return commands[toolName] ||
|
|
739
|
+
return commands[toolName] || { command: toolName, args: ["--version"] };
|
|
740
|
+
}
|
|
741
|
+
getToolTimeout(toolName) {
|
|
742
|
+
return TOOL_CHECK_TIMEOUT_MS[toolName] ?? DEFAULT_TOOL_CHECK_TIMEOUT_MS;
|
|
723
743
|
}
|
|
724
744
|
parseVersion(toolName, output) {
|
|
725
745
|
const cleaned = output.trim();
|
|
@@ -746,10 +766,11 @@ var init_environmentInspector = __esm({
|
|
|
746
766
|
const execError = error;
|
|
747
767
|
const message = execError.message || String(error);
|
|
748
768
|
const code = execError.code;
|
|
749
|
-
const isNotFound = message.includes("command not found") || message.includes("not recognized") || code === ERROR_CODE_NOT_FOUND;
|
|
769
|
+
const isNotFound = message.includes("command not found") || message.includes("not recognized") || message.includes("ENOENT") || code === "ENOENT" || code === ERROR_CODE_NOT_FOUND;
|
|
770
|
+
const isTimeout = code === ERROR_CODE_TIMEOUT || message.toLowerCase().includes("timed out");
|
|
750
771
|
return {
|
|
751
772
|
installed: false,
|
|
752
|
-
error: isNotFound ? "Not installed" : message
|
|
773
|
+
error: isNotFound ? "Not installed" : isTimeout ? "Check timed out" : message
|
|
753
774
|
};
|
|
754
775
|
}
|
|
755
776
|
};
|
|
@@ -1126,9 +1147,9 @@ var require_esprima = __commonJS({
|
|
|
1126
1147
|
});
|
|
1127
1148
|
};
|
|
1128
1149
|
CommentHandler2.prototype.visitComment = function(node, metadata) {
|
|
1129
|
-
var
|
|
1150
|
+
var type2 = node.type[0] === "L" ? "Line" : "Block";
|
|
1130
1151
|
var comment = {
|
|
1131
|
-
type,
|
|
1152
|
+
type: type2,
|
|
1132
1153
|
value: node.value
|
|
1133
1154
|
};
|
|
1134
1155
|
if (node.range) {
|
|
@@ -1141,7 +1162,7 @@ var require_esprima = __commonJS({
|
|
|
1141
1162
|
if (this.attach) {
|
|
1142
1163
|
var entry = {
|
|
1143
1164
|
comment: {
|
|
1144
|
-
type,
|
|
1165
|
+
type: type2,
|
|
1145
1166
|
value: node.value,
|
|
1146
1167
|
range: [metadata.start.offset, metadata.end.offset]
|
|
1147
1168
|
},
|
|
@@ -1150,7 +1171,7 @@ var require_esprima = __commonJS({
|
|
|
1150
1171
|
if (node.loc) {
|
|
1151
1172
|
entry.comment.loc = node.loc;
|
|
1152
1173
|
}
|
|
1153
|
-
node.type =
|
|
1174
|
+
node.type = type2;
|
|
1154
1175
|
this.leading.push(entry);
|
|
1155
1176
|
this.trailing.push(entry);
|
|
1156
1177
|
}
|
|
@@ -5965,28 +5986,28 @@ var require_esprima = __commonJS({
|
|
|
5965
5986
|
};
|
|
5966
5987
|
};
|
|
5967
5988
|
Scanner2.prototype.scanIdentifier = function() {
|
|
5968
|
-
var
|
|
5989
|
+
var type2;
|
|
5969
5990
|
var start = this.index;
|
|
5970
5991
|
var id = this.source.charCodeAt(start) === 92 ? this.getComplexIdentifier() : this.getIdentifier();
|
|
5971
5992
|
if (id.length === 1) {
|
|
5972
|
-
|
|
5993
|
+
type2 = 3;
|
|
5973
5994
|
} else if (this.isKeyword(id)) {
|
|
5974
|
-
|
|
5995
|
+
type2 = 4;
|
|
5975
5996
|
} else if (id === "null") {
|
|
5976
|
-
|
|
5997
|
+
type2 = 5;
|
|
5977
5998
|
} else if (id === "true" || id === "false") {
|
|
5978
|
-
|
|
5999
|
+
type2 = 1;
|
|
5979
6000
|
} else {
|
|
5980
|
-
|
|
6001
|
+
type2 = 3;
|
|
5981
6002
|
}
|
|
5982
|
-
if (
|
|
6003
|
+
if (type2 !== 3 && start + id.length !== this.index) {
|
|
5983
6004
|
var restore = this.index;
|
|
5984
6005
|
this.index = start;
|
|
5985
6006
|
this.tolerateUnexpectedToken(messages_1.Messages.InvalidEscapedReservedWord);
|
|
5986
6007
|
this.index = restore;
|
|
5987
6008
|
}
|
|
5988
6009
|
return {
|
|
5989
|
-
type,
|
|
6010
|
+
type: type2,
|
|
5990
6011
|
value: id,
|
|
5991
6012
|
lineNumber: this.lineNumber,
|
|
5992
6013
|
lineStart: this.lineStart,
|
|
@@ -8437,13 +8458,13 @@ var require_parse = __commonJS({
|
|
|
8437
8458
|
last = current;
|
|
8438
8459
|
current = new_token;
|
|
8439
8460
|
};
|
|
8440
|
-
var
|
|
8461
|
+
var type2 = () => {
|
|
8441
8462
|
if (!current) {
|
|
8442
8463
|
unexpected_end();
|
|
8443
8464
|
}
|
|
8444
8465
|
return current.type === "Punctuator" ? current.value : current.type;
|
|
8445
8466
|
};
|
|
8446
|
-
var is = (t) =>
|
|
8467
|
+
var is = (t) => type2() === t;
|
|
8447
8468
|
var expect = (a) => {
|
|
8448
8469
|
if (!is(a)) {
|
|
8449
8470
|
unexpected();
|
|
@@ -8598,7 +8619,7 @@ var require_parse = __commonJS({
|
|
|
8598
8619
|
return array;
|
|
8599
8620
|
};
|
|
8600
8621
|
function walk() {
|
|
8601
|
-
let tt =
|
|
8622
|
+
let tt = type2();
|
|
8602
8623
|
if (tt === CURLY_BRACKET_OPEN) {
|
|
8603
8624
|
next();
|
|
8604
8625
|
return {
|
|
@@ -8614,7 +8635,7 @@ var require_parse = __commonJS({
|
|
|
8614
8635
|
let negative = EMPTY;
|
|
8615
8636
|
if (tt === MINUS) {
|
|
8616
8637
|
next();
|
|
8617
|
-
tt =
|
|
8638
|
+
tt = type2();
|
|
8618
8639
|
negative = MINUS;
|
|
8619
8640
|
}
|
|
8620
8641
|
let v;
|
|
@@ -8740,11 +8761,11 @@ var require_stringify = __commonJS({
|
|
|
8740
8761
|
let is_line_comment = false;
|
|
8741
8762
|
const str = comments.reduce((prev, {
|
|
8742
8763
|
inline,
|
|
8743
|
-
type,
|
|
8764
|
+
type: type2,
|
|
8744
8765
|
value
|
|
8745
8766
|
}) => {
|
|
8746
8767
|
const delimiter = inline ? SPACE : LF + deeper_gap;
|
|
8747
|
-
is_line_comment =
|
|
8768
|
+
is_line_comment = type2 === "LineComment";
|
|
8748
8769
|
return prev + delimiter + comment_stringify(value, is_line_comment);
|
|
8749
8770
|
}, EMPTY);
|
|
8750
8771
|
return display_block || is_line_comment ? str + LF + deeper_gap : str;
|
|
@@ -8984,9 +9005,9 @@ function read() {
|
|
|
8984
9005
|
}
|
|
8985
9006
|
return c2;
|
|
8986
9007
|
}
|
|
8987
|
-
function newToken(
|
|
9008
|
+
function newToken(type2, value) {
|
|
8988
9009
|
return {
|
|
8989
|
-
type,
|
|
9010
|
+
type: type2,
|
|
8990
9011
|
value,
|
|
8991
9012
|
line,
|
|
8992
9013
|
column
|
|
@@ -10192,7 +10213,7 @@ var require_pend = __commonJS({
|
|
|
10192
10213
|
// ../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/fd-slicer.js
|
|
10193
10214
|
var require_fd_slicer = __commonJS({
|
|
10194
10215
|
"../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/fd-slicer.js"(exports$1) {
|
|
10195
|
-
var
|
|
10216
|
+
var fs13 = __require("fs");
|
|
10196
10217
|
var util2 = __require("util");
|
|
10197
10218
|
var stream = __require("stream");
|
|
10198
10219
|
var Readable = stream.Readable;
|
|
@@ -10217,7 +10238,7 @@ var require_fd_slicer = __commonJS({
|
|
|
10217
10238
|
FdSlicer.prototype.read = function(buffer2, offset, length, position, callback) {
|
|
10218
10239
|
var self = this;
|
|
10219
10240
|
self.pend.go(function(cb) {
|
|
10220
|
-
|
|
10241
|
+
fs13.read(self.fd, buffer2, offset, length, position, function(err, bytesRead, buffer3) {
|
|
10221
10242
|
cb();
|
|
10222
10243
|
callback(err, bytesRead, buffer3);
|
|
10223
10244
|
});
|
|
@@ -10226,7 +10247,7 @@ var require_fd_slicer = __commonJS({
|
|
|
10226
10247
|
FdSlicer.prototype.write = function(buffer2, offset, length, position, callback) {
|
|
10227
10248
|
var self = this;
|
|
10228
10249
|
self.pend.go(function(cb) {
|
|
10229
|
-
|
|
10250
|
+
fs13.write(self.fd, buffer2, offset, length, position, function(err, written, buffer3) {
|
|
10230
10251
|
cb();
|
|
10231
10252
|
callback(err, written, buffer3);
|
|
10232
10253
|
});
|
|
@@ -10247,7 +10268,7 @@ var require_fd_slicer = __commonJS({
|
|
|
10247
10268
|
if (self.refCount > 0) return;
|
|
10248
10269
|
if (self.refCount < 0) throw new Error("invalid unref");
|
|
10249
10270
|
if (self.autoClose) {
|
|
10250
|
-
|
|
10271
|
+
fs13.close(self.fd, onCloseDone);
|
|
10251
10272
|
}
|
|
10252
10273
|
function onCloseDone(err) {
|
|
10253
10274
|
if (err) {
|
|
@@ -10284,7 +10305,7 @@ var require_fd_slicer = __commonJS({
|
|
|
10284
10305
|
self.context.pend.go(function(cb) {
|
|
10285
10306
|
if (self.destroyed) return cb();
|
|
10286
10307
|
var buffer2 = Buffer.allocUnsafe(toRead);
|
|
10287
|
-
|
|
10308
|
+
fs13.read(self.context.fd, buffer2, 0, toRead, self.pos, function(err, bytesRead) {
|
|
10288
10309
|
if (err) {
|
|
10289
10310
|
self.destroy(err);
|
|
10290
10311
|
} else if (bytesRead === 0) {
|
|
@@ -10331,7 +10352,7 @@ var require_fd_slicer = __commonJS({
|
|
|
10331
10352
|
}
|
|
10332
10353
|
self.context.pend.go(function(cb) {
|
|
10333
10354
|
if (self.destroyed) return cb();
|
|
10334
|
-
|
|
10355
|
+
fs13.write(self.context.fd, buffer2, 0, buffer2.length, self.pos, function(err2, bytes) {
|
|
10335
10356
|
if (err2) {
|
|
10336
10357
|
self.destroy();
|
|
10337
10358
|
cb();
|
|
@@ -10769,7 +10790,7 @@ var require_buffer_crc32 = __commonJS({
|
|
|
10769
10790
|
// ../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/index.js
|
|
10770
10791
|
var require_yauzl = __commonJS({
|
|
10771
10792
|
"../../node_modules/.pnpm/yauzl@3.2.0/node_modules/yauzl/index.js"(exports$1) {
|
|
10772
|
-
var
|
|
10793
|
+
var fs13 = __require("fs");
|
|
10773
10794
|
var zlib = __require("zlib");
|
|
10774
10795
|
var fd_slicer = require_fd_slicer();
|
|
10775
10796
|
var crc32 = require_buffer_crc32();
|
|
@@ -10790,7 +10811,7 @@ var require_yauzl = __commonJS({
|
|
|
10790
10811
|
exports$1.Entry = Entry;
|
|
10791
10812
|
exports$1.LocalFileHeader = LocalFileHeader;
|
|
10792
10813
|
exports$1.RandomAccessReader = RandomAccessReader;
|
|
10793
|
-
function open2(
|
|
10814
|
+
function open2(path9, options2, callback) {
|
|
10794
10815
|
if (typeof options2 === "function") {
|
|
10795
10816
|
callback = options2;
|
|
10796
10817
|
options2 = null;
|
|
@@ -10802,10 +10823,10 @@ var require_yauzl = __commonJS({
|
|
|
10802
10823
|
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
10803
10824
|
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
10804
10825
|
if (callback == null) callback = defaultCallback;
|
|
10805
|
-
|
|
10826
|
+
fs13.open(path9, "r", function(err, fd) {
|
|
10806
10827
|
if (err) return callback(err);
|
|
10807
10828
|
fromFd(fd, options2, function(err2, zipfile) {
|
|
10808
|
-
if (err2)
|
|
10829
|
+
if (err2) fs13.close(fd, defaultCallback);
|
|
10809
10830
|
callback(err2, zipfile);
|
|
10810
10831
|
});
|
|
10811
10832
|
});
|
|
@@ -10822,7 +10843,7 @@ var require_yauzl = __commonJS({
|
|
|
10822
10843
|
if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
|
|
10823
10844
|
if (options2.strictFileNames == null) options2.strictFileNames = false;
|
|
10824
10845
|
if (callback == null) callback = defaultCallback;
|
|
10825
|
-
|
|
10846
|
+
fs13.fstat(fd, function(err, stats) {
|
|
10826
10847
|
if (err) return callback(err);
|
|
10827
10848
|
var reader = fd_slicer.createFromFd(fd, { autoClose: true });
|
|
10828
10849
|
fromRandomAccessReader(reader, stats.size, options2, callback);
|
|
@@ -11534,7 +11555,7 @@ var init_fileUtils = __esm({
|
|
|
11534
11555
|
return reject(
|
|
11535
11556
|
new Error("Failed to open zip entry stream.")
|
|
11536
11557
|
);
|
|
11537
|
-
const writeStream =
|
|
11558
|
+
const writeStream = fs8.createWriteStream(outputPath);
|
|
11538
11559
|
readStream.on("error", reject);
|
|
11539
11560
|
writeStream.on("error", reject);
|
|
11540
11561
|
writeStream.on("close", () => {
|
|
@@ -11608,7 +11629,7 @@ var init_fileUtils = __esm({
|
|
|
11608
11629
|
const destFile = path.join(destDir, file);
|
|
11609
11630
|
if (!overwrite) {
|
|
11610
11631
|
try {
|
|
11611
|
-
await fs2.access(destFile,
|
|
11632
|
+
await fs2.access(destFile, fs8.constants.F_OK);
|
|
11612
11633
|
await fs2.rm(sourceFile, { recursive: true, force: true });
|
|
11613
11634
|
continue;
|
|
11614
11635
|
} catch {
|
|
@@ -11819,8 +11840,8 @@ var init_DaemonLogger = __esm({
|
|
|
11819
11840
|
constructor(workspacePath) {
|
|
11820
11841
|
this.logPath = path__namespace.join(workspacePath, CONFIG_DIR, LOG_FILE);
|
|
11821
11842
|
const dir = path__namespace.dirname(this.logPath);
|
|
11822
|
-
if (!
|
|
11823
|
-
|
|
11843
|
+
if (!fs8__namespace.existsSync(dir)) {
|
|
11844
|
+
fs8__namespace.mkdirSync(dir, { recursive: true });
|
|
11824
11845
|
}
|
|
11825
11846
|
}
|
|
11826
11847
|
getLogPath() {
|
|
@@ -11831,16 +11852,16 @@ var init_DaemonLogger = __esm({
|
|
|
11831
11852
|
const line2 = `[${ts}] [${level.toUpperCase()}] ${message}
|
|
11832
11853
|
`;
|
|
11833
11854
|
this.rotateIfNeeded();
|
|
11834
|
-
|
|
11855
|
+
fs8__namespace.appendFileSync(this.logPath, line2, "utf-8");
|
|
11835
11856
|
}
|
|
11836
11857
|
rotateIfNeeded() {
|
|
11837
11858
|
try {
|
|
11838
|
-
const stats =
|
|
11859
|
+
const stats = fs8__namespace.statSync(this.logPath);
|
|
11839
11860
|
if (stats.size > MAX_LOG_SIZE) {
|
|
11840
|
-
const content =
|
|
11861
|
+
const content = fs8__namespace.readFileSync(this.logPath, "utf-8");
|
|
11841
11862
|
const halfIdx = content.indexOf("\n", Math.floor(content.length / 2));
|
|
11842
11863
|
if (halfIdx > 0) {
|
|
11843
|
-
|
|
11864
|
+
fs8__namespace.writeFileSync(this.logPath, content.slice(halfIdx + 1), "utf-8");
|
|
11844
11865
|
}
|
|
11845
11866
|
}
|
|
11846
11867
|
} catch {
|
|
@@ -11863,20 +11884,20 @@ var init_PidManager = __esm({
|
|
|
11863
11884
|
}
|
|
11864
11885
|
writePid(pid) {
|
|
11865
11886
|
const dir = path__namespace.dirname(this.pidPath);
|
|
11866
|
-
if (!
|
|
11867
|
-
|
|
11887
|
+
if (!fs8__namespace.existsSync(dir)) {
|
|
11888
|
+
fs8__namespace.mkdirSync(dir, { recursive: true });
|
|
11868
11889
|
}
|
|
11869
|
-
|
|
11890
|
+
fs8__namespace.writeFileSync(this.pidPath, String(pid), "utf-8");
|
|
11870
11891
|
}
|
|
11871
11892
|
readPid() {
|
|
11872
|
-
if (!
|
|
11873
|
-
const raw =
|
|
11893
|
+
if (!fs8__namespace.existsSync(this.pidPath)) return null;
|
|
11894
|
+
const raw = fs8__namespace.readFileSync(this.pidPath, "utf-8").trim();
|
|
11874
11895
|
const pid = Number.parseInt(raw, 10);
|
|
11875
11896
|
return Number.isNaN(pid) ? null : pid;
|
|
11876
11897
|
}
|
|
11877
11898
|
removePid() {
|
|
11878
|
-
if (
|
|
11879
|
-
|
|
11899
|
+
if (fs8__namespace.existsSync(this.pidPath)) {
|
|
11900
|
+
fs8__namespace.unlinkSync(this.pidPath);
|
|
11880
11901
|
}
|
|
11881
11902
|
}
|
|
11882
11903
|
isProcessRunning(pid) {
|
|
@@ -11897,12 +11918,76 @@ var init_PidManager = __esm({
|
|
|
11897
11918
|
};
|
|
11898
11919
|
}
|
|
11899
11920
|
});
|
|
11900
|
-
|
|
11921
|
+
|
|
11922
|
+
// ../../packages/serviceme-core/src/scheduled-tasks/executors/timeout.ts
|
|
11923
|
+
function resolveConfiguredTimeoutMs(timeoutSeconds, defaultTimeoutMs) {
|
|
11924
|
+
if (timeoutSeconds === 0) {
|
|
11925
|
+
return void 0;
|
|
11926
|
+
}
|
|
11927
|
+
if (typeof timeoutSeconds !== "number" || !Number.isFinite(timeoutSeconds) || timeoutSeconds < 0) {
|
|
11928
|
+
return defaultTimeoutMs;
|
|
11929
|
+
}
|
|
11930
|
+
return timeoutSeconds * 1e3;
|
|
11931
|
+
}
|
|
11932
|
+
var init_timeout = __esm({
|
|
11933
|
+
"../../packages/serviceme-core/src/scheduled-tasks/executors/timeout.ts"() {
|
|
11934
|
+
}
|
|
11935
|
+
});
|
|
11936
|
+
function redactArgs(args) {
|
|
11937
|
+
const redacted = [];
|
|
11938
|
+
let redactNext = false;
|
|
11939
|
+
for (const arg of args) {
|
|
11940
|
+
if (redactNext) {
|
|
11941
|
+
redacted.push("<redacted>");
|
|
11942
|
+
redactNext = false;
|
|
11943
|
+
continue;
|
|
11944
|
+
}
|
|
11945
|
+
redacted.push(arg);
|
|
11946
|
+
if (arg === "--prompt") {
|
|
11947
|
+
redactNext = true;
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
return redacted;
|
|
11951
|
+
}
|
|
11952
|
+
function writeDiagnostic(message) {
|
|
11953
|
+
const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
|
|
11954
|
+
if (logPath) {
|
|
11955
|
+
fs8__namespace.appendFileSync(logPath, message);
|
|
11956
|
+
return;
|
|
11957
|
+
}
|
|
11958
|
+
process.stderr.write(message);
|
|
11959
|
+
}
|
|
11960
|
+
function resolveGithubCopilotCliExecution(payload) {
|
|
11961
|
+
const args = ["copilot", "prompt", "--prompt", payload.prompt];
|
|
11962
|
+
if (payload.autopilot) {
|
|
11963
|
+
args.push("--autopilot");
|
|
11964
|
+
}
|
|
11965
|
+
if (payload.allowTools && payload.allowTools.length > 0) {
|
|
11966
|
+
args.push("--allow-tools", payload.allowTools.join(","));
|
|
11967
|
+
}
|
|
11968
|
+
if (payload.model) {
|
|
11969
|
+
args.push("--model", payload.model);
|
|
11970
|
+
}
|
|
11971
|
+
if (payload.agent) {
|
|
11972
|
+
args.push("--agent", payload.agent);
|
|
11973
|
+
}
|
|
11974
|
+
args.push("--timeout", String(payload.timeout ?? 0));
|
|
11975
|
+
return {
|
|
11976
|
+
command: "serviceme",
|
|
11977
|
+
args,
|
|
11978
|
+
cwd: payload.workspace,
|
|
11979
|
+
timeoutMs: resolveConfiguredTimeoutMs(payload.timeout, DEFAULT_TIMEOUT_MS2),
|
|
11980
|
+
diagnosticArgs: redactArgs(args),
|
|
11981
|
+
promptLen: payload.prompt.length
|
|
11982
|
+
};
|
|
11983
|
+
}
|
|
11984
|
+
var MAX_OUTPUT_BYTES, DEFAULT_TIMEOUT_MS2, GithubCopilotCliExecutor;
|
|
11901
11985
|
var init_GithubCopilotCliExecutor = __esm({
|
|
11902
11986
|
"../../packages/serviceme-core/src/scheduled-tasks/executors/GithubCopilotCliExecutor.ts"() {
|
|
11903
11987
|
init_doctor();
|
|
11904
|
-
|
|
11988
|
+
init_timeout();
|
|
11905
11989
|
MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
11990
|
+
DEFAULT_TIMEOUT_MS2 = 3e5;
|
|
11906
11991
|
GithubCopilotCliExecutor = class {
|
|
11907
11992
|
async execute(payload, abortSignal) {
|
|
11908
11993
|
const authenticated = await isCopilotAuthenticated();
|
|
@@ -11925,7 +12010,7 @@ var init_GithubCopilotCliExecutor = __esm({
|
|
|
11925
12010
|
}
|
|
11926
12011
|
executeStreaming(payload, onOutput, abortSignal) {
|
|
11927
12012
|
const p = payload;
|
|
11928
|
-
const
|
|
12013
|
+
const execution = resolveGithubCopilotCliExecution(p);
|
|
11929
12014
|
let resolve;
|
|
11930
12015
|
const resultPromise = new Promise((r) => {
|
|
11931
12016
|
resolve = r;
|
|
@@ -11934,7 +12019,7 @@ var init_GithubCopilotCliExecutor = __esm({
|
|
|
11934
12019
|
const settle = (result) => {
|
|
11935
12020
|
if (settled) return;
|
|
11936
12021
|
settled = true;
|
|
11937
|
-
clearTimeout(timer);
|
|
12022
|
+
if (timer) clearTimeout(timer);
|
|
11938
12023
|
resolve?.(result);
|
|
11939
12024
|
};
|
|
11940
12025
|
if (abortSignal?.aborted) {
|
|
@@ -11947,36 +12032,32 @@ var init_GithubCopilotCliExecutor = __esm({
|
|
|
11947
12032
|
}
|
|
11948
12033
|
};
|
|
11949
12034
|
}
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
args.push("--model", p.model);
|
|
11959
|
-
}
|
|
11960
|
-
if (p.agent) {
|
|
11961
|
-
args.push("--agent", p.agent);
|
|
11962
|
-
}
|
|
11963
|
-
if (p.timeout != null) {
|
|
11964
|
-
args.push("--timeout", String(p.timeout));
|
|
11965
|
-
}
|
|
11966
|
-
const child = child_process.spawn("serviceme", args, {
|
|
11967
|
-
cwd: p.workspace,
|
|
11968
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
12035
|
+
writeDiagnostic(
|
|
12036
|
+
`[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}
|
|
12037
|
+
`
|
|
12038
|
+
);
|
|
12039
|
+
const child = child_process.spawn(execution.command, execution.args, {
|
|
12040
|
+
cwd: execution.cwd,
|
|
12041
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
12042
|
+
windowsHide: true
|
|
11969
12043
|
});
|
|
11970
|
-
|
|
12044
|
+
if (child.pid) {
|
|
12045
|
+
writeDiagnostic(
|
|
12046
|
+
`[GithubCopilotCliExecutor] spawned child PID=${child.pid}
|
|
12047
|
+
`
|
|
12048
|
+
);
|
|
12049
|
+
}
|
|
12050
|
+
const timeoutMs = execution.timeoutMs;
|
|
12051
|
+
const timer = timeoutMs != null ? setTimeout(() => {
|
|
11971
12052
|
child.kill("SIGTERM");
|
|
11972
12053
|
setTimeout(() => {
|
|
11973
12054
|
if (!child.killed) child.kill("SIGKILL");
|
|
11974
12055
|
}, 5e3);
|
|
11975
12056
|
settle({
|
|
11976
12057
|
status: "timeout",
|
|
11977
|
-
error: `Copilot CLI execution timed out after ${
|
|
12058
|
+
error: `Copilot CLI execution timed out after ${timeoutMs / 1e3}s`
|
|
11978
12059
|
});
|
|
11979
|
-
},
|
|
12060
|
+
}, timeoutMs) : void 0;
|
|
11980
12061
|
let stdoutBuf = "";
|
|
11981
12062
|
let stderrBuf = "";
|
|
11982
12063
|
child.stdout.on("data", (chunk) => {
|
|
@@ -12022,20 +12103,23 @@ var init_GithubCopilotCliExecutor = __esm({
|
|
|
12022
12103
|
});
|
|
12023
12104
|
|
|
12024
12105
|
// ../../packages/serviceme-core/src/scheduled-tasks/executors/HttpRequestExecutor.ts
|
|
12025
|
-
var
|
|
12106
|
+
var DEFAULT_TIMEOUT_MS3, HttpRequestExecutor;
|
|
12026
12107
|
var init_HttpRequestExecutor = __esm({
|
|
12027
12108
|
"../../packages/serviceme-core/src/scheduled-tasks/executors/HttpRequestExecutor.ts"() {
|
|
12028
|
-
|
|
12109
|
+
init_timeout();
|
|
12110
|
+
DEFAULT_TIMEOUT_MS3 = 3e4;
|
|
12029
12111
|
HttpRequestExecutor = class {
|
|
12030
12112
|
async execute(payload, abortSignal) {
|
|
12031
12113
|
const p = payload;
|
|
12032
|
-
const
|
|
12114
|
+
const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS3);
|
|
12033
12115
|
const ac = new AbortController();
|
|
12034
|
-
|
|
12116
|
+
let timedOut = false;
|
|
12117
|
+
const timer = timeoutMs != null ? setTimeout(() => {
|
|
12118
|
+
timedOut = true;
|
|
12035
12119
|
ac.abort();
|
|
12036
|
-
},
|
|
12120
|
+
}, timeoutMs) : void 0;
|
|
12037
12121
|
if (abortSignal?.aborted) {
|
|
12038
|
-
clearTimeout(timer);
|
|
12122
|
+
if (timer) clearTimeout(timer);
|
|
12039
12123
|
return { status: "cancelled", error: "Execution aborted" };
|
|
12040
12124
|
}
|
|
12041
12125
|
let externalAbort = false;
|
|
@@ -12043,7 +12127,7 @@ var init_HttpRequestExecutor = __esm({
|
|
|
12043
12127
|
"abort",
|
|
12044
12128
|
() => {
|
|
12045
12129
|
externalAbort = true;
|
|
12046
|
-
clearTimeout(timer);
|
|
12130
|
+
if (timer) clearTimeout(timer);
|
|
12047
12131
|
ac.abort();
|
|
12048
12132
|
},
|
|
12049
12133
|
{ once: true }
|
|
@@ -12055,7 +12139,7 @@ var init_HttpRequestExecutor = __esm({
|
|
|
12055
12139
|
body: p.body,
|
|
12056
12140
|
signal: ac.signal
|
|
12057
12141
|
});
|
|
12058
|
-
clearTimeout(timer);
|
|
12142
|
+
if (timer) clearTimeout(timer);
|
|
12059
12143
|
const body = await response.text();
|
|
12060
12144
|
if (response.ok) {
|
|
12061
12145
|
return {
|
|
@@ -12070,14 +12154,17 @@ ${body}`.trim()
|
|
|
12070
12154
|
${body}`.trim()
|
|
12071
12155
|
};
|
|
12072
12156
|
} catch (err) {
|
|
12073
|
-
clearTimeout(timer);
|
|
12157
|
+
if (timer) clearTimeout(timer);
|
|
12074
12158
|
if (err instanceof Error && err.name === "AbortError") {
|
|
12075
12159
|
if (externalAbort) {
|
|
12076
12160
|
return { status: "cancelled", error: "Execution cancelled" };
|
|
12077
12161
|
}
|
|
12162
|
+
if (!timedOut || timeoutMs == null) {
|
|
12163
|
+
return { status: "failure", error: err.message };
|
|
12164
|
+
}
|
|
12078
12165
|
return {
|
|
12079
12166
|
status: "timeout",
|
|
12080
|
-
error: `HTTP request timed out after ${
|
|
12167
|
+
error: `HTTP request timed out after ${timeoutMs / 1e3}s`
|
|
12081
12168
|
};
|
|
12082
12169
|
}
|
|
12083
12170
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -12087,11 +12174,84 @@ ${body}`.trim()
|
|
|
12087
12174
|
};
|
|
12088
12175
|
}
|
|
12089
12176
|
});
|
|
12090
|
-
|
|
12177
|
+
function resolveShellExecution(script, options2 = {}) {
|
|
12178
|
+
const platform = options2.platform ?? process.platform;
|
|
12179
|
+
const env = options2.env ?? process.env;
|
|
12180
|
+
const fileExists = options2.fileExists ?? fs8__namespace.existsSync;
|
|
12181
|
+
if (platform === "win32") {
|
|
12182
|
+
const posixShell = usesPosixShellSyntax(script) ? findWindowsPosixShell(env, fileExists) : null;
|
|
12183
|
+
if (posixShell) {
|
|
12184
|
+
return {
|
|
12185
|
+
command: posixShell,
|
|
12186
|
+
args: ["-s"],
|
|
12187
|
+
stdinScript: script,
|
|
12188
|
+
outputEncoding: "utf8",
|
|
12189
|
+
shellKind: "posix"
|
|
12190
|
+
};
|
|
12191
|
+
}
|
|
12192
|
+
return {
|
|
12193
|
+
command: env.ComSpec ?? env.COMSPEC ?? "cmd.exe",
|
|
12194
|
+
args: ["/d", "/s", "/c", script],
|
|
12195
|
+
outputEncoding: "utf8",
|
|
12196
|
+
shellKind: "cmd"
|
|
12197
|
+
};
|
|
12198
|
+
}
|
|
12199
|
+
return {
|
|
12200
|
+
command: "sh",
|
|
12201
|
+
args: ["-s"],
|
|
12202
|
+
stdinScript: script,
|
|
12203
|
+
outputEncoding: "utf8",
|
|
12204
|
+
shellKind: "posix"
|
|
12205
|
+
};
|
|
12206
|
+
}
|
|
12207
|
+
function usesPosixShellSyntax(script) {
|
|
12208
|
+
return /\$\([^)]*\)|`[^`]*`/.test(script);
|
|
12209
|
+
}
|
|
12210
|
+
function findWindowsPosixShell(env, fileExists) {
|
|
12211
|
+
const explicitShell = env.SERVICEME_POSIX_SHELL;
|
|
12212
|
+
if (explicitShell && fileExists(explicitShell)) {
|
|
12213
|
+
return explicitShell;
|
|
12214
|
+
}
|
|
12215
|
+
const knownGitBashPaths = [
|
|
12216
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
12217
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
12218
|
+
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
12219
|
+
"C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
|
|
12220
|
+
];
|
|
12221
|
+
for (const candidate of knownGitBashPaths) {
|
|
12222
|
+
if (fileExists(candidate)) return candidate;
|
|
12223
|
+
}
|
|
12224
|
+
const pathValue = env.Path ?? env.PATH ?? "";
|
|
12225
|
+
for (const dir of pathValue.split(path__namespace.win32.delimiter)) {
|
|
12226
|
+
if (!dir) continue;
|
|
12227
|
+
for (const executable of POSIX_SHELL_CANDIDATES) {
|
|
12228
|
+
const candidate = path__namespace.win32.join(dir, executable);
|
|
12229
|
+
if (fileExists(candidate) && !isWindowsWslLauncher(candidate)) {
|
|
12230
|
+
return candidate;
|
|
12231
|
+
}
|
|
12232
|
+
}
|
|
12233
|
+
}
|
|
12234
|
+
return null;
|
|
12235
|
+
}
|
|
12236
|
+
function isWindowsWslLauncher(candidate) {
|
|
12237
|
+
const normalized = path__namespace.win32.normalize(candidate).toLowerCase();
|
|
12238
|
+
return normalized.endsWith("\\windows\\system32\\bash.exe") || normalized.endsWith("\\windows\\syswow64\\bash.exe");
|
|
12239
|
+
}
|
|
12240
|
+
function writeDiagnostic2(message) {
|
|
12241
|
+
const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
|
|
12242
|
+
if (logPath) {
|
|
12243
|
+
fs8__namespace.appendFileSync(logPath, message);
|
|
12244
|
+
return;
|
|
12245
|
+
}
|
|
12246
|
+
process.stderr.write(message);
|
|
12247
|
+
}
|
|
12248
|
+
var MAX_OUTPUT_BYTES2, DEFAULT_TIMEOUT_MS4, POSIX_SHELL_CANDIDATES, ShellExecutor;
|
|
12091
12249
|
var init_ShellExecutor = __esm({
|
|
12092
12250
|
"../../packages/serviceme-core/src/scheduled-tasks/executors/ShellExecutor.ts"() {
|
|
12093
|
-
|
|
12251
|
+
init_timeout();
|
|
12094
12252
|
MAX_OUTPUT_BYTES2 = 1024 * 1024;
|
|
12253
|
+
DEFAULT_TIMEOUT_MS4 = 6e4;
|
|
12254
|
+
POSIX_SHELL_CANDIDATES = ["bash.exe", "sh.exe"];
|
|
12095
12255
|
ShellExecutor = class {
|
|
12096
12256
|
async execute(payload, abortSignal) {
|
|
12097
12257
|
let output = "";
|
|
@@ -12107,7 +12267,7 @@ var init_ShellExecutor = __esm({
|
|
|
12107
12267
|
}
|
|
12108
12268
|
executeStreaming(payload, onOutput, abortSignal) {
|
|
12109
12269
|
const p = payload;
|
|
12110
|
-
const
|
|
12270
|
+
const timeoutMs = resolveConfiguredTimeoutMs(p.timeout, DEFAULT_TIMEOUT_MS4);
|
|
12111
12271
|
let resolve;
|
|
12112
12272
|
const resultPromise = new Promise((r) => {
|
|
12113
12273
|
resolve = r;
|
|
@@ -12116,7 +12276,7 @@ var init_ShellExecutor = __esm({
|
|
|
12116
12276
|
const settle = (result) => {
|
|
12117
12277
|
if (settled) return;
|
|
12118
12278
|
settled = true;
|
|
12119
|
-
clearTimeout(timer);
|
|
12279
|
+
if (timer) clearTimeout(timer);
|
|
12120
12280
|
resolve?.(result);
|
|
12121
12281
|
};
|
|
12122
12282
|
if (abortSignal?.aborted) {
|
|
@@ -12129,37 +12289,65 @@ var init_ShellExecutor = __esm({
|
|
|
12129
12289
|
}
|
|
12130
12290
|
};
|
|
12131
12291
|
}
|
|
12132
|
-
const
|
|
12292
|
+
const shellExecution = resolveShellExecution(p.script);
|
|
12293
|
+
const spawnOpts = {
|
|
12133
12294
|
cwd: p.cwd,
|
|
12134
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
12135
|
-
|
|
12136
|
-
|
|
12295
|
+
stdio: [shellExecution.stdinScript ? "pipe" : "ignore", "pipe", "pipe"],
|
|
12296
|
+
windowsHide: true
|
|
12297
|
+
};
|
|
12298
|
+
writeDiagnostic2(
|
|
12299
|
+
`[ShellExecutor] spawn:
|
|
12300
|
+
platform=${process.platform}
|
|
12301
|
+
shell=${shellExecution.shellKind}
|
|
12302
|
+
command=${shellExecution.command}
|
|
12303
|
+
args=${JSON.stringify(shellExecution.args.filter((a) => a !== p.script))}
|
|
12304
|
+
stdin=${shellExecution.stdinScript ? "true" : "false"}
|
|
12305
|
+
cwd=${p.cwd ?? "(default)"}
|
|
12306
|
+
timeout=${timeoutMs != null ? `${timeoutMs}ms` : "unlimited"}
|
|
12307
|
+
scriptLen=${p.script.length}
|
|
12308
|
+
windowsHide=true
|
|
12309
|
+
daemonPid=${process.pid}
|
|
12310
|
+
`
|
|
12311
|
+
);
|
|
12312
|
+
const child = child_process.spawn(shellExecution.command, shellExecution.args, spawnOpts);
|
|
12313
|
+
if (shellExecution.stdinScript && child.stdin) {
|
|
12314
|
+
child.stdin.end(shellExecution.stdinScript);
|
|
12315
|
+
}
|
|
12316
|
+
if (child.pid) {
|
|
12317
|
+
writeDiagnostic2(`[ShellExecutor] spawned child PID=${child.pid}
|
|
12318
|
+
`);
|
|
12319
|
+
}
|
|
12320
|
+
const timer = timeoutMs != null ? setTimeout(() => {
|
|
12137
12321
|
child.kill("SIGTERM");
|
|
12138
12322
|
setTimeout(() => {
|
|
12139
12323
|
if (!child.killed) child.kill("SIGKILL");
|
|
12140
12324
|
}, 5e3);
|
|
12141
12325
|
settle({
|
|
12142
12326
|
status: "timeout",
|
|
12143
|
-
error: `Shell execution timed out after ${
|
|
12327
|
+
error: `Shell execution timed out after ${timeoutMs / 1e3}s`
|
|
12144
12328
|
});
|
|
12145
|
-
},
|
|
12329
|
+
}, timeoutMs) : void 0;
|
|
12146
12330
|
let stdoutBuf = "";
|
|
12147
12331
|
let stderrBuf = "";
|
|
12148
|
-
child.stdout
|
|
12149
|
-
const data = chunk.toString();
|
|
12332
|
+
child.stdout?.on("data", (chunk) => {
|
|
12333
|
+
const data = chunk.toString(shellExecution.outputEncoding);
|
|
12150
12334
|
stdoutBuf += data;
|
|
12151
12335
|
if (stdoutBuf.length > MAX_OUTPUT_BYTES2)
|
|
12152
12336
|
stdoutBuf = stdoutBuf.slice(-MAX_OUTPUT_BYTES2);
|
|
12153
12337
|
onOutput("stdout", data);
|
|
12154
12338
|
});
|
|
12155
|
-
child.stderr
|
|
12156
|
-
const data = chunk.toString();
|
|
12339
|
+
child.stderr?.on("data", (chunk) => {
|
|
12340
|
+
const data = chunk.toString(shellExecution.outputEncoding);
|
|
12157
12341
|
stderrBuf += data;
|
|
12158
12342
|
if (stderrBuf.length > MAX_OUTPUT_BYTES2)
|
|
12159
12343
|
stderrBuf = stderrBuf.slice(-MAX_OUTPUT_BYTES2);
|
|
12160
12344
|
onOutput("stderr", data);
|
|
12161
12345
|
});
|
|
12162
12346
|
child.on("close", (code) => {
|
|
12347
|
+
writeDiagnostic2(
|
|
12348
|
+
`[ShellExecutor] child PID=${child.pid} exited: code=${code}
|
|
12349
|
+
`
|
|
12350
|
+
);
|
|
12163
12351
|
if (code === 0) {
|
|
12164
12352
|
settle({ status: "success", output: stdoutBuf || void 0 });
|
|
12165
12353
|
} else {
|
|
@@ -12221,9 +12409,38 @@ var init_executors = __esm({
|
|
|
12221
12409
|
function emptyConfig() {
|
|
12222
12410
|
return { version: 1, tasks: [] };
|
|
12223
12411
|
}
|
|
12412
|
+
function isRecord3(value) {
|
|
12413
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12414
|
+
}
|
|
12415
|
+
function requireNonEmptyString(payload, field, taskType) {
|
|
12416
|
+
if (!isRecord3(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
|
|
12417
|
+
throw createServicemeError(
|
|
12418
|
+
"invalid_payload",
|
|
12419
|
+
`${taskType} payload ${field} is required`
|
|
12420
|
+
);
|
|
12421
|
+
}
|
|
12422
|
+
}
|
|
12423
|
+
function validateTaskPayload(taskType, payload) {
|
|
12424
|
+
switch (taskType) {
|
|
12425
|
+
case "command":
|
|
12426
|
+
requireNonEmptyString(payload, "command", taskType);
|
|
12427
|
+
return;
|
|
12428
|
+
case "shell":
|
|
12429
|
+
requireNonEmptyString(payload, "script", taskType);
|
|
12430
|
+
return;
|
|
12431
|
+
case "http_request":
|
|
12432
|
+
requireNonEmptyString(payload, "url", taskType);
|
|
12433
|
+
requireNonEmptyString(payload, "method", taskType);
|
|
12434
|
+
return;
|
|
12435
|
+
case "github_copilot_cli":
|
|
12436
|
+
requireNonEmptyString(payload, "prompt", taskType);
|
|
12437
|
+
return;
|
|
12438
|
+
}
|
|
12439
|
+
}
|
|
12224
12440
|
var CONFIG_DIR3, CONFIG_FILE, TaskConfigManager;
|
|
12225
12441
|
var init_TaskConfigManager = __esm({
|
|
12226
12442
|
"../../packages/serviceme-core/src/scheduled-tasks/TaskConfigManager.ts"() {
|
|
12443
|
+
init_src();
|
|
12227
12444
|
CONFIG_DIR3 = ".serviceme";
|
|
12228
12445
|
CONFIG_FILE = "scheduled-tasks.json";
|
|
12229
12446
|
TaskConfigManager = class {
|
|
@@ -12234,21 +12451,21 @@ var init_TaskConfigManager = __esm({
|
|
|
12234
12451
|
return this.configPath;
|
|
12235
12452
|
}
|
|
12236
12453
|
readConfig() {
|
|
12237
|
-
if (!
|
|
12454
|
+
if (!fs8__namespace.existsSync(this.configPath)) {
|
|
12238
12455
|
return emptyConfig();
|
|
12239
12456
|
}
|
|
12240
|
-
const raw =
|
|
12457
|
+
const raw = fs8__namespace.readFileSync(this.configPath, "utf-8");
|
|
12241
12458
|
const parsed = JSON.parse(raw);
|
|
12242
12459
|
return parsed;
|
|
12243
12460
|
}
|
|
12244
12461
|
writeConfig(config) {
|
|
12245
12462
|
const dir = path__namespace.dirname(this.configPath);
|
|
12246
|
-
if (!
|
|
12247
|
-
|
|
12463
|
+
if (!fs8__namespace.existsSync(dir)) {
|
|
12464
|
+
fs8__namespace.mkdirSync(dir, { recursive: true });
|
|
12248
12465
|
}
|
|
12249
12466
|
const tmp = `${this.configPath}.tmp`;
|
|
12250
|
-
|
|
12251
|
-
|
|
12467
|
+
fs8__namespace.writeFileSync(tmp, JSON.stringify(config, null, " "), "utf-8");
|
|
12468
|
+
fs8__namespace.renameSync(tmp, this.configPath);
|
|
12252
12469
|
}
|
|
12253
12470
|
listTasks() {
|
|
12254
12471
|
return this.readConfig().tasks;
|
|
@@ -12260,6 +12477,7 @@ var init_TaskConfigManager = __esm({
|
|
|
12260
12477
|
return this.readConfig().tasks.find((t) => t.name === name);
|
|
12261
12478
|
}
|
|
12262
12479
|
createTask(input) {
|
|
12480
|
+
validateTaskPayload(input.taskType, input.payload);
|
|
12263
12481
|
const config = this.readConfig();
|
|
12264
12482
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12265
12483
|
const task = {
|
|
@@ -12288,6 +12506,9 @@ var init_TaskConfigManager = __esm({
|
|
|
12288
12506
|
if (!existing) {
|
|
12289
12507
|
throw new Error(`Task '${id}' not found`);
|
|
12290
12508
|
}
|
|
12509
|
+
const nextTaskType = input.taskType ?? existing.taskType;
|
|
12510
|
+
const nextPayload = input.payload ?? existing.payload;
|
|
12511
|
+
validateTaskPayload(nextTaskType, nextPayload);
|
|
12291
12512
|
const updated = {
|
|
12292
12513
|
...existing,
|
|
12293
12514
|
...input.name !== void 0 && { name: input.name },
|
|
@@ -12327,6 +12548,200 @@ var init_TaskConfigManager = __esm({
|
|
|
12327
12548
|
};
|
|
12328
12549
|
}
|
|
12329
12550
|
});
|
|
12551
|
+
|
|
12552
|
+
// ../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts
|
|
12553
|
+
function hasNonEmptyString(value) {
|
|
12554
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
12555
|
+
}
|
|
12556
|
+
function resolveTaskExecutionPayload(taskType, payload, workspacePath) {
|
|
12557
|
+
if (!hasNonEmptyString(workspacePath)) {
|
|
12558
|
+
return payload;
|
|
12559
|
+
}
|
|
12560
|
+
if (taskType === "shell") {
|
|
12561
|
+
const shellPayload = payload;
|
|
12562
|
+
if (hasNonEmptyString(shellPayload.cwd)) {
|
|
12563
|
+
return shellPayload;
|
|
12564
|
+
}
|
|
12565
|
+
return { ...shellPayload, cwd: workspacePath };
|
|
12566
|
+
}
|
|
12567
|
+
if (taskType === "github_copilot_cli") {
|
|
12568
|
+
const copilotPayload = payload;
|
|
12569
|
+
if (hasNonEmptyString(copilotPayload.workspace)) {
|
|
12570
|
+
return copilotPayload;
|
|
12571
|
+
}
|
|
12572
|
+
return { ...copilotPayload, workspace: workspacePath };
|
|
12573
|
+
}
|
|
12574
|
+
return payload;
|
|
12575
|
+
}
|
|
12576
|
+
var TaskExecutionEngine;
|
|
12577
|
+
var init_TaskExecutionEngine = __esm({
|
|
12578
|
+
"../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts"() {
|
|
12579
|
+
init_types();
|
|
12580
|
+
init_TaskConfigManager();
|
|
12581
|
+
TaskExecutionEngine = class {
|
|
12582
|
+
constructor(getExecutor2) {
|
|
12583
|
+
this.getExecutor = getExecutor2;
|
|
12584
|
+
this.running = /* @__PURE__ */ new Map();
|
|
12585
|
+
this.taskExecutions = /* @__PURE__ */ new Map();
|
|
12586
|
+
this.listener = null;
|
|
12587
|
+
}
|
|
12588
|
+
setListener(listener) {
|
|
12589
|
+
this.listener = listener;
|
|
12590
|
+
}
|
|
12591
|
+
async execute(snapshot) {
|
|
12592
|
+
const policy = snapshot.concurrencyPolicy ?? "reject";
|
|
12593
|
+
if (policy === "reject") {
|
|
12594
|
+
const existingIds = this.taskExecutions.get(snapshot.taskId);
|
|
12595
|
+
if (existingIds && existingIds.size > 0) {
|
|
12596
|
+
throw new Error(
|
|
12597
|
+
`TASK_ALREADY_RUNNING: Task ${snapshot.taskId} is already running`
|
|
12598
|
+
);
|
|
12599
|
+
}
|
|
12600
|
+
}
|
|
12601
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12602
|
+
if (!this.taskExecutions.has(snapshot.taskId)) {
|
|
12603
|
+
this.taskExecutions.set(snapshot.taskId, /* @__PURE__ */ new Set());
|
|
12604
|
+
}
|
|
12605
|
+
this.taskExecutions.get(snapshot.taskId)?.add(snapshot.executionId);
|
|
12606
|
+
const ac = new AbortController();
|
|
12607
|
+
const runningExec = {
|
|
12608
|
+
executionId: snapshot.executionId,
|
|
12609
|
+
taskId: snapshot.taskId,
|
|
12610
|
+
startedAt,
|
|
12611
|
+
cancel: () => ac.abort()
|
|
12612
|
+
};
|
|
12613
|
+
this.running.set(snapshot.executionId, runningExec);
|
|
12614
|
+
this.listener?.onStarted({
|
|
12615
|
+
executionId: snapshot.executionId,
|
|
12616
|
+
taskId: snapshot.taskId,
|
|
12617
|
+
startedAt
|
|
12618
|
+
});
|
|
12619
|
+
try {
|
|
12620
|
+
const executionPayload = resolveTaskExecutionPayload(
|
|
12621
|
+
snapshot.type,
|
|
12622
|
+
snapshot.payload,
|
|
12623
|
+
snapshot.workspacePath
|
|
12624
|
+
);
|
|
12625
|
+
validateTaskPayload(snapshot.type, executionPayload);
|
|
12626
|
+
const executor = this.getExecutor(snapshot.type);
|
|
12627
|
+
let result;
|
|
12628
|
+
if (isStreamingTaskExecutor(executor)) {
|
|
12629
|
+
const handle = executor.executeStreaming(
|
|
12630
|
+
executionPayload,
|
|
12631
|
+
(stream, data) => {
|
|
12632
|
+
this.listener?.onOutput({
|
|
12633
|
+
executionId: snapshot.executionId,
|
|
12634
|
+
stream,
|
|
12635
|
+
data
|
|
12636
|
+
});
|
|
12637
|
+
},
|
|
12638
|
+
ac.signal
|
|
12639
|
+
);
|
|
12640
|
+
runningExec.cancel = () => {
|
|
12641
|
+
handle.cancel();
|
|
12642
|
+
ac.abort();
|
|
12643
|
+
};
|
|
12644
|
+
result = await handle.result;
|
|
12645
|
+
} else {
|
|
12646
|
+
result = await executor.execute(executionPayload, ac.signal);
|
|
12647
|
+
}
|
|
12648
|
+
const log = {
|
|
12649
|
+
id: snapshot.executionId,
|
|
12650
|
+
taskId: snapshot.taskId,
|
|
12651
|
+
taskName: snapshot.name,
|
|
12652
|
+
startedAt,
|
|
12653
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12654
|
+
status: result.status === "running" ? "failure" : result.status,
|
|
12655
|
+
output: result.output,
|
|
12656
|
+
error: result.error
|
|
12657
|
+
};
|
|
12658
|
+
switch (log.status) {
|
|
12659
|
+
case "success":
|
|
12660
|
+
this.listener?.onCompleted({
|
|
12661
|
+
executionId: snapshot.executionId,
|
|
12662
|
+
log
|
|
12663
|
+
});
|
|
12664
|
+
break;
|
|
12665
|
+
case "cancelled":
|
|
12666
|
+
this.listener?.onCancelled({
|
|
12667
|
+
executionId: snapshot.executionId,
|
|
12668
|
+
log
|
|
12669
|
+
});
|
|
12670
|
+
break;
|
|
12671
|
+
case "timeout":
|
|
12672
|
+
this.listener?.onFailed({
|
|
12673
|
+
executionId: snapshot.executionId,
|
|
12674
|
+
status: "timeout",
|
|
12675
|
+
reason: "timeout",
|
|
12676
|
+
log
|
|
12677
|
+
});
|
|
12678
|
+
break;
|
|
12679
|
+
default:
|
|
12680
|
+
this.listener?.onFailed({
|
|
12681
|
+
executionId: snapshot.executionId,
|
|
12682
|
+
status: "failure",
|
|
12683
|
+
reason: "error",
|
|
12684
|
+
log
|
|
12685
|
+
});
|
|
12686
|
+
break;
|
|
12687
|
+
}
|
|
12688
|
+
} catch (err) {
|
|
12689
|
+
const log = {
|
|
12690
|
+
id: snapshot.executionId,
|
|
12691
|
+
taskId: snapshot.taskId,
|
|
12692
|
+
taskName: snapshot.name,
|
|
12693
|
+
startedAt,
|
|
12694
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12695
|
+
status: ac.signal.aborted ? "cancelled" : "failure",
|
|
12696
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12697
|
+
};
|
|
12698
|
+
if (ac.signal.aborted) {
|
|
12699
|
+
this.listener?.onCancelled({
|
|
12700
|
+
executionId: snapshot.executionId,
|
|
12701
|
+
log
|
|
12702
|
+
});
|
|
12703
|
+
} else {
|
|
12704
|
+
this.listener?.onFailed({
|
|
12705
|
+
executionId: snapshot.executionId,
|
|
12706
|
+
status: "failure",
|
|
12707
|
+
reason: "error",
|
|
12708
|
+
log
|
|
12709
|
+
});
|
|
12710
|
+
}
|
|
12711
|
+
} finally {
|
|
12712
|
+
this.running.delete(snapshot.executionId);
|
|
12713
|
+
const taskExecIds = this.taskExecutions.get(snapshot.taskId);
|
|
12714
|
+
if (taskExecIds) {
|
|
12715
|
+
taskExecIds.delete(snapshot.executionId);
|
|
12716
|
+
if (taskExecIds.size === 0) {
|
|
12717
|
+
this.taskExecutions.delete(snapshot.taskId);
|
|
12718
|
+
}
|
|
12719
|
+
}
|
|
12720
|
+
}
|
|
12721
|
+
}
|
|
12722
|
+
cancel(executionId) {
|
|
12723
|
+
const exec = this.running.get(executionId);
|
|
12724
|
+
if (!exec) return false;
|
|
12725
|
+
exec.cancel();
|
|
12726
|
+
return true;
|
|
12727
|
+
}
|
|
12728
|
+
listRunning() {
|
|
12729
|
+
return Array.from(this.running.values()).map((e) => ({
|
|
12730
|
+
executionId: e.executionId,
|
|
12731
|
+
taskId: e.taskId,
|
|
12732
|
+
startedAt: e.startedAt
|
|
12733
|
+
}));
|
|
12734
|
+
}
|
|
12735
|
+
dispose() {
|
|
12736
|
+
for (const exec of this.running.values()) {
|
|
12737
|
+
exec.cancel();
|
|
12738
|
+
}
|
|
12739
|
+
this.running.clear();
|
|
12740
|
+
this.taskExecutions.clear();
|
|
12741
|
+
}
|
|
12742
|
+
};
|
|
12743
|
+
}
|
|
12744
|
+
});
|
|
12330
12745
|
function emptyLogFile() {
|
|
12331
12746
|
return { logs: [] };
|
|
12332
12747
|
}
|
|
@@ -12360,11 +12775,11 @@ var init_TaskLogManager = __esm({
|
|
|
12360
12775
|
return this.logPath;
|
|
12361
12776
|
}
|
|
12362
12777
|
readLogFile() {
|
|
12363
|
-
if (!
|
|
12778
|
+
if (!fs8__namespace.existsSync(this.logPath)) {
|
|
12364
12779
|
return emptyLogFile();
|
|
12365
12780
|
}
|
|
12366
12781
|
try {
|
|
12367
|
-
const raw =
|
|
12782
|
+
const raw = fs8__namespace.readFileSync(this.logPath, "utf-8");
|
|
12368
12783
|
const parsed = JSON.parse(raw);
|
|
12369
12784
|
const file = validateAndRepairLogFile(parsed);
|
|
12370
12785
|
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.logs) || parsed.logs.length !== file.logs.length) {
|
|
@@ -12380,21 +12795,21 @@ var init_TaskLogManager = __esm({
|
|
|
12380
12795
|
}
|
|
12381
12796
|
backupCorruptedFile() {
|
|
12382
12797
|
try {
|
|
12383
|
-
if (
|
|
12798
|
+
if (fs8__namespace.existsSync(this.logPath)) {
|
|
12384
12799
|
const backupPath = `${this.logPath}.corrupted.${Date.now()}`;
|
|
12385
|
-
|
|
12800
|
+
fs8__namespace.copyFileSync(this.logPath, backupPath);
|
|
12386
12801
|
}
|
|
12387
12802
|
} catch {
|
|
12388
12803
|
}
|
|
12389
12804
|
}
|
|
12390
12805
|
writeLogFile(file) {
|
|
12391
12806
|
const dir = path__namespace.dirname(this.logPath);
|
|
12392
|
-
if (!
|
|
12393
|
-
|
|
12807
|
+
if (!fs8__namespace.existsSync(dir)) {
|
|
12808
|
+
fs8__namespace.mkdirSync(dir, { recursive: true });
|
|
12394
12809
|
}
|
|
12395
12810
|
const tmp = `${this.logPath}.tmp`;
|
|
12396
|
-
|
|
12397
|
-
|
|
12811
|
+
fs8__namespace.writeFileSync(tmp, JSON.stringify(file, null, " "), "utf-8");
|
|
12812
|
+
fs8__namespace.renameSync(tmp, this.logPath);
|
|
12398
12813
|
}
|
|
12399
12814
|
appendLog(input) {
|
|
12400
12815
|
const file = this.readLogFile();
|
|
@@ -12486,6 +12901,7 @@ var init_SchedulerDaemon = __esm({
|
|
|
12486
12901
|
"../../packages/serviceme-core/src/scheduled-tasks/daemon/SchedulerDaemon.ts"() {
|
|
12487
12902
|
init_executors();
|
|
12488
12903
|
init_TaskConfigManager();
|
|
12904
|
+
init_TaskExecutionEngine();
|
|
12489
12905
|
init_TaskLogManager();
|
|
12490
12906
|
init_DaemonLogger();
|
|
12491
12907
|
init_PidManager();
|
|
@@ -12511,7 +12927,23 @@ var init_SchedulerDaemon = __esm({
|
|
|
12511
12927
|
this.running = true;
|
|
12512
12928
|
this.startTime = Date.now();
|
|
12513
12929
|
this.pidManager.writePid(process.pid);
|
|
12514
|
-
this.
|
|
12930
|
+
const configPath = this.configManager.getConfigPath();
|
|
12931
|
+
const logPath = this.logger.getLogPath();
|
|
12932
|
+
this.logger.log("info", "=".repeat(60));
|
|
12933
|
+
this.logger.log(
|
|
12934
|
+
"info",
|
|
12935
|
+
`Scheduler daemon started
|
|
12936
|
+
PID: ${process.pid}
|
|
12937
|
+
Node: ${process.version}
|
|
12938
|
+
OS: ${os__namespace.type()} ${os__namespace.release()} (${process.arch})
|
|
12939
|
+
Platform: ${process.platform}
|
|
12940
|
+
Hostname: ${os__namespace.hostname()}
|
|
12941
|
+
User: ${os__namespace.userInfo().username}
|
|
12942
|
+
Workspace: ${this.workspacePath}
|
|
12943
|
+
Config: ${configPath}
|
|
12944
|
+
LogPath: ${logPath}
|
|
12945
|
+
ExecPath: ${process.execPath}`
|
|
12946
|
+
);
|
|
12515
12947
|
this.tickTimer = setInterval(() => this.tick(), TICK_INTERVAL);
|
|
12516
12948
|
this.setupConfigWatch();
|
|
12517
12949
|
process.on("SIGTERM", () => this.stop());
|
|
@@ -12536,8 +12968,8 @@ var init_SchedulerDaemon = __esm({
|
|
|
12536
12968
|
const configPath = this.configManager.getConfigPath();
|
|
12537
12969
|
const dir = configPath.substring(0, configPath.lastIndexOf("/"));
|
|
12538
12970
|
try {
|
|
12539
|
-
if (
|
|
12540
|
-
this.watcher =
|
|
12971
|
+
if (fs8__namespace.existsSync(dir)) {
|
|
12972
|
+
this.watcher = fs8__namespace.watch(dir, (_eventType, filename) => {
|
|
12541
12973
|
if (filename === "scheduled-tasks.json") {
|
|
12542
12974
|
this.logger.log("info", "Config file changed, reconciling...");
|
|
12543
12975
|
}
|
|
@@ -12553,7 +12985,11 @@ var init_SchedulerDaemon = __esm({
|
|
|
12553
12985
|
for (const task of config.tasks) {
|
|
12554
12986
|
if (!task.enabled) continue;
|
|
12555
12987
|
if (this.taskRunning.has(task.id)) continue;
|
|
12556
|
-
|
|
12988
|
+
let lastExec = this.lastRun.get(task.id);
|
|
12989
|
+
if (lastExec === void 0) {
|
|
12990
|
+
this.lastRun.set(task.id, now);
|
|
12991
|
+
lastExec = now;
|
|
12992
|
+
}
|
|
12557
12993
|
if (this.shouldRun(task, lastExec, now)) {
|
|
12558
12994
|
this.executeTask(task, now);
|
|
12559
12995
|
}
|
|
@@ -12575,11 +13011,25 @@ var init_SchedulerDaemon = __esm({
|
|
|
12575
13011
|
this.taskRunning.add(task.id);
|
|
12576
13012
|
this.lastRun.set(task.id, now);
|
|
12577
13013
|
const startedAt = new Date(now).toISOString();
|
|
12578
|
-
|
|
13014
|
+
const startMs = Date.now();
|
|
13015
|
+
this.logger.log(
|
|
13016
|
+
"info",
|
|
13017
|
+
`Executing task: ${task.name} (${task.id})
|
|
13018
|
+
type: ${task.taskType}
|
|
13019
|
+
schedule: ${task.schedule} (${task.scheduleType})
|
|
13020
|
+
enabled: ${task.enabled}`
|
|
13021
|
+
);
|
|
12579
13022
|
try {
|
|
13023
|
+
const executionPayload = resolveTaskExecutionPayload(
|
|
13024
|
+
task.taskType,
|
|
13025
|
+
task.payload,
|
|
13026
|
+
this.workspacePath
|
|
13027
|
+
);
|
|
13028
|
+
validateTaskPayload(task.taskType, executionPayload);
|
|
12580
13029
|
const executor = getExecutor(task.taskType);
|
|
12581
|
-
const result = await executor.execute(
|
|
13030
|
+
const result = await executor.execute(executionPayload);
|
|
12582
13031
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13032
|
+
const durationMs = Date.now() - startMs;
|
|
12583
13033
|
this.logManager.appendLog({
|
|
12584
13034
|
taskId: task.id,
|
|
12585
13035
|
taskName: task.name,
|
|
@@ -12589,9 +13039,17 @@ var init_SchedulerDaemon = __esm({
|
|
|
12589
13039
|
output: result.output,
|
|
12590
13040
|
error: result.error
|
|
12591
13041
|
});
|
|
12592
|
-
|
|
13042
|
+
const outputBytes = result.output ? Buffer.byteLength(result.output) : 0;
|
|
13043
|
+
this.logger.log(
|
|
13044
|
+
"info",
|
|
13045
|
+
`Task completed: ${task.name} (${task.id})
|
|
13046
|
+
status: ${result.status}
|
|
13047
|
+
duration: ${durationMs}ms
|
|
13048
|
+
outputBytes: ${outputBytes}`
|
|
13049
|
+
);
|
|
12593
13050
|
} catch (err) {
|
|
12594
13051
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13052
|
+
const durationMs = Date.now() - startMs;
|
|
12595
13053
|
const message = err instanceof Error ? err.message : String(err);
|
|
12596
13054
|
this.logManager.appendLog({
|
|
12597
13055
|
taskId: task.id,
|
|
@@ -12601,7 +13059,12 @@ var init_SchedulerDaemon = __esm({
|
|
|
12601
13059
|
status: "failure",
|
|
12602
13060
|
error: message
|
|
12603
13061
|
});
|
|
12604
|
-
this.logger.log(
|
|
13062
|
+
this.logger.log(
|
|
13063
|
+
"error",
|
|
13064
|
+
`Task failed: ${task.name} (${task.id})
|
|
13065
|
+
duration: ${durationMs}ms
|
|
13066
|
+
error: ${message}`
|
|
13067
|
+
);
|
|
12605
13068
|
} finally {
|
|
12606
13069
|
this.taskRunning.delete(task.id);
|
|
12607
13070
|
}
|
|
@@ -12631,170 +13094,6 @@ var init_daemon = __esm({
|
|
|
12631
13094
|
}
|
|
12632
13095
|
});
|
|
12633
13096
|
|
|
12634
|
-
// ../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts
|
|
12635
|
-
var TaskExecutionEngine;
|
|
12636
|
-
var init_TaskExecutionEngine = __esm({
|
|
12637
|
-
"../../packages/serviceme-core/src/scheduled-tasks/TaskExecutionEngine.ts"() {
|
|
12638
|
-
init_types();
|
|
12639
|
-
TaskExecutionEngine = class {
|
|
12640
|
-
constructor(getExecutor2) {
|
|
12641
|
-
this.getExecutor = getExecutor2;
|
|
12642
|
-
this.running = /* @__PURE__ */ new Map();
|
|
12643
|
-
this.taskExecutions = /* @__PURE__ */ new Map();
|
|
12644
|
-
this.listener = null;
|
|
12645
|
-
}
|
|
12646
|
-
setListener(listener) {
|
|
12647
|
-
this.listener = listener;
|
|
12648
|
-
}
|
|
12649
|
-
async execute(snapshot) {
|
|
12650
|
-
const policy = snapshot.concurrencyPolicy ?? "reject";
|
|
12651
|
-
if (policy === "reject") {
|
|
12652
|
-
const existingIds = this.taskExecutions.get(snapshot.taskId);
|
|
12653
|
-
if (existingIds && existingIds.size > 0) {
|
|
12654
|
-
throw new Error(
|
|
12655
|
-
`TASK_ALREADY_RUNNING: Task ${snapshot.taskId} is already running`
|
|
12656
|
-
);
|
|
12657
|
-
}
|
|
12658
|
-
}
|
|
12659
|
-
const executor = this.getExecutor(snapshot.type);
|
|
12660
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12661
|
-
if (!this.taskExecutions.has(snapshot.taskId)) {
|
|
12662
|
-
this.taskExecutions.set(snapshot.taskId, /* @__PURE__ */ new Set());
|
|
12663
|
-
}
|
|
12664
|
-
this.taskExecutions.get(snapshot.taskId)?.add(snapshot.executionId);
|
|
12665
|
-
const ac = new AbortController();
|
|
12666
|
-
const runningExec = {
|
|
12667
|
-
executionId: snapshot.executionId,
|
|
12668
|
-
taskId: snapshot.taskId,
|
|
12669
|
-
startedAt,
|
|
12670
|
-
cancel: () => ac.abort()
|
|
12671
|
-
};
|
|
12672
|
-
this.running.set(snapshot.executionId, runningExec);
|
|
12673
|
-
this.listener?.onStarted({
|
|
12674
|
-
executionId: snapshot.executionId,
|
|
12675
|
-
taskId: snapshot.taskId,
|
|
12676
|
-
startedAt
|
|
12677
|
-
});
|
|
12678
|
-
try {
|
|
12679
|
-
let result;
|
|
12680
|
-
if (isStreamingTaskExecutor(executor)) {
|
|
12681
|
-
const handle = executor.executeStreaming(
|
|
12682
|
-
snapshot.payload,
|
|
12683
|
-
(stream, data) => {
|
|
12684
|
-
this.listener?.onOutput({
|
|
12685
|
-
executionId: snapshot.executionId,
|
|
12686
|
-
stream,
|
|
12687
|
-
data
|
|
12688
|
-
});
|
|
12689
|
-
},
|
|
12690
|
-
ac.signal
|
|
12691
|
-
);
|
|
12692
|
-
runningExec.cancel = () => {
|
|
12693
|
-
handle.cancel();
|
|
12694
|
-
ac.abort();
|
|
12695
|
-
};
|
|
12696
|
-
result = await handle.result;
|
|
12697
|
-
} else {
|
|
12698
|
-
result = await executor.execute(snapshot.payload, ac.signal);
|
|
12699
|
-
}
|
|
12700
|
-
const log = {
|
|
12701
|
-
id: snapshot.executionId,
|
|
12702
|
-
taskId: snapshot.taskId,
|
|
12703
|
-
taskName: snapshot.name,
|
|
12704
|
-
startedAt,
|
|
12705
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12706
|
-
status: result.status === "running" ? "failure" : result.status,
|
|
12707
|
-
output: result.output,
|
|
12708
|
-
error: result.error
|
|
12709
|
-
};
|
|
12710
|
-
switch (log.status) {
|
|
12711
|
-
case "success":
|
|
12712
|
-
this.listener?.onCompleted({
|
|
12713
|
-
executionId: snapshot.executionId,
|
|
12714
|
-
log
|
|
12715
|
-
});
|
|
12716
|
-
break;
|
|
12717
|
-
case "cancelled":
|
|
12718
|
-
this.listener?.onCancelled({
|
|
12719
|
-
executionId: snapshot.executionId,
|
|
12720
|
-
log
|
|
12721
|
-
});
|
|
12722
|
-
break;
|
|
12723
|
-
case "timeout":
|
|
12724
|
-
this.listener?.onFailed({
|
|
12725
|
-
executionId: snapshot.executionId,
|
|
12726
|
-
status: "timeout",
|
|
12727
|
-
reason: "timeout",
|
|
12728
|
-
log
|
|
12729
|
-
});
|
|
12730
|
-
break;
|
|
12731
|
-
default:
|
|
12732
|
-
this.listener?.onFailed({
|
|
12733
|
-
executionId: snapshot.executionId,
|
|
12734
|
-
status: "failure",
|
|
12735
|
-
reason: "error",
|
|
12736
|
-
log
|
|
12737
|
-
});
|
|
12738
|
-
break;
|
|
12739
|
-
}
|
|
12740
|
-
} catch (err) {
|
|
12741
|
-
const log = {
|
|
12742
|
-
id: snapshot.executionId,
|
|
12743
|
-
taskId: snapshot.taskId,
|
|
12744
|
-
taskName: snapshot.name,
|
|
12745
|
-
startedAt,
|
|
12746
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12747
|
-
status: ac.signal.aborted ? "cancelled" : "failure",
|
|
12748
|
-
error: err instanceof Error ? err.message : String(err)
|
|
12749
|
-
};
|
|
12750
|
-
if (ac.signal.aborted) {
|
|
12751
|
-
this.listener?.onCancelled({
|
|
12752
|
-
executionId: snapshot.executionId,
|
|
12753
|
-
log
|
|
12754
|
-
});
|
|
12755
|
-
} else {
|
|
12756
|
-
this.listener?.onFailed({
|
|
12757
|
-
executionId: snapshot.executionId,
|
|
12758
|
-
status: "failure",
|
|
12759
|
-
reason: "error",
|
|
12760
|
-
log
|
|
12761
|
-
});
|
|
12762
|
-
}
|
|
12763
|
-
} finally {
|
|
12764
|
-
this.running.delete(snapshot.executionId);
|
|
12765
|
-
const taskExecIds = this.taskExecutions.get(snapshot.taskId);
|
|
12766
|
-
if (taskExecIds) {
|
|
12767
|
-
taskExecIds.delete(snapshot.executionId);
|
|
12768
|
-
if (taskExecIds.size === 0) {
|
|
12769
|
-
this.taskExecutions.delete(snapshot.taskId);
|
|
12770
|
-
}
|
|
12771
|
-
}
|
|
12772
|
-
}
|
|
12773
|
-
}
|
|
12774
|
-
cancel(executionId) {
|
|
12775
|
-
const exec = this.running.get(executionId);
|
|
12776
|
-
if (!exec) return false;
|
|
12777
|
-
exec.cancel();
|
|
12778
|
-
return true;
|
|
12779
|
-
}
|
|
12780
|
-
listRunning() {
|
|
12781
|
-
return Array.from(this.running.values()).map((e) => ({
|
|
12782
|
-
executionId: e.executionId,
|
|
12783
|
-
taskId: e.taskId,
|
|
12784
|
-
startedAt: e.startedAt
|
|
12785
|
-
}));
|
|
12786
|
-
}
|
|
12787
|
-
dispose() {
|
|
12788
|
-
for (const exec of this.running.values()) {
|
|
12789
|
-
exec.cancel();
|
|
12790
|
-
}
|
|
12791
|
-
this.running.clear();
|
|
12792
|
-
this.taskExecutions.clear();
|
|
12793
|
-
}
|
|
12794
|
-
};
|
|
12795
|
-
}
|
|
12796
|
-
});
|
|
12797
|
-
|
|
12798
13097
|
// ../../packages/serviceme-core/src/scheduled-tasks/index.ts
|
|
12799
13098
|
var init_scheduled_tasks2 = __esm({
|
|
12800
13099
|
"../../packages/serviceme-core/src/scheduled-tasks/index.ts"() {
|
|
@@ -12836,7 +13135,9 @@ __export(src_exports, {
|
|
|
12836
13135
|
moveFiles: () => moveFiles,
|
|
12837
13136
|
noopLogger: () => noopLogger,
|
|
12838
13137
|
parseIntervalMs: () => parseIntervalMs,
|
|
12839
|
-
|
|
13138
|
+
resolveTaskExecutionPayload: () => resolveTaskExecutionPayload,
|
|
13139
|
+
unzipFile: () => unzipFile,
|
|
13140
|
+
validateTaskPayload: () => validateTaskPayload
|
|
12840
13141
|
});
|
|
12841
13142
|
var init_src2 = __esm({
|
|
12842
13143
|
"../../packages/serviceme-core/src/index.ts"() {
|
|
@@ -12905,7 +13206,7 @@ init_src();
|
|
|
12905
13206
|
|
|
12906
13207
|
// src/version.ts
|
|
12907
13208
|
var SERVICEME_CLI_NAME = "serviceme";
|
|
12908
|
-
var SERVICEME_CLI_VERSION = "0.1.
|
|
13209
|
+
var SERVICEME_CLI_VERSION = "0.1.5";
|
|
12909
13210
|
|
|
12910
13211
|
// src/bridge/ndjson.ts
|
|
12911
13212
|
function writeBridgeMessage(message) {
|
|
@@ -13432,7 +13733,7 @@ function requireWorkspace(parsed) {
|
|
|
13432
13733
|
"Missing required flag: --workspacePath"
|
|
13433
13734
|
);
|
|
13434
13735
|
}
|
|
13435
|
-
if (!
|
|
13736
|
+
if (!fs8__namespace.existsSync(wp)) {
|
|
13436
13737
|
throw createServicemeError(
|
|
13437
13738
|
"workspace_not_found",
|
|
13438
13739
|
`Workspace path does not exist: ${wp}`
|
|
@@ -13765,8 +14066,14 @@ async function handleTrigger(parsed) {
|
|
|
13765
14066
|
);
|
|
13766
14067
|
}
|
|
13767
14068
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14069
|
+
const executionPayload = resolveTaskExecutionPayload(
|
|
14070
|
+
task.taskType,
|
|
14071
|
+
task.payload,
|
|
14072
|
+
wp
|
|
14073
|
+
);
|
|
14074
|
+
validateTaskPayload(task.taskType, executionPayload);
|
|
13768
14075
|
const executor = getExecutor(task.taskType);
|
|
13769
|
-
const result = await executor.execute(
|
|
14076
|
+
const result = await executor.execute(executionPayload);
|
|
13770
14077
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13771
14078
|
const logMgr = new TaskLogManager(wp);
|
|
13772
14079
|
const log = logMgr.appendLog({
|
|
@@ -13995,7 +14302,7 @@ function requireWorkspace2(parsed) {
|
|
|
13995
14302
|
"Missing required flag: --workspacePath"
|
|
13996
14303
|
);
|
|
13997
14304
|
}
|
|
13998
|
-
if (!
|
|
14305
|
+
if (!fs8__namespace.existsSync(wp)) {
|
|
13999
14306
|
throw createServicemeError(
|
|
14000
14307
|
"workspace_not_found",
|
|
14001
14308
|
`Workspace path does not exist: ${wp}`
|
|
@@ -14024,20 +14331,43 @@ function handleStart(parsed) {
|
|
|
14024
14331
|
}
|
|
14025
14332
|
const logPath = path__namespace.join(wp, ".serviceme", "scheduler.log");
|
|
14026
14333
|
const logDir = path__namespace.dirname(logPath);
|
|
14027
|
-
if (!
|
|
14028
|
-
|
|
14029
|
-
}
|
|
14030
|
-
const
|
|
14031
|
-
const
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14039
|
-
|
|
14334
|
+
if (!fs8__namespace.existsSync(logDir)) {
|
|
14335
|
+
fs8__namespace.mkdirSync(logDir, { recursive: true });
|
|
14336
|
+
}
|
|
14337
|
+
const spawnCmd = process.execPath;
|
|
14338
|
+
const spawnArgs = [
|
|
14339
|
+
cliPath,
|
|
14340
|
+
"scheduler",
|
|
14341
|
+
"__daemon",
|
|
14342
|
+
"--workspacePath",
|
|
14343
|
+
wp,
|
|
14344
|
+
"--logPath",
|
|
14345
|
+
logPath
|
|
14346
|
+
];
|
|
14347
|
+
if (process.platform === "win32") {
|
|
14348
|
+
fs8__namespace.appendFileSync(
|
|
14349
|
+
logPath,
|
|
14350
|
+
`[scheduler:start] spawning daemon via hidden PowerShell Start-Process: cmd=${spawnCmd}, args=${JSON.stringify(spawnArgs)}, platform=${process.platform}, windowsHide=true
|
|
14351
|
+
`
|
|
14352
|
+
);
|
|
14353
|
+
const pid2 = startWindowsDaemon(spawnCmd, spawnArgs);
|
|
14354
|
+
pidMgr.writePid(pid2);
|
|
14355
|
+
writeSuccess({ pid: pid2, status: "started", workspacePath: wp });
|
|
14356
|
+
return;
|
|
14357
|
+
}
|
|
14358
|
+
const out = fs8__namespace.openSync(logPath, "a");
|
|
14359
|
+
const err = fs8__namespace.openSync(logPath, "a");
|
|
14360
|
+
fs8__namespace.appendFileSync(
|
|
14361
|
+
logPath,
|
|
14362
|
+
`[scheduler:start] spawning daemon: cmd=${spawnCmd}, args=${JSON.stringify(spawnArgs)}, platform=${process.platform}, detached=true, windowsHide=true
|
|
14363
|
+
`
|
|
14040
14364
|
);
|
|
14365
|
+
const child = child_process.spawn(spawnCmd, spawnArgs, {
|
|
14366
|
+
detached: true,
|
|
14367
|
+
stdio: ["ignore", out, err],
|
|
14368
|
+
env: { ...process.env },
|
|
14369
|
+
windowsHide: true
|
|
14370
|
+
});
|
|
14041
14371
|
child.unref();
|
|
14042
14372
|
const pid = child.pid;
|
|
14043
14373
|
if (pid === void 0) {
|
|
@@ -14049,6 +14379,60 @@ function handleStart(parsed) {
|
|
|
14049
14379
|
pidMgr.writePid(pid);
|
|
14050
14380
|
writeSuccess({ pid, status: "started", workspacePath: wp });
|
|
14051
14381
|
}
|
|
14382
|
+
function startWindowsDaemon(command, args) {
|
|
14383
|
+
const argumentLine = args.map(quoteWindowsArgument).join(" ");
|
|
14384
|
+
const script = [
|
|
14385
|
+
"$ErrorActionPreference = 'Stop'",
|
|
14386
|
+
`$process = Start-Process -FilePath ${quotePowerShellString(command)} -ArgumentList ${quotePowerShellString(argumentLine)} -WindowStyle Hidden -PassThru`,
|
|
14387
|
+
"Write-Output $process.Id"
|
|
14388
|
+
].join("; ");
|
|
14389
|
+
const encodedCommand = Buffer.from(script, "utf16le").toString("base64");
|
|
14390
|
+
const result = child_process.spawnSync(
|
|
14391
|
+
"powershell.exe",
|
|
14392
|
+
[
|
|
14393
|
+
"-NoProfile",
|
|
14394
|
+
"-NonInteractive",
|
|
14395
|
+
"-ExecutionPolicy",
|
|
14396
|
+
"Bypass",
|
|
14397
|
+
"-WindowStyle",
|
|
14398
|
+
"Hidden",
|
|
14399
|
+
"-EncodedCommand",
|
|
14400
|
+
encodedCommand
|
|
14401
|
+
],
|
|
14402
|
+
{
|
|
14403
|
+
encoding: "utf8",
|
|
14404
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
14405
|
+
windowsHide: true
|
|
14406
|
+
}
|
|
14407
|
+
);
|
|
14408
|
+
if (result.error) {
|
|
14409
|
+
throw createServicemeError(
|
|
14410
|
+
"internal_error",
|
|
14411
|
+
`Failed to start scheduler daemon: ${result.error.message}`
|
|
14412
|
+
);
|
|
14413
|
+
}
|
|
14414
|
+
if (result.status !== 0) {
|
|
14415
|
+
const stderr = result.stderr.trim();
|
|
14416
|
+
throw createServicemeError(
|
|
14417
|
+
"internal_error",
|
|
14418
|
+
`Failed to start scheduler daemon${stderr ? `: ${stderr}` : ""}`
|
|
14419
|
+
);
|
|
14420
|
+
}
|
|
14421
|
+
const pid = Number.parseInt(result.stdout.trim(), 10);
|
|
14422
|
+
if (!Number.isFinite(pid)) {
|
|
14423
|
+
throw createServicemeError(
|
|
14424
|
+
"internal_error",
|
|
14425
|
+
`Failed to parse scheduler daemon PID: ${result.stdout.trim()}`
|
|
14426
|
+
);
|
|
14427
|
+
}
|
|
14428
|
+
return pid;
|
|
14429
|
+
}
|
|
14430
|
+
function quotePowerShellString(value) {
|
|
14431
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
14432
|
+
}
|
|
14433
|
+
function quoteWindowsArgument(value) {
|
|
14434
|
+
return `"${value.replace(/(\\*)"/g, '$1$1\\"').replace(/\\+$/g, "$&$&")}"`;
|
|
14435
|
+
}
|
|
14052
14436
|
function handleStop(parsed) {
|
|
14053
14437
|
const wp = requireWorkspace2(parsed);
|
|
14054
14438
|
if (!getBooleanFlag(parsed, "yes")) {
|
|
@@ -14084,7 +14468,7 @@ function handleStatus(parsed) {
|
|
|
14084
14468
|
let uptimeSeconds = null;
|
|
14085
14469
|
if (pid !== null) {
|
|
14086
14470
|
try {
|
|
14087
|
-
const stat2 =
|
|
14471
|
+
const stat2 = fs8__namespace.statSync(pidMgr.getPidPath());
|
|
14088
14472
|
uptimeSeconds = Math.floor((Date.now() - stat2.mtimeMs) / 1e3);
|
|
14089
14473
|
} catch {
|
|
14090
14474
|
uptimeSeconds = null;
|
|
@@ -14103,6 +14487,10 @@ function handleStatus(parsed) {
|
|
|
14103
14487
|
}
|
|
14104
14488
|
async function runDaemon(parsed) {
|
|
14105
14489
|
const wp = requireWorkspace2(parsed);
|
|
14490
|
+
const logPath = getStringFlag(parsed, "logPath");
|
|
14491
|
+
if (logPath) {
|
|
14492
|
+
process.env.SERVICEME_SCHEDULER_LOG_PATH = logPath;
|
|
14493
|
+
}
|
|
14106
14494
|
const pidMgr = new PidManager(wp);
|
|
14107
14495
|
const existingPid = pidMgr.getRunningPid();
|
|
14108
14496
|
if (existingPid !== null && existingPid !== process.pid) {
|