@serviceme/devtools-core 0.3.1 → 0.3.2
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/device.js.map +1 -1
- package/dist/device.mjs.map +1 -1
- package/dist/index.d.mts +100 -21
- package/dist/index.d.ts +100 -21
- package/dist/index.js +266 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -162
- package/dist/index.mjs.map +1 -1
- package/dist/skill-linker.js.map +1 -1
- package/dist/skill-linker.mjs.map +1 -1
- package/dist/submit.js.map +1 -1
- package/dist/submit.mjs.map +1 -1
- package/dist/toolbox.js.map +1 -1
- package/dist/toolbox.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1671,6 +1671,7 @@ var DRAFTS_SUBDIR = "drafts";
|
|
|
1671
1671
|
var SKILL_DRAFTS_SUBDIR = "skills";
|
|
1672
1672
|
var AGENT_DRAFTS_SUBDIR = "agents";
|
|
1673
1673
|
var REPOS_CONFIG_FILENAME = "repos.json";
|
|
1674
|
+
var SERVER_PROXY_GLOBAL_FILENAME = "server-proxy.json";
|
|
1674
1675
|
var SAFE_REPO_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
|
|
1675
1676
|
var SERVICEME_HOME_ENV = "SERVICEME_HOME";
|
|
1676
1677
|
var activeOverrides = {};
|
|
@@ -1771,6 +1772,9 @@ function getMigrationFailuresPath() {
|
|
|
1771
1772
|
function getKnownWorkspacesPath() {
|
|
1772
1773
|
return path2.join(getServicemeHome(), KNOWN_WORKSPACES_FILENAME);
|
|
1773
1774
|
}
|
|
1775
|
+
function getServerProxyGlobalPath() {
|
|
1776
|
+
return path2.join(getServicemeHome(), SERVER_PROXY_GLOBAL_FILENAME);
|
|
1777
|
+
}
|
|
1774
1778
|
var CREDENTIALS_CONFIG_FILENAME = "credentials.json";
|
|
1775
1779
|
var DEVICE_JSON_FILENAME = "device.json";
|
|
1776
1780
|
var TOOLBOX_JSON_FILENAME = "toolbox.json";
|
|
@@ -3017,10 +3021,85 @@ function createConsoleLogger(prefix = "serviceme") {
|
|
|
3017
3021
|
};
|
|
3018
3022
|
}
|
|
3019
3023
|
|
|
3020
|
-
// src/
|
|
3024
|
+
// src/paths/serverProxyGlobal.ts
|
|
3021
3025
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3022
3026
|
import * as fs6 from "fs/promises";
|
|
3027
|
+
import { open as open2 } from "fs/promises";
|
|
3023
3028
|
import * as path9 from "path";
|
|
3029
|
+
async function readServerProxyGlobal() {
|
|
3030
|
+
const filePath = getServerProxyGlobalPath();
|
|
3031
|
+
try {
|
|
3032
|
+
const raw = await fs6.readFile(filePath, "utf8");
|
|
3033
|
+
const parsed = JSON.parse(raw);
|
|
3034
|
+
if (!isServerProxyGlobalState(parsed)) {
|
|
3035
|
+
throw new Error(
|
|
3036
|
+
`Invalid ${SERVER_PROXY_GLOBAL_FILENAME}: expected {enabled: boolean, lastServerUrl?: string, updatedAt: string}, got ${JSON.stringify(parsed).slice(0, 80)}`
|
|
3037
|
+
);
|
|
3038
|
+
}
|
|
3039
|
+
return parsed;
|
|
3040
|
+
} catch (err) {
|
|
3041
|
+
if (isENOENT(err)) return null;
|
|
3042
|
+
throw err;
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
async function writeServerProxyGlobal(patch) {
|
|
3046
|
+
const filePath = getServerProxyGlobalPath();
|
|
3047
|
+
const dirPath = path9.dirname(filePath);
|
|
3048
|
+
await fs6.mkdir(dirPath, { recursive: true });
|
|
3049
|
+
const current = await readServerProxyGlobal() ?? {
|
|
3050
|
+
enabled: false,
|
|
3051
|
+
allowOverride: false,
|
|
3052
|
+
lastServerUrl: void 0,
|
|
3053
|
+
updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
3054
|
+
};
|
|
3055
|
+
const next = {
|
|
3056
|
+
enabled: patch.enabled !== void 0 ? patch.enabled : current.enabled,
|
|
3057
|
+
allowOverride: patch.allowOverride !== void 0 ? patch.allowOverride : current.allowOverride,
|
|
3058
|
+
lastServerUrl: patch.lastServerUrl === void 0 ? current.lastServerUrl : patch.lastServerUrl === null ? void 0 : patch.lastServerUrl,
|
|
3059
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3060
|
+
};
|
|
3061
|
+
const tmpPath = `${filePath}.tmp-${randomUUID2()}`;
|
|
3062
|
+
const fh = await open2(tmpPath, "w");
|
|
3063
|
+
try {
|
|
3064
|
+
await fh.writeFile(JSON.stringify(next, null, " "), "utf8");
|
|
3065
|
+
await fh.sync();
|
|
3066
|
+
} finally {
|
|
3067
|
+
await fh.close();
|
|
3068
|
+
}
|
|
3069
|
+
await fs6.rename(tmpPath, filePath);
|
|
3070
|
+
return next;
|
|
3071
|
+
}
|
|
3072
|
+
async function migrateLegacyServerProxyEnabled(readLegacy, clearLegacy) {
|
|
3073
|
+
const legacyEnabled = readLegacy();
|
|
3074
|
+
if (legacyEnabled !== true) return null;
|
|
3075
|
+
const existing = await readServerProxyGlobal();
|
|
3076
|
+
if (existing?.enabled === true) {
|
|
3077
|
+
await clearLegacy();
|
|
3078
|
+
return null;
|
|
3079
|
+
}
|
|
3080
|
+
const next = await writeServerProxyGlobal({ enabled: true });
|
|
3081
|
+
await clearLegacy();
|
|
3082
|
+
return next;
|
|
3083
|
+
}
|
|
3084
|
+
function isServerProxyGlobalState(v) {
|
|
3085
|
+
if (!v || typeof v !== "object") return false;
|
|
3086
|
+
const obj = v;
|
|
3087
|
+
if (typeof obj.enabled !== "boolean") return false;
|
|
3088
|
+
if (typeof obj.allowOverride !== "boolean") return false;
|
|
3089
|
+
if (typeof obj.updatedAt !== "string") return false;
|
|
3090
|
+
if (obj.lastServerUrl !== void 0 && obj.lastServerUrl !== null && typeof obj.lastServerUrl !== "string") {
|
|
3091
|
+
return false;
|
|
3092
|
+
}
|
|
3093
|
+
return true;
|
|
3094
|
+
}
|
|
3095
|
+
function isENOENT(err) {
|
|
3096
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
// src/phase5/bootstrap.ts
|
|
3100
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
3101
|
+
import * as fs7 from "fs/promises";
|
|
3102
|
+
import * as path10 from "path";
|
|
3024
3103
|
function getPhase5FileSpecs() {
|
|
3025
3104
|
return [
|
|
3026
3105
|
{
|
|
@@ -3051,7 +3130,7 @@ function getPhase5FileSpecs() {
|
|
|
3051
3130
|
path: getMachineIdPath(),
|
|
3052
3131
|
// Random uuid, written as a bare string. Subsequent
|
|
3053
3132
|
// activations see the file and skip re-randomizing.
|
|
3054
|
-
defaultContent:
|
|
3133
|
+
defaultContent: randomUUID3()
|
|
3055
3134
|
},
|
|
3056
3135
|
{
|
|
3057
3136
|
path: getProfilesJsonPath(),
|
|
@@ -3065,19 +3144,19 @@ async function bootstrapPhase5Placeholders() {
|
|
|
3065
3144
|
const result = { created: [], skipped: [], failed: [] };
|
|
3066
3145
|
const home = getServicemeHome();
|
|
3067
3146
|
try {
|
|
3068
|
-
await
|
|
3147
|
+
await fs7.mkdir(home, { recursive: true });
|
|
3069
3148
|
} catch (err) {
|
|
3070
3149
|
result.failed.push({ path: home, reason: err.message });
|
|
3071
3150
|
return result;
|
|
3072
3151
|
}
|
|
3073
3152
|
for (const spec of getPhase5FileSpecs()) {
|
|
3074
3153
|
try {
|
|
3075
|
-
await
|
|
3154
|
+
await fs7.access(spec.path);
|
|
3076
3155
|
result.skipped.push(spec.path);
|
|
3077
3156
|
} catch {
|
|
3078
3157
|
try {
|
|
3079
|
-
await
|
|
3080
|
-
await
|
|
3158
|
+
await fs7.mkdir(path10.dirname(spec.path), { recursive: true });
|
|
3159
|
+
await fs7.writeFile(spec.path, spec.defaultContent, "utf8");
|
|
3081
3160
|
result.created.push(spec.path);
|
|
3082
3161
|
} catch (writeErr) {
|
|
3083
3162
|
result.failed.push({ path: spec.path, reason: writeErr.message });
|
|
@@ -3088,16 +3167,16 @@ async function bootstrapPhase5Placeholders() {
|
|
|
3088
3167
|
}
|
|
3089
3168
|
|
|
3090
3169
|
// src/project/projectTools.ts
|
|
3091
|
-
import * as
|
|
3092
|
-
import * as
|
|
3170
|
+
import * as fs8 from "fs/promises";
|
|
3171
|
+
import * as path11 from "path";
|
|
3093
3172
|
import {
|
|
3094
3173
|
createServicemeError as createServicemeError7
|
|
3095
3174
|
} from "@serviceme/devtools-protocol";
|
|
3096
3175
|
|
|
3097
3176
|
// src/utils/fileUtils.ts
|
|
3098
3177
|
import { constants, createWriteStream } from "fs";
|
|
3099
|
-
import { access as access5, copyFile, lstat, mkdir as
|
|
3100
|
-
import { dirname as
|
|
3178
|
+
import { access as access5, copyFile, lstat, mkdir as mkdir5, readdir as readdir3, rename as rename4, rm as rm3 } from "fs/promises";
|
|
3179
|
+
import { dirname as dirname7, join as join7 } from "path";
|
|
3101
3180
|
import yauzl from "yauzl";
|
|
3102
3181
|
var unzipFile = (zipPath, dest) => {
|
|
3103
3182
|
return new Promise((resolve3, reject) => {
|
|
@@ -3107,12 +3186,12 @@ var unzipFile = (zipPath, dest) => {
|
|
|
3107
3186
|
zipfile.readEntry();
|
|
3108
3187
|
zipfile.on("entry", (entry) => {
|
|
3109
3188
|
if (/\/$/.test(entry.fileName)) {
|
|
3110
|
-
void
|
|
3189
|
+
void mkdir5(join7(dest, entry.fileName), { recursive: true }).then(() => {
|
|
3111
3190
|
zipfile.readEntry();
|
|
3112
3191
|
}).catch(reject);
|
|
3113
3192
|
} else {
|
|
3114
3193
|
const outputPath = join7(dest, entry.fileName);
|
|
3115
|
-
void
|
|
3194
|
+
void mkdir5(dirname7(outputPath), { recursive: true }).then(() => {
|
|
3116
3195
|
zipfile.openReadStream(
|
|
3117
3196
|
entry,
|
|
3118
3197
|
(streamError, readStream) => {
|
|
@@ -3157,7 +3236,7 @@ var mergeEntry = async (sourcePath, destPath, overwrite) => {
|
|
|
3157
3236
|
}
|
|
3158
3237
|
await rm3(destPath, { recursive: true, force: true });
|
|
3159
3238
|
}
|
|
3160
|
-
await
|
|
3239
|
+
await mkdir5(destPath, { recursive: true });
|
|
3161
3240
|
const children = await readdir3(sourcePath);
|
|
3162
3241
|
for (const child of children) {
|
|
3163
3242
|
await mergeEntry(join7(sourcePath, child), join7(destPath, child), overwrite);
|
|
@@ -3173,14 +3252,14 @@ var mergeEntry = async (sourcePath, destPath, overwrite) => {
|
|
|
3173
3252
|
await rm3(destPath, { recursive: true, force: true });
|
|
3174
3253
|
}
|
|
3175
3254
|
try {
|
|
3176
|
-
await
|
|
3255
|
+
await rename4(sourcePath, destPath);
|
|
3177
3256
|
} catch {
|
|
3178
3257
|
await copyFile(sourcePath, destPath);
|
|
3179
3258
|
await rm3(sourcePath, { recursive: true, force: true });
|
|
3180
3259
|
}
|
|
3181
3260
|
};
|
|
3182
3261
|
var moveFiles = async (sourceDir, destDir, overwrite = false) => {
|
|
3183
|
-
await
|
|
3262
|
+
await mkdir5(destDir, { recursive: true });
|
|
3184
3263
|
const files = await readdir3(sourceDir);
|
|
3185
3264
|
for (const file of files) {
|
|
3186
3265
|
const sourceFile = join7(sourceDir, file);
|
|
@@ -3201,10 +3280,10 @@ var moveFiles = async (sourceDir, destDir, overwrite = false) => {
|
|
|
3201
3280
|
var ProjectTools = class {
|
|
3202
3281
|
async extractTemplate(zipPath, workspacePath, tempExtractDir, input) {
|
|
3203
3282
|
await unzipFile(zipPath, tempExtractDir);
|
|
3204
|
-
let sourceDir =
|
|
3283
|
+
let sourceDir = path11.join(tempExtractDir, input.extractedDirName);
|
|
3205
3284
|
let actualDirName = input.extractedDirName;
|
|
3206
3285
|
if (!await this.pathExists(sourceDir)) {
|
|
3207
|
-
const entries = await
|
|
3286
|
+
const entries = await fs8.readdir(tempExtractDir, { withFileTypes: true });
|
|
3208
3287
|
const directories = entries.filter(
|
|
3209
3288
|
(entry) => entry.isDirectory() && !entry.name.startsWith(".")
|
|
3210
3289
|
);
|
|
@@ -3216,7 +3295,7 @@ var ProjectTools = class {
|
|
|
3216
3295
|
);
|
|
3217
3296
|
if (selectedDirectory) {
|
|
3218
3297
|
actualDirName = selectedDirectory;
|
|
3219
|
-
sourceDir =
|
|
3298
|
+
sourceDir = path11.join(tempExtractDir, actualDirName);
|
|
3220
3299
|
} else if (directories.length === 0) {
|
|
3221
3300
|
throw new Error(
|
|
3222
3301
|
`No directory found after extraction. Expected directory: ${input.extractedDirName}`
|
|
@@ -3266,7 +3345,7 @@ var ProjectTools = class {
|
|
|
3266
3345
|
} else {
|
|
3267
3346
|
for (const scriptPath of scripts) {
|
|
3268
3347
|
try {
|
|
3269
|
-
await
|
|
3348
|
+
await fs8.chmod(scriptPath, 493);
|
|
3270
3349
|
updatedCount += 1;
|
|
3271
3350
|
} catch {
|
|
3272
3351
|
}
|
|
@@ -3314,7 +3393,7 @@ var ProjectTools = class {
|
|
|
3314
3393
|
};
|
|
3315
3394
|
}
|
|
3316
3395
|
async ensurePresetManifest(workspacePath, preset) {
|
|
3317
|
-
const presetManifestPath =
|
|
3396
|
+
const presetManifestPath = path11.join(
|
|
3318
3397
|
workspacePath,
|
|
3319
3398
|
".ms-scaffold",
|
|
3320
3399
|
"presets",
|
|
@@ -3323,11 +3402,11 @@ var ProjectTools = class {
|
|
|
3323
3402
|
if (await this.pathExists(presetManifestPath)) {
|
|
3324
3403
|
return;
|
|
3325
3404
|
}
|
|
3326
|
-
const projectModePath =
|
|
3405
|
+
const projectModePath = path11.join(workspacePath, ".ms-scaffold", "project-mode.json");
|
|
3327
3406
|
if (!await this.pathExists(projectModePath)) {
|
|
3328
3407
|
return;
|
|
3329
3408
|
}
|
|
3330
|
-
const projectModeRaw = await
|
|
3409
|
+
const projectModeRaw = await fs8.readFile(projectModePath, "utf8");
|
|
3331
3410
|
const projectMode = JSON.parse(projectModeRaw);
|
|
3332
3411
|
const synthesizedPreset = {
|
|
3333
3412
|
preset,
|
|
@@ -3339,8 +3418,8 @@ var ProjectTools = class {
|
|
|
3339
3418
|
mergeManagedFiles: [],
|
|
3340
3419
|
userOwnedPaths: []
|
|
3341
3420
|
};
|
|
3342
|
-
await
|
|
3343
|
-
await
|
|
3421
|
+
await fs8.mkdir(path11.dirname(presetManifestPath), { recursive: true });
|
|
3422
|
+
await fs8.writeFile(
|
|
3344
3423
|
presetManifestPath,
|
|
3345
3424
|
`${JSON.stringify(synthesizedPreset, null, 2)}
|
|
3346
3425
|
`,
|
|
@@ -3351,12 +3430,12 @@ var ProjectTools = class {
|
|
|
3351
3430
|
const results = [];
|
|
3352
3431
|
let entries;
|
|
3353
3432
|
try {
|
|
3354
|
-
entries = await
|
|
3433
|
+
entries = await fs8.readdir(dir, { withFileTypes: true });
|
|
3355
3434
|
} catch {
|
|
3356
3435
|
return results;
|
|
3357
3436
|
}
|
|
3358
3437
|
for (const entry of entries) {
|
|
3359
|
-
const fullPath =
|
|
3438
|
+
const fullPath = path11.join(dir, entry.name);
|
|
3360
3439
|
if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
|
|
3361
3440
|
results.push(...await this.findScripts(fullPath, extensions));
|
|
3362
3441
|
} else if (entry.isFile() && extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
@@ -3367,7 +3446,7 @@ var ProjectTools = class {
|
|
|
3367
3446
|
}
|
|
3368
3447
|
async pathExists(targetPath) {
|
|
3369
3448
|
try {
|
|
3370
|
-
await
|
|
3449
|
+
await fs8.access(targetPath);
|
|
3371
3450
|
return true;
|
|
3372
3451
|
} catch {
|
|
3373
3452
|
return false;
|
|
@@ -3384,7 +3463,7 @@ var ProjectTools = class {
|
|
|
3384
3463
|
const matches = [];
|
|
3385
3464
|
for (const directoryName of directoryNames) {
|
|
3386
3465
|
if (await this.directoryMatchesProjectPattern(
|
|
3387
|
-
|
|
3466
|
+
path11.join(tempExtractDir, directoryName),
|
|
3388
3467
|
projectFilePattern
|
|
3389
3468
|
)) {
|
|
3390
3469
|
matches.push(directoryName);
|
|
@@ -3396,7 +3475,7 @@ var ProjectTools = class {
|
|
|
3396
3475
|
return null;
|
|
3397
3476
|
}
|
|
3398
3477
|
async directoryMatchesProjectPattern(directoryPath, projectFilePattern) {
|
|
3399
|
-
const entries = await
|
|
3478
|
+
const entries = await fs8.readdir(directoryPath);
|
|
3400
3479
|
if (projectFilePattern.includes("*")) {
|
|
3401
3480
|
const regex = new RegExp(`^${projectFilePattern.replace("*", ".*")}$`);
|
|
3402
3481
|
return entries.some((entry) => regex.test(entry));
|
|
@@ -3409,8 +3488,8 @@ function createProjectTools() {
|
|
|
3409
3488
|
}
|
|
3410
3489
|
|
|
3411
3490
|
// src/repo-manager/index.ts
|
|
3412
|
-
import * as
|
|
3413
|
-
import * as
|
|
3491
|
+
import * as fs9 from "fs/promises";
|
|
3492
|
+
import * as path12 from "path";
|
|
3414
3493
|
|
|
3415
3494
|
// src/repos/types.ts
|
|
3416
3495
|
function isDefaultRepo(repo) {
|
|
@@ -3492,11 +3571,11 @@ var RepoManager = class {
|
|
|
3492
3571
|
const exists = await this.pathExists(localPath);
|
|
3493
3572
|
if (exists) {
|
|
3494
3573
|
if (await this.isValidGitRepo(localPath)) continue;
|
|
3495
|
-
await
|
|
3574
|
+
await fs9.rm(localPath, { recursive: true, force: true });
|
|
3496
3575
|
}
|
|
3497
3576
|
try {
|
|
3498
3577
|
if (!this.skipClone) {
|
|
3499
|
-
await
|
|
3578
|
+
await fs9.mkdir(path12.dirname(localPath), { recursive: true });
|
|
3500
3579
|
await this.git.clone(repo.id, repo.url, localPath, repo.branch, true);
|
|
3501
3580
|
}
|
|
3502
3581
|
await this.store.updateRepo(repo.id, {
|
|
@@ -3531,10 +3610,10 @@ var RepoManager = class {
|
|
|
3531
3610
|
const localPath = getRepoDir(repoId);
|
|
3532
3611
|
const exists = await this.pathExists(localPath);
|
|
3533
3612
|
if (exists && !await this.isValidGitRepo(localPath)) {
|
|
3534
|
-
await
|
|
3613
|
+
await fs9.rm(localPath, { recursive: true, force: true });
|
|
3535
3614
|
}
|
|
3536
3615
|
if (!exists || !await this.pathExists(localPath)) {
|
|
3537
|
-
await
|
|
3616
|
+
await fs9.mkdir(path12.dirname(localPath), { recursive: true });
|
|
3538
3617
|
if (!this.skipClone) {
|
|
3539
3618
|
await this.git.clone(proxyId, repo.url, localPath, repo.branch, useProxy);
|
|
3540
3619
|
}
|
|
@@ -3634,7 +3713,7 @@ var RepoManager = class {
|
|
|
3634
3713
|
let cloned = false;
|
|
3635
3714
|
if (!this.skipClone) {
|
|
3636
3715
|
const localPath = getRepoDir(id);
|
|
3637
|
-
await
|
|
3716
|
+
await fs9.mkdir(path12.dirname(localPath), { recursive: true });
|
|
3638
3717
|
await this.git.clone(userProxyId, url, localPath, branch, useProxy);
|
|
3639
3718
|
cloned = true;
|
|
3640
3719
|
}
|
|
@@ -3659,7 +3738,7 @@ var RepoManager = class {
|
|
|
3659
3738
|
await this.store.removeUserRepo(repoId);
|
|
3660
3739
|
const localPath = getRepoDir(repoId);
|
|
3661
3740
|
try {
|
|
3662
|
-
await
|
|
3741
|
+
await fs9.rm(localPath, { recursive: true, force: true });
|
|
3663
3742
|
} catch (err) {
|
|
3664
3743
|
if (err.code !== "ENOENT") throw err;
|
|
3665
3744
|
}
|
|
@@ -3682,7 +3761,7 @@ var RepoManager = class {
|
|
|
3682
3761
|
}
|
|
3683
3762
|
/** Force-create the SERVICEME home directory tree (idempotent). */
|
|
3684
3763
|
async ensureHome() {
|
|
3685
|
-
await
|
|
3764
|
+
await fs9.mkdir(getServicemeHome(), { recursive: true });
|
|
3686
3765
|
}
|
|
3687
3766
|
/**
|
|
3688
3767
|
* Returns `true` when `p` contains a `.git` entry — i.e. it is an
|
|
@@ -3690,11 +3769,11 @@ var RepoManager = class {
|
|
|
3690
3769
|
* (e.g. from an interrupted clone) return `false`.
|
|
3691
3770
|
*/
|
|
3692
3771
|
async isValidGitRepo(p) {
|
|
3693
|
-
return this.pathExists(
|
|
3772
|
+
return this.pathExists(path12.join(p, ".git"));
|
|
3694
3773
|
}
|
|
3695
3774
|
async pathExists(p) {
|
|
3696
3775
|
try {
|
|
3697
|
-
await
|
|
3776
|
+
await fs9.stat(p);
|
|
3698
3777
|
return true;
|
|
3699
3778
|
} catch {
|
|
3700
3779
|
return false;
|
|
@@ -3819,8 +3898,8 @@ function resolveDefaultRepoId(existing, existingIds) {
|
|
|
3819
3898
|
}
|
|
3820
3899
|
|
|
3821
3900
|
// src/repos/loader.ts
|
|
3822
|
-
import * as
|
|
3823
|
-
import * as
|
|
3901
|
+
import * as fs10 from "fs/promises";
|
|
3902
|
+
import * as path13 from "path";
|
|
3824
3903
|
import { z } from "zod";
|
|
3825
3904
|
var ISO_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})$/;
|
|
3826
3905
|
var repoIdSchema = z.string().min(1).max(64).regex(SAFE_REPO_ID_PATTERN, "repo id must match /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/");
|
|
@@ -3903,7 +3982,7 @@ var ReposLoader = class {
|
|
|
3903
3982
|
this.configPath = options.configPath;
|
|
3904
3983
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
3905
3984
|
this.randomSuffix = options.randomSuffix ?? defaultRandomSuffix;
|
|
3906
|
-
this.fileSystem = options.fileSystem ??
|
|
3985
|
+
this.fileSystem = options.fileSystem ?? fs10;
|
|
3907
3986
|
}
|
|
3908
3987
|
/** Absolute path of the file this loader reads/writes. */
|
|
3909
3988
|
getConfigPath() {
|
|
@@ -3956,7 +4035,7 @@ var ReposLoader = class {
|
|
|
3956
4035
|
*/
|
|
3957
4036
|
async save(config) {
|
|
3958
4037
|
const validated = reposFileSchema.parse(config);
|
|
3959
|
-
const dir =
|
|
4038
|
+
const dir = path13.dirname(this.configPath);
|
|
3960
4039
|
await this.fileSystem.mkdir(dir, { recursive: true });
|
|
3961
4040
|
const serialized = `${JSON.stringify(validated, null, 2)}
|
|
3962
4041
|
`;
|
|
@@ -3965,7 +4044,7 @@ var ReposLoader = class {
|
|
|
3965
4044
|
try {
|
|
3966
4045
|
await this.fileSystem.rename(tempPath, this.configPath);
|
|
3967
4046
|
} catch (error) {
|
|
3968
|
-
const unlink2 = this.fileSystem.unlink ??
|
|
4047
|
+
const unlink2 = this.fileSystem.unlink ?? fs10.unlink;
|
|
3969
4048
|
await unlink2(tempPath).catch(() => void 0);
|
|
3970
4049
|
throw error;
|
|
3971
4050
|
}
|
|
@@ -4025,7 +4104,7 @@ function narrowRepoConfig(repo) {
|
|
|
4025
4104
|
|
|
4026
4105
|
// src/repos/store.ts
|
|
4027
4106
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
4028
|
-
import * as
|
|
4107
|
+
import * as fs11 from "fs";
|
|
4029
4108
|
var ReposStore = class {
|
|
4030
4109
|
constructor(options = {}) {
|
|
4031
4110
|
this.config = null;
|
|
@@ -4034,7 +4113,7 @@ var ReposStore = class {
|
|
|
4034
4113
|
this.reloadTimer = null;
|
|
4035
4114
|
this.lastLoadResult = null;
|
|
4036
4115
|
this.loader = options.loader ?? new ReposLoader({ configPath: "" });
|
|
4037
|
-
this.fileSystem = options.fileSystem ?? { watch:
|
|
4116
|
+
this.fileSystem = options.fileSystem ?? { watch: fs11.watch };
|
|
4038
4117
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
4039
4118
|
this.debounceMs = options.debounceMs ?? 50;
|
|
4040
4119
|
this.createFsWatcher = options.createFsWatcher ?? ((p, cb) => this.defaultCreateFsWatcher(p, cb));
|
|
@@ -4316,17 +4395,17 @@ async function bootstrapDefaults(store) {
|
|
|
4316
4395
|
}
|
|
4317
4396
|
|
|
4318
4397
|
// src/scheduled-tasks/daemon/DaemonLogger.ts
|
|
4319
|
-
import * as
|
|
4320
|
-
import * as
|
|
4398
|
+
import * as fs12 from "fs";
|
|
4399
|
+
import * as path14 from "path";
|
|
4321
4400
|
var CONFIG_DIR = ".serviceme";
|
|
4322
4401
|
var LOG_FILE = "scheduler.log";
|
|
4323
4402
|
var MAX_LOG_SIZE = 1024 * 1024;
|
|
4324
4403
|
var DaemonLogger = class {
|
|
4325
4404
|
constructor(workspacePath, options = {}) {
|
|
4326
|
-
this.logPath = options.logPath ??
|
|
4327
|
-
const dir =
|
|
4328
|
-
if (!
|
|
4329
|
-
|
|
4405
|
+
this.logPath = options.logPath ?? path14.join(workspacePath, CONFIG_DIR, LOG_FILE);
|
|
4406
|
+
const dir = path14.dirname(this.logPath);
|
|
4407
|
+
if (!fs12.existsSync(dir)) {
|
|
4408
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
4330
4409
|
}
|
|
4331
4410
|
}
|
|
4332
4411
|
getLogPath() {
|
|
@@ -4337,16 +4416,16 @@ var DaemonLogger = class {
|
|
|
4337
4416
|
const line = `[${ts}] [${level.toUpperCase()}] ${message}
|
|
4338
4417
|
`;
|
|
4339
4418
|
this.rotateIfNeeded();
|
|
4340
|
-
|
|
4419
|
+
fs12.appendFileSync(this.logPath, line, "utf-8");
|
|
4341
4420
|
}
|
|
4342
4421
|
rotateIfNeeded() {
|
|
4343
4422
|
try {
|
|
4344
|
-
const stats =
|
|
4423
|
+
const stats = fs12.statSync(this.logPath);
|
|
4345
4424
|
if (stats.size > MAX_LOG_SIZE) {
|
|
4346
|
-
const content =
|
|
4425
|
+
const content = fs12.readFileSync(this.logPath, "utf-8");
|
|
4347
4426
|
const halfIdx = content.indexOf("\n", Math.floor(content.length / 2));
|
|
4348
4427
|
if (halfIdx > 0) {
|
|
4349
|
-
|
|
4428
|
+
fs12.writeFileSync(this.logPath, content.slice(halfIdx + 1), "utf-8");
|
|
4350
4429
|
}
|
|
4351
4430
|
}
|
|
4352
4431
|
} catch {
|
|
@@ -4355,39 +4434,39 @@ var DaemonLogger = class {
|
|
|
4355
4434
|
};
|
|
4356
4435
|
|
|
4357
4436
|
// src/scheduled-tasks/daemon/PidManager.ts
|
|
4358
|
-
import * as
|
|
4359
|
-
import * as
|
|
4437
|
+
import * as fs13 from "fs";
|
|
4438
|
+
import * as path15 from "path";
|
|
4360
4439
|
var CONFIG_DIR2 = ".serviceme";
|
|
4361
4440
|
var PID_FILE = "scheduler.pid";
|
|
4362
4441
|
var PidManager = class {
|
|
4363
4442
|
constructor(workspacePath, options = {}) {
|
|
4364
|
-
this.pidPath = options.pidPath ??
|
|
4443
|
+
this.pidPath = options.pidPath ?? path15.join(workspacePath, CONFIG_DIR2, PID_FILE);
|
|
4365
4444
|
}
|
|
4366
4445
|
getPidPath() {
|
|
4367
4446
|
return this.pidPath;
|
|
4368
4447
|
}
|
|
4369
4448
|
writePid(pid) {
|
|
4370
|
-
const dir =
|
|
4371
|
-
if (!
|
|
4372
|
-
|
|
4449
|
+
const dir = path15.dirname(this.pidPath);
|
|
4450
|
+
if (!fs13.existsSync(dir)) {
|
|
4451
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
4373
4452
|
}
|
|
4374
|
-
|
|
4453
|
+
fs13.writeFileSync(this.pidPath, String(pid), "utf-8");
|
|
4375
4454
|
}
|
|
4376
4455
|
readPid() {
|
|
4377
4456
|
let stat5;
|
|
4378
4457
|
try {
|
|
4379
|
-
stat5 =
|
|
4458
|
+
stat5 = fs13.statSync(this.pidPath);
|
|
4380
4459
|
} catch {
|
|
4381
4460
|
return null;
|
|
4382
4461
|
}
|
|
4383
4462
|
if (!stat5.isFile()) return null;
|
|
4384
|
-
const raw =
|
|
4463
|
+
const raw = fs13.readFileSync(this.pidPath, "utf-8").trim();
|
|
4385
4464
|
const pid = Number.parseInt(raw, 10);
|
|
4386
4465
|
return Number.isNaN(pid) ? null : pid;
|
|
4387
4466
|
}
|
|
4388
4467
|
removePid() {
|
|
4389
|
-
if (
|
|
4390
|
-
|
|
4468
|
+
if (fs13.existsSync(this.pidPath)) {
|
|
4469
|
+
fs13.unlinkSync(this.pidPath);
|
|
4391
4470
|
}
|
|
4392
4471
|
}
|
|
4393
4472
|
isProcessRunning(pid) {
|
|
@@ -4408,13 +4487,13 @@ var PidManager = class {
|
|
|
4408
4487
|
};
|
|
4409
4488
|
|
|
4410
4489
|
// src/scheduled-tasks/daemon/SchedulerDaemon.ts
|
|
4411
|
-
import * as
|
|
4490
|
+
import * as fs18 from "fs";
|
|
4412
4491
|
import * as os5 from "os";
|
|
4413
|
-
import * as
|
|
4492
|
+
import * as path19 from "path";
|
|
4414
4493
|
|
|
4415
4494
|
// src/scheduled-tasks/executors/GithubCopilotCliExecutor.ts
|
|
4416
4495
|
import { spawn as spawn3 } from "child_process";
|
|
4417
|
-
import * as
|
|
4496
|
+
import * as fs14 from "fs";
|
|
4418
4497
|
|
|
4419
4498
|
// src/scheduled-tasks/executors/timeout.ts
|
|
4420
4499
|
function resolveConfiguredTimeoutMs(timeoutSeconds, defaultTimeoutMs) {
|
|
@@ -4449,7 +4528,7 @@ function redactArgs(args) {
|
|
|
4449
4528
|
function writeDiagnostic(message) {
|
|
4450
4529
|
const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
|
|
4451
4530
|
if (logPath) {
|
|
4452
|
-
|
|
4531
|
+
fs14.appendFileSync(logPath, message);
|
|
4453
4532
|
return;
|
|
4454
4533
|
}
|
|
4455
4534
|
process.stderr.write(message);
|
|
@@ -4655,15 +4734,15 @@ ${body}`.trim()
|
|
|
4655
4734
|
|
|
4656
4735
|
// src/scheduled-tasks/executors/ShellExecutor.ts
|
|
4657
4736
|
import { spawn as spawn4 } from "child_process";
|
|
4658
|
-
import * as
|
|
4659
|
-
import * as
|
|
4737
|
+
import * as fs15 from "fs";
|
|
4738
|
+
import * as path16 from "path";
|
|
4660
4739
|
var MAX_OUTPUT_BYTES2 = 1024 * 1024;
|
|
4661
4740
|
var DEFAULT_TIMEOUT_MS4 = 6e4;
|
|
4662
4741
|
var POSIX_SHELL_CANDIDATES = ["bash.exe", "sh.exe"];
|
|
4663
4742
|
function resolveShellExecution(script, options = {}) {
|
|
4664
4743
|
const platform3 = options.platform ?? process.platform;
|
|
4665
4744
|
const env = options.env ?? process.env;
|
|
4666
|
-
const fileExists = options.fileExists ??
|
|
4745
|
+
const fileExists = options.fileExists ?? fs15.existsSync;
|
|
4667
4746
|
if (platform3 === "win32") {
|
|
4668
4747
|
const posixShell = usesPosixShellSyntax(script) ? findWindowsPosixShell(env, fileExists) : null;
|
|
4669
4748
|
if (posixShell) {
|
|
@@ -4708,10 +4787,10 @@ function findWindowsPosixShell(env, fileExists) {
|
|
|
4708
4787
|
if (fileExists(candidate)) return candidate;
|
|
4709
4788
|
}
|
|
4710
4789
|
const pathValue = env.Path ?? env.PATH ?? "";
|
|
4711
|
-
for (const dir of pathValue.split(
|
|
4790
|
+
for (const dir of pathValue.split(path16.win32.delimiter)) {
|
|
4712
4791
|
if (!dir) continue;
|
|
4713
4792
|
for (const executable of POSIX_SHELL_CANDIDATES) {
|
|
4714
|
-
const candidate =
|
|
4793
|
+
const candidate = path16.win32.join(dir, executable);
|
|
4715
4794
|
if (fileExists(candidate) && !isWindowsWslLauncher(candidate)) {
|
|
4716
4795
|
return candidate;
|
|
4717
4796
|
}
|
|
@@ -4720,13 +4799,13 @@ function findWindowsPosixShell(env, fileExists) {
|
|
|
4720
4799
|
return null;
|
|
4721
4800
|
}
|
|
4722
4801
|
function isWindowsWslLauncher(candidate) {
|
|
4723
|
-
const normalized =
|
|
4802
|
+
const normalized = path16.win32.normalize(candidate).toLowerCase();
|
|
4724
4803
|
return normalized.endsWith("\\windows\\system32\\bash.exe") || normalized.endsWith("\\windows\\syswow64\\bash.exe");
|
|
4725
4804
|
}
|
|
4726
4805
|
function writeDiagnostic2(message) {
|
|
4727
4806
|
const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
|
|
4728
4807
|
if (logPath) {
|
|
4729
|
-
|
|
4808
|
+
fs15.appendFileSync(logPath, message);
|
|
4730
4809
|
return;
|
|
4731
4810
|
}
|
|
4732
4811
|
process.stderr.write(message);
|
|
@@ -4868,10 +4947,10 @@ function getExecutor(taskType) {
|
|
|
4868
4947
|
}
|
|
4869
4948
|
|
|
4870
4949
|
// src/scheduled-tasks/TaskConfigManager.ts
|
|
4871
|
-
import { randomUUID as
|
|
4872
|
-
import * as
|
|
4950
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
4951
|
+
import * as fs16 from "fs";
|
|
4873
4952
|
import * as os4 from "os";
|
|
4874
|
-
import * as
|
|
4953
|
+
import * as path17 from "path";
|
|
4875
4954
|
import {
|
|
4876
4955
|
createServicemeError as createServicemeError8,
|
|
4877
4956
|
isScheduledTasksConfig,
|
|
@@ -4901,7 +4980,7 @@ function v1ContainerShape(value) {
|
|
|
4901
4980
|
}
|
|
4902
4981
|
function defaultWorkspaceContext() {
|
|
4903
4982
|
const home = os4.homedir() || "/";
|
|
4904
|
-
return { path: home, name:
|
|
4983
|
+
return { path: home, name: path17.basename(home) || home };
|
|
4905
4984
|
}
|
|
4906
4985
|
function requireNonEmptyString(payload, field, taskType) {
|
|
4907
4986
|
if (!isRecord2(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
|
|
@@ -4936,10 +5015,10 @@ var TaskConfigManager = class {
|
|
|
4936
5015
|
return this.configPath;
|
|
4937
5016
|
}
|
|
4938
5017
|
readConfig() {
|
|
4939
|
-
if (!
|
|
5018
|
+
if (!fs16.existsSync(this.configPath)) {
|
|
4940
5019
|
return emptyConfig();
|
|
4941
5020
|
}
|
|
4942
|
-
const raw =
|
|
5021
|
+
const raw = fs16.readFileSync(this.configPath, "utf-8");
|
|
4943
5022
|
let parsed;
|
|
4944
5023
|
try {
|
|
4945
5024
|
parsed = JSON.parse(raw);
|
|
@@ -4992,7 +5071,7 @@ var TaskConfigManager = class {
|
|
|
4992
5071
|
const target = this.migrationFailuresPath ?? getMigrationFailuresPath();
|
|
4993
5072
|
const prior = (() => {
|
|
4994
5073
|
try {
|
|
4995
|
-
return JSON.parse(
|
|
5074
|
+
return JSON.parse(fs16.readFileSync(target, "utf-8"));
|
|
4996
5075
|
} catch {
|
|
4997
5076
|
return [];
|
|
4998
5077
|
}
|
|
@@ -5005,8 +5084,8 @@ var TaskConfigManager = class {
|
|
|
5005
5084
|
snippet: raw.slice(0, 500),
|
|
5006
5085
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5007
5086
|
});
|
|
5008
|
-
|
|
5009
|
-
|
|
5087
|
+
fs16.mkdirSync(path17.dirname(target), { recursive: true });
|
|
5088
|
+
fs16.writeFileSync(target, JSON.stringify(failures, null, " "), "utf-8");
|
|
5010
5089
|
} catch (writeError) {
|
|
5011
5090
|
this.warn(
|
|
5012
5091
|
`TaskConfigManager: also failed to write migration-failures log: ${String(writeError)}`
|
|
@@ -5014,13 +5093,13 @@ var TaskConfigManager = class {
|
|
|
5014
5093
|
}
|
|
5015
5094
|
}
|
|
5016
5095
|
writeConfig(config) {
|
|
5017
|
-
const dir =
|
|
5018
|
-
if (!
|
|
5019
|
-
|
|
5096
|
+
const dir = path17.dirname(this.configPath);
|
|
5097
|
+
if (!fs16.existsSync(dir)) {
|
|
5098
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
5020
5099
|
}
|
|
5021
5100
|
const tmp = `${this.configPath}.tmp`;
|
|
5022
|
-
|
|
5023
|
-
|
|
5101
|
+
fs16.writeFileSync(tmp, JSON.stringify(config, null, " "), "utf-8");
|
|
5102
|
+
fs16.renameSync(tmp, this.configPath);
|
|
5024
5103
|
}
|
|
5025
5104
|
listTasks() {
|
|
5026
5105
|
return this.readConfig().tasks;
|
|
@@ -5042,7 +5121,7 @@ var TaskConfigManager = class {
|
|
|
5042
5121
|
const config = this.readConfig();
|
|
5043
5122
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5044
5123
|
const task = {
|
|
5045
|
-
id:
|
|
5124
|
+
id: randomUUID4(),
|
|
5046
5125
|
name: input.name,
|
|
5047
5126
|
description: input.description,
|
|
5048
5127
|
enabled: input.enabled ?? true,
|
|
@@ -5297,9 +5376,9 @@ var TaskExecutionEngine = class {
|
|
|
5297
5376
|
};
|
|
5298
5377
|
|
|
5299
5378
|
// src/scheduled-tasks/TaskLogManager.ts
|
|
5300
|
-
import { randomUUID as
|
|
5301
|
-
import * as
|
|
5302
|
-
import * as
|
|
5379
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
5380
|
+
import * as fs17 from "fs";
|
|
5381
|
+
import * as path18 from "path";
|
|
5303
5382
|
var MAX_LOGS = 200;
|
|
5304
5383
|
function emptyLogFile() {
|
|
5305
5384
|
return { logs: [] };
|
|
@@ -5328,11 +5407,11 @@ var TaskLogManager = class {
|
|
|
5328
5407
|
return this.logPath;
|
|
5329
5408
|
}
|
|
5330
5409
|
readLogFile() {
|
|
5331
|
-
if (!
|
|
5410
|
+
if (!fs17.existsSync(this.logPath)) {
|
|
5332
5411
|
return emptyLogFile();
|
|
5333
5412
|
}
|
|
5334
5413
|
try {
|
|
5335
|
-
const raw =
|
|
5414
|
+
const raw = fs17.readFileSync(this.logPath, "utf-8");
|
|
5336
5415
|
const parsed = JSON.parse(raw);
|
|
5337
5416
|
const file = validateAndRepairLogFile(parsed);
|
|
5338
5417
|
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.logs) || parsed.logs.length !== file.logs.length) {
|
|
@@ -5348,26 +5427,26 @@ var TaskLogManager = class {
|
|
|
5348
5427
|
}
|
|
5349
5428
|
backupCorruptedFile() {
|
|
5350
5429
|
try {
|
|
5351
|
-
if (
|
|
5430
|
+
if (fs17.existsSync(this.logPath)) {
|
|
5352
5431
|
const backupPath = `${this.logPath}.corrupted.${Date.now()}`;
|
|
5353
|
-
|
|
5432
|
+
fs17.copyFileSync(this.logPath, backupPath);
|
|
5354
5433
|
}
|
|
5355
5434
|
} catch {
|
|
5356
5435
|
}
|
|
5357
5436
|
}
|
|
5358
5437
|
writeLogFile(file) {
|
|
5359
|
-
const dir =
|
|
5360
|
-
if (!
|
|
5361
|
-
|
|
5438
|
+
const dir = path18.dirname(this.logPath);
|
|
5439
|
+
if (!fs17.existsSync(dir)) {
|
|
5440
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
5362
5441
|
}
|
|
5363
5442
|
const tmp = `${this.logPath}.tmp`;
|
|
5364
|
-
|
|
5365
|
-
|
|
5443
|
+
fs17.writeFileSync(tmp, JSON.stringify(file, null, " "), "utf-8");
|
|
5444
|
+
fs17.renameSync(tmp, this.logPath);
|
|
5366
5445
|
}
|
|
5367
5446
|
appendLog(input) {
|
|
5368
5447
|
const file = this.readLogFile();
|
|
5369
5448
|
const log = {
|
|
5370
|
-
id:
|
|
5449
|
+
id: randomUUID5(),
|
|
5371
5450
|
taskId: input.taskId,
|
|
5372
5451
|
taskName: input.taskName,
|
|
5373
5452
|
startedAt: input.startedAt,
|
|
@@ -5422,12 +5501,12 @@ var SchedulerDaemon = class {
|
|
|
5422
5501
|
this.lastRun = /* @__PURE__ */ new Map();
|
|
5423
5502
|
this.taskRunning = /* @__PURE__ */ new Set();
|
|
5424
5503
|
this.workspacePath = workspacePath;
|
|
5425
|
-
const configDir =
|
|
5504
|
+
const configDir = path19.join(workspacePath, ".serviceme");
|
|
5426
5505
|
this.configManager = new TaskConfigManager({
|
|
5427
|
-
configPath:
|
|
5506
|
+
configPath: path19.join(configDir, "scheduled-tasks.json")
|
|
5428
5507
|
});
|
|
5429
5508
|
this.logManager = new TaskLogManager({
|
|
5430
|
-
logPath:
|
|
5509
|
+
logPath: path19.join(configDir, "scheduled-tasks-log.json")
|
|
5431
5510
|
});
|
|
5432
5511
|
this.pidManager = new PidManager(workspacePath);
|
|
5433
5512
|
this.logger = new DaemonLogger(workspacePath);
|
|
@@ -5479,8 +5558,8 @@ var SchedulerDaemon = class {
|
|
|
5479
5558
|
const configPath = this.configManager.getConfigPath();
|
|
5480
5559
|
const dir = configPath.substring(0, configPath.lastIndexOf("/"));
|
|
5481
5560
|
try {
|
|
5482
|
-
if (
|
|
5483
|
-
this.watcher =
|
|
5561
|
+
if (fs18.existsSync(dir)) {
|
|
5562
|
+
this.watcher = fs18.watch(dir, (_eventType, filename) => {
|
|
5484
5563
|
if (filename === "scheduled-tasks.json") {
|
|
5485
5564
|
this.logger.log("info", "Config file changed, reconciling...");
|
|
5486
5565
|
}
|
|
@@ -5633,9 +5712,9 @@ function matchCronField(field, value) {
|
|
|
5633
5712
|
}
|
|
5634
5713
|
|
|
5635
5714
|
// src/scheduled-tasks/daemon/SchedulerDaemonV2.ts
|
|
5636
|
-
import * as
|
|
5715
|
+
import * as fs19 from "fs";
|
|
5637
5716
|
import * as os6 from "os";
|
|
5638
|
-
import * as
|
|
5717
|
+
import * as path20 from "path";
|
|
5639
5718
|
var TICK_INTERVAL2 = 1e3;
|
|
5640
5719
|
var MIN_SCHEDULE_INTERVAL2 = 1e3;
|
|
5641
5720
|
var SCHEDULER_LOG_FILENAME2 = "scheduler.log";
|
|
@@ -5655,7 +5734,7 @@ var SchedulerDaemonV2 = class {
|
|
|
5655
5734
|
this.logManager = options.logManager ?? new TaskLogManager();
|
|
5656
5735
|
this.pidManager = options.pidManager ?? new PidManager("", { pidPath: getSchedulerPidPath() });
|
|
5657
5736
|
this.logger = options.logger ?? new DaemonLogger(os6.homedir(), {
|
|
5658
|
-
logPath:
|
|
5737
|
+
logPath: path20.join(path20.dirname(this.pidManager.getPidPath()), SCHEDULER_LOG_FILENAME2)
|
|
5659
5738
|
});
|
|
5660
5739
|
this.getExecutor = options.getExecutor ?? getExecutor;
|
|
5661
5740
|
this.tryAcquireLock = options.tryAcquireLock ?? (() => true);
|
|
@@ -5713,7 +5792,7 @@ var SchedulerDaemonV2 = class {
|
|
|
5713
5792
|
const now = Date.now();
|
|
5714
5793
|
for (const task of config.tasks) {
|
|
5715
5794
|
if (!task.enabled) continue;
|
|
5716
|
-
if (!
|
|
5795
|
+
if (!fs19.existsSync(task.workspace.path)) {
|
|
5717
5796
|
this.disableTaskForMissingWorkspace(task, config);
|
|
5718
5797
|
continue;
|
|
5719
5798
|
}
|
|
@@ -5870,21 +5949,21 @@ function matchCronField2(field, value) {
|
|
|
5870
5949
|
}
|
|
5871
5950
|
|
|
5872
5951
|
// src/scheduled-tasks/migration/MigrateToGlobal.ts
|
|
5873
|
-
import * as
|
|
5874
|
-
import * as
|
|
5952
|
+
import * as fs20 from "fs";
|
|
5953
|
+
import * as path21 from "path";
|
|
5875
5954
|
import { isScheduledTasksConfigV1 as isScheduledTasksConfigV12, migrateV1ToV2 as migrateV1ToV22 } from "@serviceme/devtools-protocol";
|
|
5876
5955
|
var WORKSPACE_DIR = ".serviceme";
|
|
5877
5956
|
var V1_FILENAME = "scheduled-tasks.json";
|
|
5878
5957
|
function defaultProbe(workspacePath) {
|
|
5879
5958
|
return {
|
|
5880
5959
|
path: workspacePath,
|
|
5881
|
-
name:
|
|
5960
|
+
name: path21.basename(workspacePath) || workspacePath
|
|
5882
5961
|
};
|
|
5883
5962
|
}
|
|
5884
5963
|
function readV1Config(v1Path) {
|
|
5885
5964
|
let raw;
|
|
5886
5965
|
try {
|
|
5887
|
-
raw =
|
|
5966
|
+
raw = fs20.readFileSync(v1Path, "utf-8");
|
|
5888
5967
|
} catch (err) {
|
|
5889
5968
|
return {
|
|
5890
5969
|
ok: false,
|
|
@@ -5907,27 +5986,27 @@ function readV1Config(v1Path) {
|
|
|
5907
5986
|
}
|
|
5908
5987
|
function safeDelete(filePath) {
|
|
5909
5988
|
try {
|
|
5910
|
-
|
|
5989
|
+
fs20.unlinkSync(filePath);
|
|
5911
5990
|
} catch {
|
|
5912
5991
|
}
|
|
5913
5992
|
}
|
|
5914
5993
|
function ensureDir(filePath) {
|
|
5915
|
-
const dir =
|
|
5916
|
-
if (!
|
|
5917
|
-
|
|
5994
|
+
const dir = path21.dirname(filePath);
|
|
5995
|
+
if (!fs20.existsSync(dir)) {
|
|
5996
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
5918
5997
|
}
|
|
5919
5998
|
}
|
|
5920
5999
|
function readJsonFile(filePath) {
|
|
5921
|
-
if (!
|
|
6000
|
+
if (!fs20.existsSync(filePath)) return null;
|
|
5922
6001
|
try {
|
|
5923
|
-
return JSON.parse(
|
|
6002
|
+
return JSON.parse(fs20.readFileSync(filePath, "utf-8"));
|
|
5924
6003
|
} catch {
|
|
5925
6004
|
return null;
|
|
5926
6005
|
}
|
|
5927
6006
|
}
|
|
5928
6007
|
function writeJsonFile(filePath, data) {
|
|
5929
6008
|
ensureDir(filePath);
|
|
5930
|
-
|
|
6009
|
+
fs20.writeFileSync(filePath, JSON.stringify(data, null, " "), "utf-8");
|
|
5931
6010
|
}
|
|
5932
6011
|
function disambiguateName(task, existingNames, workspaceName) {
|
|
5933
6012
|
if (!existingNames.has(task.name)) {
|
|
@@ -5957,8 +6036,8 @@ async function migrateToGlobal(options) {
|
|
|
5957
6036
|
const conflicts = [];
|
|
5958
6037
|
const issues = [];
|
|
5959
6038
|
for (const workspacePath of options.workspacePaths) {
|
|
5960
|
-
const v1Path =
|
|
5961
|
-
if (!
|
|
6039
|
+
const v1Path = path21.join(workspacePath, WORKSPACE_DIR, V1_FILENAME);
|
|
6040
|
+
if (!fs20.existsSync(v1Path)) continue;
|
|
5962
6041
|
const v1 = readV1Config(v1Path);
|
|
5963
6042
|
if (!v1.ok) {
|
|
5964
6043
|
failures.push({
|
|
@@ -6000,8 +6079,8 @@ async function migrateToGlobal(options) {
|
|
|
6000
6079
|
if (migrated > 0) {
|
|
6001
6080
|
ensureDir(globalConfigPath);
|
|
6002
6081
|
const tmp = `${globalConfigPath}.tmp`;
|
|
6003
|
-
|
|
6004
|
-
|
|
6082
|
+
fs20.writeFileSync(tmp, JSON.stringify(baseConfig, null, " "), "utf-8");
|
|
6083
|
+
fs20.renameSync(tmp, globalConfigPath);
|
|
6005
6084
|
}
|
|
6006
6085
|
if (failures.length > priorFailures.length) {
|
|
6007
6086
|
writeJsonFile(migrationFailuresPath, failures);
|
|
@@ -6018,8 +6097,8 @@ async function migrateToGlobal(options) {
|
|
|
6018
6097
|
|
|
6019
6098
|
// src/scheduled-tasks/workspace-probe/WorkspaceProbe.ts
|
|
6020
6099
|
import { spawn as spawn5 } from "child_process";
|
|
6021
|
-
import * as
|
|
6022
|
-
import * as
|
|
6100
|
+
import * as fs21 from "fs";
|
|
6101
|
+
import * as path22 from "path";
|
|
6023
6102
|
var DEFAULT_TIMEOUT_MS5 = 2e3;
|
|
6024
6103
|
var GitTimeoutError = class extends Error {
|
|
6025
6104
|
constructor() {
|
|
@@ -6082,8 +6161,8 @@ var WorkspaceProbe = class {
|
|
|
6082
6161
|
}
|
|
6083
6162
|
}
|
|
6084
6163
|
async probe(workspacePath) {
|
|
6085
|
-
const name =
|
|
6086
|
-
if (!workspacePath || !
|
|
6164
|
+
const name = path22.basename(workspacePath) || workspacePath;
|
|
6165
|
+
if (!workspacePath || !fs21.existsSync(workspacePath)) {
|
|
6087
6166
|
return {
|
|
6088
6167
|
workspace: { path: workspacePath, name },
|
|
6089
6168
|
error: "path-not-found"
|
|
@@ -6235,8 +6314,8 @@ var SkillReconciler = class {
|
|
|
6235
6314
|
};
|
|
6236
6315
|
|
|
6237
6316
|
// src/skills/SkillStore.ts
|
|
6238
|
-
import * as
|
|
6239
|
-
import * as
|
|
6317
|
+
import * as fs22 from "fs/promises";
|
|
6318
|
+
import * as path23 from "path";
|
|
6240
6319
|
var USER_SKILL_MARKER_FILE = ".serviceme-skill.json";
|
|
6241
6320
|
var LEGACY_USER_SKILL_MARKER_FILE = ".ms-devtools-skill.json";
|
|
6242
6321
|
var WORKSPACE_SKILLS_ROOT_RELATIVE = ".github/skills";
|
|
@@ -6252,7 +6331,7 @@ var SkillStore = class {
|
|
|
6252
6331
|
constructor(options) {
|
|
6253
6332
|
this.workspacePath = options.workspacePath;
|
|
6254
6333
|
this.userSkillsRoot = options.userSkillsRoot;
|
|
6255
|
-
this.fileSystem = options.fileSystem ??
|
|
6334
|
+
this.fileSystem = options.fileSystem ?? fs22;
|
|
6256
6335
|
}
|
|
6257
6336
|
normalizeRemoteSkillId(remoteId) {
|
|
6258
6337
|
if (remoteId.startsWith("official/")) {
|
|
@@ -6271,10 +6350,10 @@ var SkillStore = class {
|
|
|
6271
6350
|
return WORKSPACE_SKILLS_MARKER_RELATIVE;
|
|
6272
6351
|
}
|
|
6273
6352
|
getUserSkillPath(skillId) {
|
|
6274
|
-
return
|
|
6353
|
+
return path23.join(this.userSkillsRoot, skillId);
|
|
6275
6354
|
}
|
|
6276
6355
|
async listWorkspaceSkillIds() {
|
|
6277
|
-
const skillsRootPath =
|
|
6356
|
+
const skillsRootPath = path23.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE);
|
|
6278
6357
|
try {
|
|
6279
6358
|
const entries = await this.fileSystem.readdir(skillsRootPath, {
|
|
6280
6359
|
withFileTypes: true
|
|
@@ -6298,7 +6377,7 @@ var SkillStore = class {
|
|
|
6298
6377
|
const targetDir = this.getUserSkillPath(skillId);
|
|
6299
6378
|
await this.fileSystem.mkdir(targetDir, { recursive: true });
|
|
6300
6379
|
await this.fileSystem.writeFile(
|
|
6301
|
-
|
|
6380
|
+
path23.join(targetDir, USER_SKILL_MARKER_FILE),
|
|
6302
6381
|
JSON.stringify({ skillId, installedBy: "serviceme" }, null, 2),
|
|
6303
6382
|
"utf-8"
|
|
6304
6383
|
);
|
|
@@ -6307,7 +6386,7 @@ var SkillStore = class {
|
|
|
6307
6386
|
await this.migrateLegacyUserSkillMarker(skillId);
|
|
6308
6387
|
try {
|
|
6309
6388
|
const marker = await this.fileSystem.readFile(
|
|
6310
|
-
|
|
6389
|
+
path23.join(this.getUserSkillPath(skillId), USER_SKILL_MARKER_FILE),
|
|
6311
6390
|
"utf-8"
|
|
6312
6391
|
);
|
|
6313
6392
|
const parsed = JSON.parse(marker);
|
|
@@ -6324,8 +6403,8 @@ var SkillStore = class {
|
|
|
6324
6403
|
*/
|
|
6325
6404
|
async migrateLegacyUserSkillMarker(skillId) {
|
|
6326
6405
|
const targetDir = this.getUserSkillPath(skillId);
|
|
6327
|
-
const newPath =
|
|
6328
|
-
const legacyPath =
|
|
6406
|
+
const newPath = path23.join(targetDir, USER_SKILL_MARKER_FILE);
|
|
6407
|
+
const legacyPath = path23.join(targetDir, LEGACY_USER_SKILL_MARKER_FILE);
|
|
6329
6408
|
try {
|
|
6330
6409
|
await this.fileSystem.readFile(newPath, "utf-8");
|
|
6331
6410
|
return;
|
|
@@ -6338,12 +6417,12 @@ var SkillStore = class {
|
|
|
6338
6417
|
}
|
|
6339
6418
|
}
|
|
6340
6419
|
async writeSkillFiles(skillId, scope, files) {
|
|
6341
|
-
const root = scope === "workspace" ?
|
|
6342
|
-
const targetDir =
|
|
6420
|
+
const root = scope === "workspace" ? path23.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
|
|
6421
|
+
const targetDir = path23.join(root, skillId);
|
|
6343
6422
|
await this.fileSystem.mkdir(targetDir, { recursive: true });
|
|
6344
6423
|
for (const file of files) {
|
|
6345
|
-
const filePath =
|
|
6346
|
-
await this.fileSystem.mkdir(
|
|
6424
|
+
const filePath = path23.join(targetDir, file.path);
|
|
6425
|
+
await this.fileSystem.mkdir(path23.dirname(filePath), { recursive: true });
|
|
6347
6426
|
await this.fileSystem.writeFile(filePath, file.content, "utf-8");
|
|
6348
6427
|
if (file.executable) {
|
|
6349
6428
|
try {
|
|
@@ -6356,8 +6435,8 @@ var SkillStore = class {
|
|
|
6356
6435
|
};
|
|
6357
6436
|
|
|
6358
6437
|
// src/submit/index.ts
|
|
6359
|
-
import * as
|
|
6360
|
-
import * as
|
|
6438
|
+
import * as fs23 from "fs/promises";
|
|
6439
|
+
import * as path24 from "path";
|
|
6361
6440
|
|
|
6362
6441
|
// src/submit/types.ts
|
|
6363
6442
|
var SubmitError = class extends Error {
|
|
@@ -6407,14 +6486,14 @@ var SubmitClient = class {
|
|
|
6407
6486
|
throw new SubmitError(v.reason ?? "unknown", v.detail ?? "validation denied");
|
|
6408
6487
|
}
|
|
6409
6488
|
const localRepoPath = getRepoDir(repoId);
|
|
6410
|
-
const targetDir =
|
|
6411
|
-
await
|
|
6489
|
+
const targetDir = path24.join(localRepoPath, "skills", skillName);
|
|
6490
|
+
await fs23.mkdir(targetDir, { recursive: true });
|
|
6412
6491
|
for (const f of files) {
|
|
6413
|
-
const full =
|
|
6414
|
-
await
|
|
6492
|
+
const full = path24.join(targetDir, f.path);
|
|
6493
|
+
await fs23.mkdir(path24.dirname(full), { recursive: true });
|
|
6415
6494
|
const tmp = `${full}.${process.pid}.${Date.now()}.tmp`;
|
|
6416
|
-
await
|
|
6417
|
-
await
|
|
6495
|
+
await fs23.writeFile(tmp, f.content, "utf8");
|
|
6496
|
+
await fs23.rename(tmp, full);
|
|
6418
6497
|
}
|
|
6419
6498
|
const commitMessage = `feat(skills): add ${skillName}`;
|
|
6420
6499
|
const { commitSha } = await this.git.commit(localRepoPath, commitMessage);
|
|
@@ -6483,7 +6562,7 @@ function touchLastUsedAt(tools, id, when = /* @__PURE__ */ new Date()) {
|
|
|
6483
6562
|
|
|
6484
6563
|
// src/toolbox/ToolboxStore.ts
|
|
6485
6564
|
import * as fsp2 from "fs/promises";
|
|
6486
|
-
import * as
|
|
6565
|
+
import * as path25 from "path";
|
|
6487
6566
|
import { setTimeout as delay2 } from "timers/promises";
|
|
6488
6567
|
|
|
6489
6568
|
// src/toolbox/types.ts
|
|
@@ -6518,11 +6597,11 @@ var LOCK_DIR_MODE2 = 448;
|
|
|
6518
6597
|
var DEFAULT_LOCK_TIMEOUT_MS2 = 5e3;
|
|
6519
6598
|
var DEFAULT_LOCK_RETRY_MS2 = 25;
|
|
6520
6599
|
var TMP_SUFFIX2 = ".tmp";
|
|
6521
|
-
var WORKSPACE_TOOLBOX_RELATIVE_PATH =
|
|
6600
|
+
var WORKSPACE_TOOLBOX_RELATIVE_PATH = path25.join(".github", ".serviceme-toolbox.json");
|
|
6522
6601
|
var LEGACY_WORKSPACE_TOOLBOX_FILENAME = ".ms-devtools-toolbox.json";
|
|
6523
6602
|
async function migrateLegacyWorkspaceToolboxFile(filePath) {
|
|
6524
6603
|
if (!filePath) return;
|
|
6525
|
-
const legacyPath =
|
|
6604
|
+
const legacyPath = path25.join(path25.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
|
|
6526
6605
|
if (legacyPath === filePath) return;
|
|
6527
6606
|
try {
|
|
6528
6607
|
await fsp2.access(filePath);
|
|
@@ -6567,7 +6646,7 @@ var FsToolboxFileBackend = class {
|
|
|
6567
6646
|
}
|
|
6568
6647
|
}
|
|
6569
6648
|
async write(filePath, payload) {
|
|
6570
|
-
await fsp2.mkdir(
|
|
6649
|
+
await fsp2.mkdir(path25.dirname(filePath), { recursive: true });
|
|
6571
6650
|
const tmpPath = `${filePath}${TMP_SUFFIX2}`;
|
|
6572
6651
|
const bytes = Buffer.from(JSON.stringify(payload, null, " "), "utf8");
|
|
6573
6652
|
await fsp2.rm(tmpPath, { force: true });
|
|
@@ -6630,7 +6709,7 @@ var ToolboxFileLock = class {
|
|
|
6630
6709
|
};
|
|
6631
6710
|
function defaultWorkspacePath() {
|
|
6632
6711
|
if (process.env.SERVICEME_NO_WORKSPACE_TOOLBOX === "1") return null;
|
|
6633
|
-
return
|
|
6712
|
+
return path25.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
|
|
6634
6713
|
}
|
|
6635
6714
|
var ToolboxStore = class {
|
|
6636
6715
|
constructor(opts = {}) {
|
|
@@ -6937,6 +7016,7 @@ export {
|
|
|
6937
7016
|
SCHEDULER_LOCK_FILENAME,
|
|
6938
7017
|
SCHEDULER_LOG_FILENAME,
|
|
6939
7018
|
SCHEDULER_PID_FILENAME,
|
|
7019
|
+
SERVER_PROXY_GLOBAL_FILENAME,
|
|
6940
7020
|
SERVICEME_DIR_NAME,
|
|
6941
7021
|
SERVICEME_HOME_ENV,
|
|
6942
7022
|
SKILL_DRAFTS_SUBDIR,
|
|
@@ -7004,6 +7084,7 @@ export {
|
|
|
7004
7084
|
getSchedulerLockPath,
|
|
7005
7085
|
getSchedulerLogPath,
|
|
7006
7086
|
getSchedulerPidPath,
|
|
7087
|
+
getServerProxyGlobalPath,
|
|
7007
7088
|
getServicemeHome,
|
|
7008
7089
|
getSkillDraftsDir,
|
|
7009
7090
|
getToolboxJsonPath,
|
|
@@ -7014,6 +7095,7 @@ export {
|
|
|
7014
7095
|
isUserRepo,
|
|
7015
7096
|
matchesCron,
|
|
7016
7097
|
mergeWithDefaults,
|
|
7098
|
+
migrateLegacyServerProxyEnabled,
|
|
7017
7099
|
migrateToGlobal,
|
|
7018
7100
|
moveFiles,
|
|
7019
7101
|
narrowRepoConfig,
|
|
@@ -7021,6 +7103,7 @@ export {
|
|
|
7021
7103
|
parseAgentToolPermissions,
|
|
7022
7104
|
parseIntervalMs,
|
|
7023
7105
|
randomInstallationId,
|
|
7106
|
+
readServerProxyGlobal,
|
|
7024
7107
|
reindexOrder,
|
|
7025
7108
|
reposFileSchema,
|
|
7026
7109
|
resetUserHomeOverrides,
|
|
@@ -7035,6 +7118,7 @@ export {
|
|
|
7035
7118
|
unzipFile,
|
|
7036
7119
|
userRepoSchema as userRepoConfigSchema,
|
|
7037
7120
|
validateReposFile,
|
|
7038
|
-
validateTaskPayload
|
|
7121
|
+
validateTaskPayload,
|
|
7122
|
+
writeServerProxyGlobal
|
|
7039
7123
|
};
|
|
7040
7124
|
//# sourceMappingURL=index.mjs.map
|