@serviceme/devtools-core 0.4.1 → 0.4.3
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/index.d.mts +1 -49
- package/dist/index.d.ts +1 -49
- package/dist/index.js +63 -295
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +63 -292
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -4744,7 +4744,7 @@ var PidManager = class {
|
|
|
4744
4744
|
}
|
|
4745
4745
|
};
|
|
4746
4746
|
|
|
4747
|
-
// src/scheduled-tasks/daemon/
|
|
4747
|
+
// src/scheduled-tasks/daemon/SchedulerDaemonV2.ts
|
|
4748
4748
|
import * as fs18 from "fs";
|
|
4749
4749
|
import * as os5 from "os";
|
|
4750
4750
|
import * as path19 from "path";
|
|
@@ -5746,235 +5746,9 @@ var TaskLogManager = class {
|
|
|
5746
5746
|
}
|
|
5747
5747
|
};
|
|
5748
5748
|
|
|
5749
|
-
// src/scheduled-tasks/daemon/
|
|
5749
|
+
// src/scheduled-tasks/daemon/SchedulerDaemonV2.ts
|
|
5750
5750
|
var TICK_INTERVAL = 1e3;
|
|
5751
5751
|
var MIN_SCHEDULE_INTERVAL = 1e3;
|
|
5752
|
-
var SchedulerDaemon = class {
|
|
5753
|
-
constructor(workspacePath, options = {}) {
|
|
5754
|
-
this.tickTimer = null;
|
|
5755
|
-
this.watcher = null;
|
|
5756
|
-
this.running = false;
|
|
5757
|
-
this.startTime = 0;
|
|
5758
|
-
// Track last execution time and running state per task
|
|
5759
|
-
this.lastRun = /* @__PURE__ */ new Map();
|
|
5760
|
-
this.taskRunning = /* @__PURE__ */ new Set();
|
|
5761
|
-
this.workspacePath = workspacePath;
|
|
5762
|
-
const configDir = path19.join(workspacePath, ".serviceme");
|
|
5763
|
-
this.configManager = new TaskConfigManager({
|
|
5764
|
-
configPath: path19.join(configDir, "scheduled-tasks.json")
|
|
5765
|
-
});
|
|
5766
|
-
this.logManager = new TaskLogManager({
|
|
5767
|
-
logPath: path19.join(configDir, "scheduled-tasks-log.json")
|
|
5768
|
-
});
|
|
5769
|
-
this.pidManager = new PidManager(workspacePath);
|
|
5770
|
-
this.logger = new DaemonLogger(workspacePath);
|
|
5771
|
-
this.getExecutor = options.getExecutor ?? getExecutor;
|
|
5772
|
-
}
|
|
5773
|
-
start() {
|
|
5774
|
-
if (this.running) return;
|
|
5775
|
-
this.running = true;
|
|
5776
|
-
this.startTime = Date.now();
|
|
5777
|
-
this.pidManager.writePid(process.pid);
|
|
5778
|
-
const configPath = this.configManager.getConfigPath();
|
|
5779
|
-
const logPath = this.logger.getLogPath();
|
|
5780
|
-
this.logger.log("info", "=".repeat(60));
|
|
5781
|
-
this.logger.log(
|
|
5782
|
-
"info",
|
|
5783
|
-
`Scheduler daemon started
|
|
5784
|
-
PID: ${process.pid}
|
|
5785
|
-
Node: ${process.version}
|
|
5786
|
-
OS: ${os5.type()} ${os5.release()} (${process.arch})
|
|
5787
|
-
Platform: ${process.platform}
|
|
5788
|
-
Hostname: ${os5.hostname()}
|
|
5789
|
-
User: ${os5.userInfo().username}
|
|
5790
|
-
Workspace: ${this.workspacePath}
|
|
5791
|
-
Config: ${configPath}
|
|
5792
|
-
LogPath: ${logPath}
|
|
5793
|
-
ExecPath: ${process.execPath}`
|
|
5794
|
-
);
|
|
5795
|
-
this.tickTimer = setInterval(() => this.tick(), TICK_INTERVAL);
|
|
5796
|
-
this.setupConfigWatch();
|
|
5797
|
-
process.on("SIGTERM", () => this.stop());
|
|
5798
|
-
process.on("SIGINT", () => this.stop());
|
|
5799
|
-
}
|
|
5800
|
-
stop() {
|
|
5801
|
-
if (!this.running) return;
|
|
5802
|
-
this.running = false;
|
|
5803
|
-
if (this.tickTimer) {
|
|
5804
|
-
clearInterval(this.tickTimer);
|
|
5805
|
-
this.tickTimer = null;
|
|
5806
|
-
}
|
|
5807
|
-
if (this.watcher) {
|
|
5808
|
-
this.watcher.close();
|
|
5809
|
-
this.watcher = null;
|
|
5810
|
-
}
|
|
5811
|
-
this.pidManager.removePid();
|
|
5812
|
-
this.logger.log("info", "Scheduler daemon stopped");
|
|
5813
|
-
process.exit(0);
|
|
5814
|
-
}
|
|
5815
|
-
setupConfigWatch() {
|
|
5816
|
-
const configPath = this.configManager.getConfigPath();
|
|
5817
|
-
const dir = configPath.substring(0, configPath.lastIndexOf("/"));
|
|
5818
|
-
try {
|
|
5819
|
-
if (fs18.existsSync(dir)) {
|
|
5820
|
-
this.watcher = fs18.watch(dir, (_eventType, filename) => {
|
|
5821
|
-
if (filename === "scheduled-tasks.json") {
|
|
5822
|
-
this.logger.log("info", "Config file changed, reconciling...");
|
|
5823
|
-
}
|
|
5824
|
-
});
|
|
5825
|
-
}
|
|
5826
|
-
} catch {
|
|
5827
|
-
this.logger.log("warn", "Could not watch config directory");
|
|
5828
|
-
}
|
|
5829
|
-
}
|
|
5830
|
-
tick() {
|
|
5831
|
-
const config = this.configManager.readConfig();
|
|
5832
|
-
const now = Date.now();
|
|
5833
|
-
for (const task of config.tasks) {
|
|
5834
|
-
if (!task.enabled) continue;
|
|
5835
|
-
if (this.taskRunning.has(task.id)) continue;
|
|
5836
|
-
let lastExec = this.lastRun.get(task.id);
|
|
5837
|
-
if (lastExec === void 0) {
|
|
5838
|
-
this.lastRun.set(task.id, now);
|
|
5839
|
-
lastExec = now;
|
|
5840
|
-
}
|
|
5841
|
-
if (this.shouldRun(task, lastExec, now)) {
|
|
5842
|
-
this.executeTask(task, now);
|
|
5843
|
-
}
|
|
5844
|
-
}
|
|
5845
|
-
}
|
|
5846
|
-
shouldRun(task, lastExec, now) {
|
|
5847
|
-
if (task.scheduleType === "interval") {
|
|
5848
|
-
const intervalMs = parseIntervalMs(task.schedule);
|
|
5849
|
-
if (intervalMs < MIN_SCHEDULE_INTERVAL) return false;
|
|
5850
|
-
return now - lastExec >= intervalMs;
|
|
5851
|
-
}
|
|
5852
|
-
if (task.scheduleType === "cron") {
|
|
5853
|
-
if (now - lastExec < 6e4) return false;
|
|
5854
|
-
return matchesCron(task.schedule, new Date(now));
|
|
5855
|
-
}
|
|
5856
|
-
return false;
|
|
5857
|
-
}
|
|
5858
|
-
async executeTask(task, now) {
|
|
5859
|
-
this.taskRunning.add(task.id);
|
|
5860
|
-
this.lastRun.set(task.id, now);
|
|
5861
|
-
const startedAt = new Date(now).toISOString();
|
|
5862
|
-
const startMs = Date.now();
|
|
5863
|
-
this.logger.log(
|
|
5864
|
-
"info",
|
|
5865
|
-
`Executing task: ${task.name} (${task.id})
|
|
5866
|
-
type: ${task.taskType}
|
|
5867
|
-
schedule: ${task.schedule} (${task.scheduleType})
|
|
5868
|
-
enabled: ${task.enabled}`
|
|
5869
|
-
);
|
|
5870
|
-
try {
|
|
5871
|
-
const executionPayload = resolveTaskExecutionPayload(
|
|
5872
|
-
task.taskType,
|
|
5873
|
-
task.payload,
|
|
5874
|
-
this.workspacePath
|
|
5875
|
-
);
|
|
5876
|
-
validateTaskPayload(task.taskType, executionPayload);
|
|
5877
|
-
const executor = this.getExecutor(task.taskType);
|
|
5878
|
-
const result = await executor.execute(executionPayload);
|
|
5879
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5880
|
-
const durationMs = Date.now() - startMs;
|
|
5881
|
-
this.logManager.appendLog({
|
|
5882
|
-
taskId: task.id,
|
|
5883
|
-
taskName: task.name,
|
|
5884
|
-
startedAt,
|
|
5885
|
-
finishedAt,
|
|
5886
|
-
status: result.status === "running" ? "failure" : result.status,
|
|
5887
|
-
output: result.output,
|
|
5888
|
-
error: result.error
|
|
5889
|
-
});
|
|
5890
|
-
const outputBytes = result.output ? Buffer.byteLength(result.output) : 0;
|
|
5891
|
-
this.logger.log(
|
|
5892
|
-
"info",
|
|
5893
|
-
`Task completed: ${task.name} (${task.id})
|
|
5894
|
-
status: ${result.status}
|
|
5895
|
-
duration: ${durationMs}ms
|
|
5896
|
-
outputBytes: ${outputBytes}`
|
|
5897
|
-
);
|
|
5898
|
-
} catch (err) {
|
|
5899
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5900
|
-
const durationMs = Date.now() - startMs;
|
|
5901
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
5902
|
-
this.logManager.appendLog({
|
|
5903
|
-
taskId: task.id,
|
|
5904
|
-
taskName: task.name,
|
|
5905
|
-
startedAt,
|
|
5906
|
-
finishedAt,
|
|
5907
|
-
status: "failure",
|
|
5908
|
-
error: message
|
|
5909
|
-
});
|
|
5910
|
-
this.logger.log(
|
|
5911
|
-
"error",
|
|
5912
|
-
`Task failed: ${task.name} (${task.id})
|
|
5913
|
-
duration: ${durationMs}ms
|
|
5914
|
-
error: ${message}`
|
|
5915
|
-
);
|
|
5916
|
-
} finally {
|
|
5917
|
-
this.taskRunning.delete(task.id);
|
|
5918
|
-
}
|
|
5919
|
-
}
|
|
5920
|
-
getStatus() {
|
|
5921
|
-
const config = this.configManager.readConfig();
|
|
5922
|
-
return {
|
|
5923
|
-
running: this.running,
|
|
5924
|
-
pid: process.pid,
|
|
5925
|
-
uptimeSeconds: this.running ? Math.floor((Date.now() - this.startTime) / 1e3) : null,
|
|
5926
|
-
tasksRegistered: config.tasks.length,
|
|
5927
|
-
tasksEnabled: config.tasks.filter((t) => t.enabled).length,
|
|
5928
|
-
workspacePath: this.workspacePath,
|
|
5929
|
-
pidFile: this.pidManager.getPidPath()
|
|
5930
|
-
};
|
|
5931
|
-
}
|
|
5932
|
-
};
|
|
5933
|
-
function parseIntervalMs(schedule) {
|
|
5934
|
-
const match = /^every\s+(\d+)\s*(s|sec|m|min|h|hr|d|day)s?$/i.exec(schedule);
|
|
5935
|
-
if (!match) return 0;
|
|
5936
|
-
const [, numStr, unit] = match;
|
|
5937
|
-
const num = Number.parseInt(numStr ?? "0", 10);
|
|
5938
|
-
switch (unit?.toLowerCase()) {
|
|
5939
|
-
case "s":
|
|
5940
|
-
case "sec":
|
|
5941
|
-
return num * 1e3;
|
|
5942
|
-
case "m":
|
|
5943
|
-
case "min":
|
|
5944
|
-
return num * 60 * 1e3;
|
|
5945
|
-
case "h":
|
|
5946
|
-
case "hr":
|
|
5947
|
-
return num * 60 * 60 * 1e3;
|
|
5948
|
-
case "d":
|
|
5949
|
-
case "day":
|
|
5950
|
-
return num * 24 * 60 * 60 * 1e3;
|
|
5951
|
-
default:
|
|
5952
|
-
return 0;
|
|
5953
|
-
}
|
|
5954
|
-
}
|
|
5955
|
-
function matchesCron(expression, date) {
|
|
5956
|
-
const parts = expression.trim().split(/\s+/);
|
|
5957
|
-
if (parts.length < 5) return false;
|
|
5958
|
-
const [minPart, hourPart, dayPart, monthPart, weekdayPart] = parts;
|
|
5959
|
-
if (!minPart || !hourPart || !dayPart || !monthPart || !weekdayPart) return false;
|
|
5960
|
-
return matchCronField(minPart, date.getMinutes()) && matchCronField(hourPart, date.getHours()) && matchCronField(dayPart, date.getDate()) && matchCronField(monthPart, date.getMonth() + 1) && matchCronField(weekdayPart, date.getDay());
|
|
5961
|
-
}
|
|
5962
|
-
function matchCronField(field, value) {
|
|
5963
|
-
if (field === "*") return true;
|
|
5964
|
-
if (field.startsWith("*/")) {
|
|
5965
|
-
const step = Number.parseInt(field.slice(2), 10);
|
|
5966
|
-
return step > 0 && value % step === 0;
|
|
5967
|
-
}
|
|
5968
|
-
const values = field.split(",");
|
|
5969
|
-
return values.some((v) => Number.parseInt(v, 10) === value);
|
|
5970
|
-
}
|
|
5971
|
-
|
|
5972
|
-
// src/scheduled-tasks/daemon/SchedulerDaemonV2.ts
|
|
5973
|
-
import * as fs19 from "fs";
|
|
5974
|
-
import * as os6 from "os";
|
|
5975
|
-
import * as path20 from "path";
|
|
5976
|
-
var TICK_INTERVAL2 = 1e3;
|
|
5977
|
-
var MIN_SCHEDULE_INTERVAL2 = 1e3;
|
|
5978
5752
|
var SCHEDULER_LOG_FILENAME2 = "scheduler.log";
|
|
5979
5753
|
var SchedulerDaemonV2 = class {
|
|
5980
5754
|
constructor(options = {}) {
|
|
@@ -5991,8 +5765,8 @@ var SchedulerDaemonV2 = class {
|
|
|
5991
5765
|
this.configManager = options.configManager ?? new TaskConfigManager();
|
|
5992
5766
|
this.logManager = options.logManager ?? new TaskLogManager();
|
|
5993
5767
|
this.pidManager = options.pidManager ?? new PidManager("", { pidPath: getSchedulerPidPath() });
|
|
5994
|
-
this.logger = options.logger ?? new DaemonLogger(
|
|
5995
|
-
logPath:
|
|
5768
|
+
this.logger = options.logger ?? new DaemonLogger(os5.homedir(), {
|
|
5769
|
+
logPath: path19.join(path19.dirname(this.pidManager.getPidPath()), SCHEDULER_LOG_FILENAME2)
|
|
5996
5770
|
});
|
|
5997
5771
|
this.getExecutor = options.getExecutor ?? getExecutor;
|
|
5998
5772
|
this.tryAcquireLock = options.tryAcquireLock ?? (() => true);
|
|
@@ -6022,12 +5796,12 @@ var SchedulerDaemonV2 = class {
|
|
|
6022
5796
|
`SchedulerDaemonV2 started
|
|
6023
5797
|
PID: ${process.pid}
|
|
6024
5798
|
Node: ${process.version}
|
|
6025
|
-
OS: ${
|
|
5799
|
+
OS: ${os5.type()} ${os5.release()} (${process.arch})
|
|
6026
5800
|
Config: ${this.configManager.getConfigPath()}
|
|
6027
5801
|
LogPath: ${this.logger.getLogPath()}
|
|
6028
5802
|
PidPath: ${this.pidManager.getPidPath()}`
|
|
6029
5803
|
);
|
|
6030
|
-
this.tickTimer = setInterval(() => this.tick(),
|
|
5804
|
+
this.tickTimer = setInterval(() => this.tick(), TICK_INTERVAL);
|
|
6031
5805
|
process.on("SIGTERM", this.sigtermHandler);
|
|
6032
5806
|
process.on("SIGINT", this.sigintHandler);
|
|
6033
5807
|
}
|
|
@@ -6050,7 +5824,7 @@ var SchedulerDaemonV2 = class {
|
|
|
6050
5824
|
const now = Date.now();
|
|
6051
5825
|
for (const task of config.tasks) {
|
|
6052
5826
|
if (!task.enabled) continue;
|
|
6053
|
-
if (!
|
|
5827
|
+
if (!fs18.existsSync(task.workspace.path)) {
|
|
6054
5828
|
this.disableTaskForMissingWorkspace(task, config);
|
|
6055
5829
|
continue;
|
|
6056
5830
|
}
|
|
@@ -6090,13 +5864,13 @@ var SchedulerDaemonV2 = class {
|
|
|
6090
5864
|
}
|
|
6091
5865
|
shouldRun(task, lastExec, now) {
|
|
6092
5866
|
if (task.scheduleType === "interval") {
|
|
6093
|
-
const intervalMs =
|
|
6094
|
-
if (intervalMs <
|
|
5867
|
+
const intervalMs = parseIntervalMs(task.schedule);
|
|
5868
|
+
if (intervalMs < MIN_SCHEDULE_INTERVAL) return false;
|
|
6095
5869
|
return now - lastExec >= intervalMs;
|
|
6096
5870
|
}
|
|
6097
5871
|
if (task.scheduleType === "cron") {
|
|
6098
5872
|
if (now - lastExec < 6e4) return false;
|
|
6099
|
-
return
|
|
5873
|
+
return matchesCron(task.schedule, new Date(now));
|
|
6100
5874
|
}
|
|
6101
5875
|
return false;
|
|
6102
5876
|
}
|
|
@@ -6167,7 +5941,7 @@ var SchedulerDaemonV2 = class {
|
|
|
6167
5941
|
};
|
|
6168
5942
|
}
|
|
6169
5943
|
};
|
|
6170
|
-
function
|
|
5944
|
+
function parseIntervalMs(schedule) {
|
|
6171
5945
|
const match = /^every\s+(\d+)\s*(s|sec|m|min|h|hr|d|day)s?$/i.exec(schedule);
|
|
6172
5946
|
if (!match) return 0;
|
|
6173
5947
|
const [, numStr, unit] = match;
|
|
@@ -6189,14 +5963,14 @@ function parseIntervalMs2(schedule) {
|
|
|
6189
5963
|
return 0;
|
|
6190
5964
|
}
|
|
6191
5965
|
}
|
|
6192
|
-
function
|
|
5966
|
+
function matchesCron(expression, date) {
|
|
6193
5967
|
const parts = expression.trim().split(/\s+/);
|
|
6194
5968
|
if (parts.length < 5) return false;
|
|
6195
5969
|
const [minPart, hourPart, dayPart, monthPart, weekdayPart] = parts;
|
|
6196
5970
|
if (!minPart || !hourPart || !dayPart || !monthPart || !weekdayPart) return false;
|
|
6197
|
-
return
|
|
5971
|
+
return matchCronField(minPart, date.getMinutes()) && matchCronField(hourPart, date.getHours()) && matchCronField(dayPart, date.getDate()) && matchCronField(monthPart, date.getMonth() + 1) && matchCronField(weekdayPart, date.getDay());
|
|
6198
5972
|
}
|
|
6199
|
-
function
|
|
5973
|
+
function matchCronField(field, value) {
|
|
6200
5974
|
if (field === "*") return true;
|
|
6201
5975
|
if (field.startsWith("*/")) {
|
|
6202
5976
|
const step = Number.parseInt(field.slice(2), 10);
|
|
@@ -6207,21 +5981,21 @@ function matchCronField2(field, value) {
|
|
|
6207
5981
|
}
|
|
6208
5982
|
|
|
6209
5983
|
// src/scheduled-tasks/migration/MigrateToGlobal.ts
|
|
6210
|
-
import * as
|
|
6211
|
-
import * as
|
|
5984
|
+
import * as fs19 from "fs";
|
|
5985
|
+
import * as path20 from "path";
|
|
6212
5986
|
import { isScheduledTasksConfigV1 as isScheduledTasksConfigV12, migrateV1ToV2 as migrateV1ToV22 } from "@serviceme/devtools-protocol";
|
|
6213
5987
|
var WORKSPACE_DIR = ".serviceme";
|
|
6214
5988
|
var V1_FILENAME = "scheduled-tasks.json";
|
|
6215
5989
|
function defaultProbe(workspacePath) {
|
|
6216
5990
|
return {
|
|
6217
5991
|
path: workspacePath,
|
|
6218
|
-
name:
|
|
5992
|
+
name: path20.basename(workspacePath) || workspacePath
|
|
6219
5993
|
};
|
|
6220
5994
|
}
|
|
6221
5995
|
function readV1Config(v1Path) {
|
|
6222
5996
|
let raw;
|
|
6223
5997
|
try {
|
|
6224
|
-
raw =
|
|
5998
|
+
raw = fs19.readFileSync(v1Path, "utf-8");
|
|
6225
5999
|
} catch (err) {
|
|
6226
6000
|
return {
|
|
6227
6001
|
ok: false,
|
|
@@ -6244,27 +6018,27 @@ function readV1Config(v1Path) {
|
|
|
6244
6018
|
}
|
|
6245
6019
|
function safeDelete(filePath) {
|
|
6246
6020
|
try {
|
|
6247
|
-
|
|
6021
|
+
fs19.unlinkSync(filePath);
|
|
6248
6022
|
} catch {
|
|
6249
6023
|
}
|
|
6250
6024
|
}
|
|
6251
6025
|
function ensureDir(filePath) {
|
|
6252
|
-
const dir =
|
|
6253
|
-
if (!
|
|
6254
|
-
|
|
6026
|
+
const dir = path20.dirname(filePath);
|
|
6027
|
+
if (!fs19.existsSync(dir)) {
|
|
6028
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
6255
6029
|
}
|
|
6256
6030
|
}
|
|
6257
6031
|
function readJsonFile(filePath) {
|
|
6258
|
-
if (!
|
|
6032
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
6259
6033
|
try {
|
|
6260
|
-
return JSON.parse(
|
|
6034
|
+
return JSON.parse(fs19.readFileSync(filePath, "utf-8"));
|
|
6261
6035
|
} catch {
|
|
6262
6036
|
return null;
|
|
6263
6037
|
}
|
|
6264
6038
|
}
|
|
6265
6039
|
function writeJsonFile(filePath, data) {
|
|
6266
6040
|
ensureDir(filePath);
|
|
6267
|
-
|
|
6041
|
+
fs19.writeFileSync(filePath, JSON.stringify(data, null, " "), "utf-8");
|
|
6268
6042
|
}
|
|
6269
6043
|
function disambiguateName(task, existingNames, workspaceName) {
|
|
6270
6044
|
if (!existingNames.has(task.name)) {
|
|
@@ -6294,8 +6068,8 @@ async function migrateToGlobal(options) {
|
|
|
6294
6068
|
const conflicts = [];
|
|
6295
6069
|
const issues = [];
|
|
6296
6070
|
for (const workspacePath of options.workspacePaths) {
|
|
6297
|
-
const v1Path =
|
|
6298
|
-
if (!
|
|
6071
|
+
const v1Path = path20.join(workspacePath, WORKSPACE_DIR, V1_FILENAME);
|
|
6072
|
+
if (!fs19.existsSync(v1Path)) continue;
|
|
6299
6073
|
const v1 = readV1Config(v1Path);
|
|
6300
6074
|
if (!v1.ok) {
|
|
6301
6075
|
failures.push({
|
|
@@ -6337,8 +6111,8 @@ async function migrateToGlobal(options) {
|
|
|
6337
6111
|
if (migrated > 0) {
|
|
6338
6112
|
ensureDir(globalConfigPath);
|
|
6339
6113
|
const tmp = `${globalConfigPath}.tmp`;
|
|
6340
|
-
|
|
6341
|
-
|
|
6114
|
+
fs19.writeFileSync(tmp, JSON.stringify(baseConfig, null, " "), "utf-8");
|
|
6115
|
+
fs19.renameSync(tmp, globalConfigPath);
|
|
6342
6116
|
}
|
|
6343
6117
|
if (failures.length > priorFailures.length) {
|
|
6344
6118
|
writeJsonFile(migrationFailuresPath, failures);
|
|
@@ -6355,8 +6129,8 @@ async function migrateToGlobal(options) {
|
|
|
6355
6129
|
|
|
6356
6130
|
// src/scheduled-tasks/workspace-probe/WorkspaceProbe.ts
|
|
6357
6131
|
import { spawn as spawn5 } from "child_process";
|
|
6358
|
-
import * as
|
|
6359
|
-
import * as
|
|
6132
|
+
import * as fs20 from "fs";
|
|
6133
|
+
import * as path21 from "path";
|
|
6360
6134
|
var DEFAULT_TIMEOUT_MS5 = 2e3;
|
|
6361
6135
|
var GitTimeoutError = class extends Error {
|
|
6362
6136
|
constructor() {
|
|
@@ -6419,8 +6193,8 @@ var WorkspaceProbe = class {
|
|
|
6419
6193
|
}
|
|
6420
6194
|
}
|
|
6421
6195
|
async probe(workspacePath) {
|
|
6422
|
-
const name =
|
|
6423
|
-
if (!workspacePath || !
|
|
6196
|
+
const name = path21.basename(workspacePath) || workspacePath;
|
|
6197
|
+
if (!workspacePath || !fs20.existsSync(workspacePath)) {
|
|
6424
6198
|
return {
|
|
6425
6199
|
workspace: { path: workspacePath, name },
|
|
6426
6200
|
error: "path-not-found"
|
|
@@ -6572,8 +6346,8 @@ var SkillReconciler = class {
|
|
|
6572
6346
|
};
|
|
6573
6347
|
|
|
6574
6348
|
// src/skills/SkillStore.ts
|
|
6575
|
-
import * as
|
|
6576
|
-
import * as
|
|
6349
|
+
import * as fs21 from "fs/promises";
|
|
6350
|
+
import * as path22 from "path";
|
|
6577
6351
|
var USER_SKILL_MARKER_FILE = ".serviceme-skill.json";
|
|
6578
6352
|
var LEGACY_USER_SKILL_MARKER_FILE = ".ms-devtools-skill.json";
|
|
6579
6353
|
var WORKSPACE_SKILLS_ROOT_RELATIVE = ".github/skills";
|
|
@@ -6589,7 +6363,7 @@ var SkillStore = class {
|
|
|
6589
6363
|
constructor(options) {
|
|
6590
6364
|
this.workspacePath = options.workspacePath;
|
|
6591
6365
|
this.userSkillsRoot = options.userSkillsRoot;
|
|
6592
|
-
this.fileSystem = options.fileSystem ??
|
|
6366
|
+
this.fileSystem = options.fileSystem ?? fs21;
|
|
6593
6367
|
}
|
|
6594
6368
|
normalizeRemoteSkillId(remoteId) {
|
|
6595
6369
|
if (remoteId.startsWith("official/")) {
|
|
@@ -6608,10 +6382,10 @@ var SkillStore = class {
|
|
|
6608
6382
|
return WORKSPACE_SKILLS_MARKER_RELATIVE;
|
|
6609
6383
|
}
|
|
6610
6384
|
getUserSkillPath(skillId) {
|
|
6611
|
-
return
|
|
6385
|
+
return path22.join(this.userSkillsRoot, skillId);
|
|
6612
6386
|
}
|
|
6613
6387
|
async listWorkspaceSkillIds() {
|
|
6614
|
-
const skillsRootPath =
|
|
6388
|
+
const skillsRootPath = path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE);
|
|
6615
6389
|
try {
|
|
6616
6390
|
const entries = await this.fileSystem.readdir(skillsRootPath, {
|
|
6617
6391
|
withFileTypes: true
|
|
@@ -6635,7 +6409,7 @@ var SkillStore = class {
|
|
|
6635
6409
|
const targetDir = this.getUserSkillPath(skillId);
|
|
6636
6410
|
await this.fileSystem.mkdir(targetDir, { recursive: true });
|
|
6637
6411
|
await this.fileSystem.writeFile(
|
|
6638
|
-
|
|
6412
|
+
path22.join(targetDir, USER_SKILL_MARKER_FILE),
|
|
6639
6413
|
JSON.stringify({ skillId, installedBy: "serviceme" }, null, 2),
|
|
6640
6414
|
"utf-8"
|
|
6641
6415
|
);
|
|
@@ -6644,7 +6418,7 @@ var SkillStore = class {
|
|
|
6644
6418
|
await this.migrateLegacyUserSkillMarker(skillId);
|
|
6645
6419
|
try {
|
|
6646
6420
|
const marker = await this.fileSystem.readFile(
|
|
6647
|
-
|
|
6421
|
+
path22.join(this.getUserSkillPath(skillId), USER_SKILL_MARKER_FILE),
|
|
6648
6422
|
"utf-8"
|
|
6649
6423
|
);
|
|
6650
6424
|
const parsed = JSON.parse(marker);
|
|
@@ -6661,8 +6435,8 @@ var SkillStore = class {
|
|
|
6661
6435
|
*/
|
|
6662
6436
|
async migrateLegacyUserSkillMarker(skillId) {
|
|
6663
6437
|
const targetDir = this.getUserSkillPath(skillId);
|
|
6664
|
-
const newPath =
|
|
6665
|
-
const legacyPath =
|
|
6438
|
+
const newPath = path22.join(targetDir, USER_SKILL_MARKER_FILE);
|
|
6439
|
+
const legacyPath = path22.join(targetDir, LEGACY_USER_SKILL_MARKER_FILE);
|
|
6666
6440
|
try {
|
|
6667
6441
|
await this.fileSystem.readFile(newPath, "utf-8");
|
|
6668
6442
|
return;
|
|
@@ -6675,12 +6449,12 @@ var SkillStore = class {
|
|
|
6675
6449
|
}
|
|
6676
6450
|
}
|
|
6677
6451
|
async writeSkillFiles(skillId, scope, files) {
|
|
6678
|
-
const root = scope === "workspace" ?
|
|
6679
|
-
const targetDir =
|
|
6452
|
+
const root = scope === "workspace" ? path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
|
|
6453
|
+
const targetDir = path22.join(root, skillId);
|
|
6680
6454
|
await this.fileSystem.mkdir(targetDir, { recursive: true });
|
|
6681
6455
|
for (const file of files) {
|
|
6682
|
-
const filePath =
|
|
6683
|
-
await this.fileSystem.mkdir(
|
|
6456
|
+
const filePath = path22.join(targetDir, file.path);
|
|
6457
|
+
await this.fileSystem.mkdir(path22.dirname(filePath), { recursive: true });
|
|
6684
6458
|
await this.fileSystem.writeFile(filePath, file.content, "utf-8");
|
|
6685
6459
|
if (file.executable) {
|
|
6686
6460
|
try {
|
|
@@ -6693,8 +6467,8 @@ var SkillStore = class {
|
|
|
6693
6467
|
};
|
|
6694
6468
|
|
|
6695
6469
|
// src/submit/index.ts
|
|
6696
|
-
import * as
|
|
6697
|
-
import * as
|
|
6470
|
+
import * as fs22 from "fs/promises";
|
|
6471
|
+
import * as path23 from "path";
|
|
6698
6472
|
|
|
6699
6473
|
// src/submit/types.ts
|
|
6700
6474
|
var SubmitError = class extends Error {
|
|
@@ -6744,14 +6518,14 @@ var SubmitClient = class {
|
|
|
6744
6518
|
throw new SubmitError(v.reason ?? "unknown", v.detail ?? "validation denied");
|
|
6745
6519
|
}
|
|
6746
6520
|
const localRepoPath = getRepoDir(repoId);
|
|
6747
|
-
const targetDir =
|
|
6748
|
-
await
|
|
6521
|
+
const targetDir = path23.join(localRepoPath, "skills", skillName);
|
|
6522
|
+
await fs22.mkdir(targetDir, { recursive: true });
|
|
6749
6523
|
for (const f of files) {
|
|
6750
|
-
const full =
|
|
6751
|
-
await
|
|
6524
|
+
const full = path23.join(targetDir, f.path);
|
|
6525
|
+
await fs22.mkdir(path23.dirname(full), { recursive: true });
|
|
6752
6526
|
const tmp = `${full}.${process.pid}.${Date.now()}.tmp`;
|
|
6753
|
-
await
|
|
6754
|
-
await
|
|
6527
|
+
await fs22.writeFile(tmp, f.content, "utf8");
|
|
6528
|
+
await fs22.rename(tmp, full);
|
|
6755
6529
|
}
|
|
6756
6530
|
const commitMessage = `feat(skills): add ${skillName}`;
|
|
6757
6531
|
const { commitSha } = await this.git.commit(localRepoPath, commitMessage);
|
|
@@ -6820,7 +6594,7 @@ function touchLastUsedAt(tools, id, when = /* @__PURE__ */ new Date()) {
|
|
|
6820
6594
|
|
|
6821
6595
|
// src/toolbox/ToolboxStore.ts
|
|
6822
6596
|
import * as fsp2 from "fs/promises";
|
|
6823
|
-
import * as
|
|
6597
|
+
import * as path24 from "path";
|
|
6824
6598
|
import { setTimeout as delay2 } from "timers/promises";
|
|
6825
6599
|
|
|
6826
6600
|
// src/toolbox/types.ts
|
|
@@ -6856,11 +6630,11 @@ var DEFAULT_LOCK_TIMEOUT_MS2 = 5e3;
|
|
|
6856
6630
|
var DEFAULT_LOCK_RETRY_MS2 = 25;
|
|
6857
6631
|
var LOCK_STALE_GRACE_MS2 = 200;
|
|
6858
6632
|
var TMP_SUFFIX2 = ".tmp";
|
|
6859
|
-
var WORKSPACE_TOOLBOX_RELATIVE_PATH =
|
|
6633
|
+
var WORKSPACE_TOOLBOX_RELATIVE_PATH = path24.join(".github", ".serviceme-toolbox.json");
|
|
6860
6634
|
var LEGACY_WORKSPACE_TOOLBOX_FILENAME = ".ms-devtools-toolbox.json";
|
|
6861
6635
|
async function migrateLegacyWorkspaceToolboxFile(filePath) {
|
|
6862
6636
|
if (!filePath) return;
|
|
6863
|
-
const legacyPath =
|
|
6637
|
+
const legacyPath = path24.join(path24.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
|
|
6864
6638
|
if (legacyPath === filePath) return;
|
|
6865
6639
|
try {
|
|
6866
6640
|
await fsp2.access(filePath);
|
|
@@ -6909,15 +6683,15 @@ var FsToolboxFileBackend = class {
|
|
|
6909
6683
|
}
|
|
6910
6684
|
}
|
|
6911
6685
|
async purgeExcessBackups(filePath) {
|
|
6912
|
-
const dir =
|
|
6913
|
-
const base =
|
|
6686
|
+
const dir = path24.dirname(filePath);
|
|
6687
|
+
const base = path24.basename(filePath);
|
|
6914
6688
|
let entries;
|
|
6915
6689
|
try {
|
|
6916
6690
|
entries = await fsp2.readdir(dir);
|
|
6917
6691
|
} catch {
|
|
6918
6692
|
return;
|
|
6919
6693
|
}
|
|
6920
|
-
const backups = entries.filter((n) => n.startsWith(base) && n.endsWith(".bak")).map((n) => ({ name: n, filePath:
|
|
6694
|
+
const backups = entries.filter((n) => n.startsWith(base) && n.endsWith(".bak")).map((n) => ({ name: n, filePath: path24.join(dir, n) })).sort((a, b) => {
|
|
6921
6695
|
return a.name.localeCompare(b.name);
|
|
6922
6696
|
});
|
|
6923
6697
|
const excess = backups.length - this.maxBackupCount;
|
|
@@ -6927,7 +6701,7 @@ var FsToolboxFileBackend = class {
|
|
|
6927
6701
|
);
|
|
6928
6702
|
}
|
|
6929
6703
|
async write(filePath, payload) {
|
|
6930
|
-
await fsp2.mkdir(
|
|
6704
|
+
await fsp2.mkdir(path24.dirname(filePath), { recursive: true });
|
|
6931
6705
|
const tmpPath = `${filePath}${TMP_SUFFIX2}`;
|
|
6932
6706
|
const bytes = Buffer.from(JSON.stringify(payload, null, " "), "utf8");
|
|
6933
6707
|
await fsp2.rm(tmpPath, { force: true });
|
|
@@ -6971,7 +6745,7 @@ var ToolboxFileLock = class {
|
|
|
6971
6745
|
constructor(filePath, timeoutMs, retryMs) {
|
|
6972
6746
|
this.acquired = false;
|
|
6973
6747
|
this.dirPath = `${filePath}.lock`;
|
|
6974
|
-
this.pidFilePath =
|
|
6748
|
+
this.pidFilePath = path24.join(this.dirPath, "pid");
|
|
6975
6749
|
this.timeoutMs = timeoutMs;
|
|
6976
6750
|
this.retryMs = retryMs;
|
|
6977
6751
|
}
|
|
@@ -7021,7 +6795,7 @@ var ToolboxFileLock = class {
|
|
|
7021
6795
|
};
|
|
7022
6796
|
function defaultWorkspacePath() {
|
|
7023
6797
|
if (process.env.SERVICEME_NO_WORKSPACE_TOOLBOX === "1") return null;
|
|
7024
|
-
return
|
|
6798
|
+
return path24.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
|
|
7025
6799
|
}
|
|
7026
6800
|
var ToolboxStore = class {
|
|
7027
6801
|
constructor(opts = {}) {
|
|
@@ -7333,7 +7107,6 @@ export {
|
|
|
7333
7107
|
SERVICEME_DIR_NAME,
|
|
7334
7108
|
SERVICEME_HOME_ENV,
|
|
7335
7109
|
SKILL_DRAFTS_SUBDIR,
|
|
7336
|
-
SchedulerDaemon,
|
|
7337
7110
|
SchedulerDaemonV2,
|
|
7338
7111
|
ShellExecutor,
|
|
7339
7112
|
SkillCatalogClient,
|
|
@@ -7407,7 +7180,6 @@ export {
|
|
|
7407
7180
|
isGitHubLocalEmail,
|
|
7408
7181
|
isStreamingTaskExecutor,
|
|
7409
7182
|
isUserRepo,
|
|
7410
|
-
matchesCron,
|
|
7411
7183
|
mergeWithDefaults,
|
|
7412
7184
|
migrateLegacyServerProxyEnabled,
|
|
7413
7185
|
migrateToGlobal,
|
|
@@ -7415,7 +7187,6 @@ export {
|
|
|
7415
7187
|
narrowRepoConfig,
|
|
7416
7188
|
noopLogger,
|
|
7417
7189
|
parseAgentToolPermissions,
|
|
7418
|
-
parseIntervalMs,
|
|
7419
7190
|
randomInstallationId,
|
|
7420
7191
|
readServerProxyGlobal,
|
|
7421
7192
|
reindexOrder,
|