@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/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/phase5/bootstrap.ts
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: randomUUID2()
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 fs6.mkdir(home, { recursive: true });
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 fs6.access(spec.path);
3154
+ await fs7.access(spec.path);
3076
3155
  result.skipped.push(spec.path);
3077
3156
  } catch {
3078
3157
  try {
3079
- await fs6.mkdir(path9.dirname(spec.path), { recursive: true });
3080
- await fs6.writeFile(spec.path, spec.defaultContent, "utf8");
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 fs7 from "fs/promises";
3092
- import * as path10 from "path";
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 mkdir4, readdir as readdir3, rename as rename3, rm as rm3 } from "fs/promises";
3100
- import { dirname as dirname6, join as join7 } from "path";
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 mkdir4(join7(dest, entry.fileName), { recursive: true }).then(() => {
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 mkdir4(dirname6(outputPath), { recursive: true }).then(() => {
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 mkdir4(destPath, { recursive: true });
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 rename3(sourcePath, destPath);
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 mkdir4(destDir, { recursive: true });
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 = path10.join(tempExtractDir, input.extractedDirName);
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 fs7.readdir(tempExtractDir, { withFileTypes: true });
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 = path10.join(tempExtractDir, actualDirName);
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 fs7.chmod(scriptPath, 493);
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 = path10.join(
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 = path10.join(workspacePath, ".ms-scaffold", "project-mode.json");
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 fs7.readFile(projectModePath, "utf8");
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 fs7.mkdir(path10.dirname(presetManifestPath), { recursive: true });
3343
- await fs7.writeFile(
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 fs7.readdir(dir, { withFileTypes: true });
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 = path10.join(dir, entry.name);
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 fs7.access(targetPath);
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
- path10.join(tempExtractDir, directoryName),
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 fs7.readdir(directoryPath);
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 fs8 from "fs/promises";
3413
- import * as path11 from "path";
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 fs8.rm(localPath, { recursive: true, force: true });
3574
+ await fs9.rm(localPath, { recursive: true, force: true });
3496
3575
  }
3497
3576
  try {
3498
3577
  if (!this.skipClone) {
3499
- await fs8.mkdir(path11.dirname(localPath), { recursive: true });
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 fs8.rm(localPath, { recursive: true, force: true });
3613
+ await fs9.rm(localPath, { recursive: true, force: true });
3535
3614
  }
3536
3615
  if (!exists || !await this.pathExists(localPath)) {
3537
- await fs8.mkdir(path11.dirname(localPath), { recursive: true });
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 fs8.mkdir(path11.dirname(localPath), { recursive: true });
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 fs8.rm(localPath, { recursive: true, force: true });
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 fs8.mkdir(getServicemeHome(), { recursive: true });
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(path11.join(p, ".git"));
3772
+ return this.pathExists(path12.join(p, ".git"));
3694
3773
  }
3695
3774
  async pathExists(p) {
3696
3775
  try {
3697
- await fs8.stat(p);
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 fs9 from "fs/promises";
3823
- import * as path12 from "path";
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 ?? fs9;
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 = path12.dirname(this.configPath);
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 ?? fs9.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 fs10 from "fs";
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: fs10.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 fs11 from "fs";
4320
- import * as path13 from "path";
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 ?? path13.join(workspacePath, CONFIG_DIR, LOG_FILE);
4327
- const dir = path13.dirname(this.logPath);
4328
- if (!fs11.existsSync(dir)) {
4329
- fs11.mkdirSync(dir, { recursive: true });
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
- fs11.appendFileSync(this.logPath, line, "utf-8");
4419
+ fs12.appendFileSync(this.logPath, line, "utf-8");
4341
4420
  }
4342
4421
  rotateIfNeeded() {
4343
4422
  try {
4344
- const stats = fs11.statSync(this.logPath);
4423
+ const stats = fs12.statSync(this.logPath);
4345
4424
  if (stats.size > MAX_LOG_SIZE) {
4346
- const content = fs11.readFileSync(this.logPath, "utf-8");
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
- fs11.writeFileSync(this.logPath, content.slice(halfIdx + 1), "utf-8");
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 fs12 from "fs";
4359
- import * as path14 from "path";
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 ?? path14.join(workspacePath, CONFIG_DIR2, PID_FILE);
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 = path14.dirname(this.pidPath);
4371
- if (!fs12.existsSync(dir)) {
4372
- fs12.mkdirSync(dir, { recursive: true });
4449
+ const dir = path15.dirname(this.pidPath);
4450
+ if (!fs13.existsSync(dir)) {
4451
+ fs13.mkdirSync(dir, { recursive: true });
4373
4452
  }
4374
- fs12.writeFileSync(this.pidPath, String(pid), "utf-8");
4453
+ fs13.writeFileSync(this.pidPath, String(pid), "utf-8");
4375
4454
  }
4376
4455
  readPid() {
4377
4456
  let stat5;
4378
4457
  try {
4379
- stat5 = fs12.statSync(this.pidPath);
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 = fs12.readFileSync(this.pidPath, "utf-8").trim();
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 (fs12.existsSync(this.pidPath)) {
4390
- fs12.unlinkSync(this.pidPath);
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 fs17 from "fs";
4490
+ import * as fs18 from "fs";
4412
4491
  import * as os5 from "os";
4413
- import * as path18 from "path";
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 fs13 from "fs";
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
- fs13.appendFileSync(logPath, message);
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 fs14 from "fs";
4659
- import * as path15 from "path";
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 ?? fs14.existsSync;
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(path15.win32.delimiter)) {
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 = path15.win32.join(dir, executable);
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 = path15.win32.normalize(candidate).toLowerCase();
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
- fs14.appendFileSync(logPath, message);
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 randomUUID3 } from "crypto";
4872
- import * as fs15 from "fs";
4950
+ import { randomUUID as randomUUID4 } from "crypto";
4951
+ import * as fs16 from "fs";
4873
4952
  import * as os4 from "os";
4874
- import * as path16 from "path";
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: path16.basename(home) || home };
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 (!fs15.existsSync(this.configPath)) {
5018
+ if (!fs16.existsSync(this.configPath)) {
4940
5019
  return emptyConfig();
4941
5020
  }
4942
- const raw = fs15.readFileSync(this.configPath, "utf-8");
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(fs15.readFileSync(target, "utf-8"));
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
- fs15.mkdirSync(path16.dirname(target), { recursive: true });
5009
- fs15.writeFileSync(target, JSON.stringify(failures, null, " "), "utf-8");
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 = path16.dirname(this.configPath);
5018
- if (!fs15.existsSync(dir)) {
5019
- fs15.mkdirSync(dir, { recursive: true });
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
- fs15.writeFileSync(tmp, JSON.stringify(config, null, " "), "utf-8");
5023
- fs15.renameSync(tmp, this.configPath);
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: randomUUID3(),
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 randomUUID4 } from "crypto";
5301
- import * as fs16 from "fs";
5302
- import * as path17 from "path";
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 (!fs16.existsSync(this.logPath)) {
5410
+ if (!fs17.existsSync(this.logPath)) {
5332
5411
  return emptyLogFile();
5333
5412
  }
5334
5413
  try {
5335
- const raw = fs16.readFileSync(this.logPath, "utf-8");
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 (fs16.existsSync(this.logPath)) {
5430
+ if (fs17.existsSync(this.logPath)) {
5352
5431
  const backupPath = `${this.logPath}.corrupted.${Date.now()}`;
5353
- fs16.copyFileSync(this.logPath, backupPath);
5432
+ fs17.copyFileSync(this.logPath, backupPath);
5354
5433
  }
5355
5434
  } catch {
5356
5435
  }
5357
5436
  }
5358
5437
  writeLogFile(file) {
5359
- const dir = path17.dirname(this.logPath);
5360
- if (!fs16.existsSync(dir)) {
5361
- fs16.mkdirSync(dir, { recursive: true });
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
- fs16.writeFileSync(tmp, JSON.stringify(file, null, " "), "utf-8");
5365
- fs16.renameSync(tmp, this.logPath);
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: randomUUID4(),
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 = path18.join(workspacePath, ".serviceme");
5504
+ const configDir = path19.join(workspacePath, ".serviceme");
5426
5505
  this.configManager = new TaskConfigManager({
5427
- configPath: path18.join(configDir, "scheduled-tasks.json")
5506
+ configPath: path19.join(configDir, "scheduled-tasks.json")
5428
5507
  });
5429
5508
  this.logManager = new TaskLogManager({
5430
- logPath: path18.join(configDir, "scheduled-tasks-log.json")
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 (fs17.existsSync(dir)) {
5483
- this.watcher = fs17.watch(dir, (_eventType, filename) => {
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 fs18 from "fs";
5715
+ import * as fs19 from "fs";
5637
5716
  import * as os6 from "os";
5638
- import * as path19 from "path";
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: path19.join(path19.dirname(this.pidManager.getPidPath()), SCHEDULER_LOG_FILENAME2)
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 (!fs18.existsSync(task.workspace.path)) {
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 fs19 from "fs";
5874
- import * as path20 from "path";
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: path20.basename(workspacePath) || workspacePath
5960
+ name: path21.basename(workspacePath) || workspacePath
5882
5961
  };
5883
5962
  }
5884
5963
  function readV1Config(v1Path) {
5885
5964
  let raw;
5886
5965
  try {
5887
- raw = fs19.readFileSync(v1Path, "utf-8");
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
- fs19.unlinkSync(filePath);
5989
+ fs20.unlinkSync(filePath);
5911
5990
  } catch {
5912
5991
  }
5913
5992
  }
5914
5993
  function ensureDir(filePath) {
5915
- const dir = path20.dirname(filePath);
5916
- if (!fs19.existsSync(dir)) {
5917
- fs19.mkdirSync(dir, { recursive: true });
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 (!fs19.existsSync(filePath)) return null;
6000
+ if (!fs20.existsSync(filePath)) return null;
5922
6001
  try {
5923
- return JSON.parse(fs19.readFileSync(filePath, "utf-8"));
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
- fs19.writeFileSync(filePath, JSON.stringify(data, null, " "), "utf-8");
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 = path20.join(workspacePath, WORKSPACE_DIR, V1_FILENAME);
5961
- if (!fs19.existsSync(v1Path)) continue;
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
- fs19.writeFileSync(tmp, JSON.stringify(baseConfig, null, " "), "utf-8");
6004
- fs19.renameSync(tmp, globalConfigPath);
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 fs20 from "fs";
6022
- import * as path21 from "path";
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 = path21.basename(workspacePath) || workspacePath;
6086
- if (!workspacePath || !fs20.existsSync(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 fs21 from "fs/promises";
6239
- import * as path22 from "path";
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 ?? fs21;
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 path22.join(this.userSkillsRoot, skillId);
6353
+ return path23.join(this.userSkillsRoot, skillId);
6275
6354
  }
6276
6355
  async listWorkspaceSkillIds() {
6277
- const skillsRootPath = path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE);
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
- path22.join(targetDir, USER_SKILL_MARKER_FILE),
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
- path22.join(this.getUserSkillPath(skillId), USER_SKILL_MARKER_FILE),
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 = path22.join(targetDir, USER_SKILL_MARKER_FILE);
6328
- const legacyPath = path22.join(targetDir, LEGACY_USER_SKILL_MARKER_FILE);
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" ? path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
6342
- const targetDir = path22.join(root, skillId);
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 = path22.join(targetDir, file.path);
6346
- await this.fileSystem.mkdir(path22.dirname(filePath), { recursive: true });
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 fs22 from "fs/promises";
6360
- import * as path23 from "path";
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 = path23.join(localRepoPath, "skills", skillName);
6411
- await fs22.mkdir(targetDir, { recursive: true });
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 = path23.join(targetDir, f.path);
6414
- await fs22.mkdir(path23.dirname(full), { recursive: true });
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 fs22.writeFile(tmp, f.content, "utf8");
6417
- await fs22.rename(tmp, full);
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 path24 from "path";
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 = path24.join(".github", ".serviceme-toolbox.json");
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 = path24.join(path24.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
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(path24.dirname(filePath), { recursive: true });
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 path24.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
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