@serviceme/devtools-core 0.3.0 → 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.js CHANGED
@@ -96,6 +96,7 @@ __export(src_exports, {
96
96
  SCHEDULER_LOCK_FILENAME: () => SCHEDULER_LOCK_FILENAME,
97
97
  SCHEDULER_LOG_FILENAME: () => SCHEDULER_LOG_FILENAME,
98
98
  SCHEDULER_PID_FILENAME: () => SCHEDULER_PID_FILENAME,
99
+ SERVER_PROXY_GLOBAL_FILENAME: () => SERVER_PROXY_GLOBAL_FILENAME,
99
100
  SERVICEME_DIR_NAME: () => SERVICEME_DIR_NAME,
100
101
  SERVICEME_HOME_ENV: () => SERVICEME_HOME_ENV,
101
102
  SKILL_DRAFTS_SUBDIR: () => SKILL_DRAFTS_SUBDIR,
@@ -163,6 +164,7 @@ __export(src_exports, {
163
164
  getSchedulerLockPath: () => getSchedulerLockPath,
164
165
  getSchedulerLogPath: () => getSchedulerLogPath,
165
166
  getSchedulerPidPath: () => getSchedulerPidPath,
167
+ getServerProxyGlobalPath: () => getServerProxyGlobalPath,
166
168
  getServicemeHome: () => getServicemeHome,
167
169
  getSkillDraftsDir: () => getSkillDraftsDir,
168
170
  getToolboxJsonPath: () => getToolboxJsonPath,
@@ -173,6 +175,7 @@ __export(src_exports, {
173
175
  isUserRepo: () => isUserRepo,
174
176
  matchesCron: () => matchesCron,
175
177
  mergeWithDefaults: () => mergeWithDefaults,
178
+ migrateLegacyServerProxyEnabled: () => migrateLegacyServerProxyEnabled,
176
179
  migrateToGlobal: () => migrateToGlobal,
177
180
  moveFiles: () => moveFiles,
178
181
  narrowRepoConfig: () => narrowRepoConfig,
@@ -180,6 +183,7 @@ __export(src_exports, {
180
183
  parseAgentToolPermissions: () => parseAgentToolPermissions,
181
184
  parseIntervalMs: () => parseIntervalMs,
182
185
  randomInstallationId: () => randomInstallationId,
186
+ readServerProxyGlobal: () => readServerProxyGlobal,
183
187
  reindexOrder: () => reindexOrder,
184
188
  reposFileSchema: () => reposFileSchema,
185
189
  resetUserHomeOverrides: () => resetUserHomeOverrides,
@@ -194,7 +198,8 @@ __export(src_exports, {
194
198
  unzipFile: () => unzipFile,
195
199
  userRepoConfigSchema: () => userRepoSchema,
196
200
  validateReposFile: () => validateReposFile,
197
- validateTaskPayload: () => validateTaskPayload
201
+ validateTaskPayload: () => validateTaskPayload,
202
+ writeServerProxyGlobal: () => writeServerProxyGlobal
198
203
  });
199
204
  module.exports = __toCommonJS(src_exports);
200
205
 
@@ -1857,6 +1862,7 @@ var DRAFTS_SUBDIR = "drafts";
1857
1862
  var SKILL_DRAFTS_SUBDIR = "skills";
1858
1863
  var AGENT_DRAFTS_SUBDIR = "agents";
1859
1864
  var REPOS_CONFIG_FILENAME = "repos.json";
1865
+ var SERVER_PROXY_GLOBAL_FILENAME = "server-proxy.json";
1860
1866
  var SAFE_REPO_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
1861
1867
  var SERVICEME_HOME_ENV = "SERVICEME_HOME";
1862
1868
  var activeOverrides = {};
@@ -1957,6 +1963,9 @@ function getMigrationFailuresPath() {
1957
1963
  function getKnownWorkspacesPath() {
1958
1964
  return path2.join(getServicemeHome(), KNOWN_WORKSPACES_FILENAME);
1959
1965
  }
1966
+ function getServerProxyGlobalPath() {
1967
+ return path2.join(getServicemeHome(), SERVER_PROXY_GLOBAL_FILENAME);
1968
+ }
1960
1969
  var CREDENTIALS_CONFIG_FILENAME = "credentials.json";
1961
1970
  var DEVICE_JSON_FILENAME = "device.json";
1962
1971
  var TOOLBOX_JSON_FILENAME = "toolbox.json";
@@ -3195,10 +3204,85 @@ function createConsoleLogger(prefix = "serviceme") {
3195
3204
  };
3196
3205
  }
3197
3206
 
3198
- // src/phase5/bootstrap.ts
3207
+ // src/paths/serverProxyGlobal.ts
3199
3208
  var import_node_crypto4 = require("crypto");
3200
3209
  var fs6 = __toESM(require("fs/promises"));
3210
+ var import_promises2 = require("fs/promises");
3201
3211
  var path9 = __toESM(require("path"));
3212
+ async function readServerProxyGlobal() {
3213
+ const filePath = getServerProxyGlobalPath();
3214
+ try {
3215
+ const raw = await fs6.readFile(filePath, "utf8");
3216
+ const parsed = JSON.parse(raw);
3217
+ if (!isServerProxyGlobalState(parsed)) {
3218
+ throw new Error(
3219
+ `Invalid ${SERVER_PROXY_GLOBAL_FILENAME}: expected {enabled: boolean, lastServerUrl?: string, updatedAt: string}, got ${JSON.stringify(parsed).slice(0, 80)}`
3220
+ );
3221
+ }
3222
+ return parsed;
3223
+ } catch (err) {
3224
+ if (isENOENT(err)) return null;
3225
+ throw err;
3226
+ }
3227
+ }
3228
+ async function writeServerProxyGlobal(patch) {
3229
+ const filePath = getServerProxyGlobalPath();
3230
+ const dirPath = path9.dirname(filePath);
3231
+ await fs6.mkdir(dirPath, { recursive: true });
3232
+ const current = await readServerProxyGlobal() ?? {
3233
+ enabled: false,
3234
+ allowOverride: false,
3235
+ lastServerUrl: void 0,
3236
+ updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
3237
+ };
3238
+ const next = {
3239
+ enabled: patch.enabled !== void 0 ? patch.enabled : current.enabled,
3240
+ allowOverride: patch.allowOverride !== void 0 ? patch.allowOverride : current.allowOverride,
3241
+ lastServerUrl: patch.lastServerUrl === void 0 ? current.lastServerUrl : patch.lastServerUrl === null ? void 0 : patch.lastServerUrl,
3242
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3243
+ };
3244
+ const tmpPath = `${filePath}.tmp-${(0, import_node_crypto4.randomUUID)()}`;
3245
+ const fh = await (0, import_promises2.open)(tmpPath, "w");
3246
+ try {
3247
+ await fh.writeFile(JSON.stringify(next, null, " "), "utf8");
3248
+ await fh.sync();
3249
+ } finally {
3250
+ await fh.close();
3251
+ }
3252
+ await fs6.rename(tmpPath, filePath);
3253
+ return next;
3254
+ }
3255
+ async function migrateLegacyServerProxyEnabled(readLegacy, clearLegacy) {
3256
+ const legacyEnabled = readLegacy();
3257
+ if (legacyEnabled !== true) return null;
3258
+ const existing = await readServerProxyGlobal();
3259
+ if (existing?.enabled === true) {
3260
+ await clearLegacy();
3261
+ return null;
3262
+ }
3263
+ const next = await writeServerProxyGlobal({ enabled: true });
3264
+ await clearLegacy();
3265
+ return next;
3266
+ }
3267
+ function isServerProxyGlobalState(v) {
3268
+ if (!v || typeof v !== "object") return false;
3269
+ const obj = v;
3270
+ if (typeof obj.enabled !== "boolean") return false;
3271
+ if (typeof obj.allowOverride !== "boolean") return false;
3272
+ if (typeof obj.updatedAt !== "string") return false;
3273
+ if (obj.lastServerUrl !== void 0 && obj.lastServerUrl !== null && typeof obj.lastServerUrl !== "string") {
3274
+ return false;
3275
+ }
3276
+ return true;
3277
+ }
3278
+ function isENOENT(err) {
3279
+ return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
3280
+ }
3281
+
3282
+ // src/phase5/bootstrap.ts
3283
+ var import_node_crypto5 = require("crypto");
3284
+ var fs7 = __toESM(require("fs/promises"));
3285
+ var path10 = __toESM(require("path"));
3202
3286
  function getPhase5FileSpecs() {
3203
3287
  return [
3204
3288
  {
@@ -3229,7 +3313,7 @@ function getPhase5FileSpecs() {
3229
3313
  path: getMachineIdPath(),
3230
3314
  // Random uuid, written as a bare string. Subsequent
3231
3315
  // activations see the file and skip re-randomizing.
3232
- defaultContent: (0, import_node_crypto4.randomUUID)()
3316
+ defaultContent: (0, import_node_crypto5.randomUUID)()
3233
3317
  },
3234
3318
  {
3235
3319
  path: getProfilesJsonPath(),
@@ -3243,19 +3327,19 @@ async function bootstrapPhase5Placeholders() {
3243
3327
  const result = { created: [], skipped: [], failed: [] };
3244
3328
  const home = getServicemeHome();
3245
3329
  try {
3246
- await fs6.mkdir(home, { recursive: true });
3330
+ await fs7.mkdir(home, { recursive: true });
3247
3331
  } catch (err) {
3248
3332
  result.failed.push({ path: home, reason: err.message });
3249
3333
  return result;
3250
3334
  }
3251
3335
  for (const spec of getPhase5FileSpecs()) {
3252
3336
  try {
3253
- await fs6.access(spec.path);
3337
+ await fs7.access(spec.path);
3254
3338
  result.skipped.push(spec.path);
3255
3339
  } catch {
3256
3340
  try {
3257
- await fs6.mkdir(path9.dirname(spec.path), { recursive: true });
3258
- await fs6.writeFile(spec.path, spec.defaultContent, "utf8");
3341
+ await fs7.mkdir(path10.dirname(spec.path), { recursive: true });
3342
+ await fs7.writeFile(spec.path, spec.defaultContent, "utf8");
3259
3343
  result.created.push(spec.path);
3260
3344
  } catch (writeErr) {
3261
3345
  result.failed.push({ path: spec.path, reason: writeErr.message });
@@ -3266,13 +3350,13 @@ async function bootstrapPhase5Placeholders() {
3266
3350
  }
3267
3351
 
3268
3352
  // src/project/projectTools.ts
3269
- var fs7 = __toESM(require("fs/promises"));
3270
- var path10 = __toESM(require("path"));
3353
+ var fs8 = __toESM(require("fs/promises"));
3354
+ var path11 = __toESM(require("path"));
3271
3355
  var import_devtools_protocol7 = require("@serviceme/devtools-protocol");
3272
3356
 
3273
3357
  // src/utils/fileUtils.ts
3274
3358
  var import_node_fs = require("fs");
3275
- var import_promises2 = require("fs/promises");
3359
+ var import_promises3 = require("fs/promises");
3276
3360
  var import_node_path = require("path");
3277
3361
  var import_yauzl = __toESM(require("yauzl"));
3278
3362
  var unzipFile = (zipPath, dest) => {
@@ -3283,12 +3367,12 @@ var unzipFile = (zipPath, dest) => {
3283
3367
  zipfile.readEntry();
3284
3368
  zipfile.on("entry", (entry) => {
3285
3369
  if (/\/$/.test(entry.fileName)) {
3286
- void (0, import_promises2.mkdir)((0, import_node_path.join)(dest, entry.fileName), { recursive: true }).then(() => {
3370
+ void (0, import_promises3.mkdir)((0, import_node_path.join)(dest, entry.fileName), { recursive: true }).then(() => {
3287
3371
  zipfile.readEntry();
3288
3372
  }).catch(reject);
3289
3373
  } else {
3290
3374
  const outputPath = (0, import_node_path.join)(dest, entry.fileName);
3291
- void (0, import_promises2.mkdir)((0, import_node_path.dirname)(outputPath), { recursive: true }).then(() => {
3375
+ void (0, import_promises3.mkdir)((0, import_node_path.dirname)(outputPath), { recursive: true }).then(() => {
3292
3376
  zipfile.openReadStream(
3293
3377
  entry,
3294
3378
  (streamError, readStream) => {
@@ -3317,54 +3401,54 @@ var unzipFile = (zipPath, dest) => {
3317
3401
  };
3318
3402
  var tryLstat = async (targetPath) => {
3319
3403
  try {
3320
- return await (0, import_promises2.lstat)(targetPath);
3404
+ return await (0, import_promises3.lstat)(targetPath);
3321
3405
  } catch {
3322
3406
  return null;
3323
3407
  }
3324
3408
  };
3325
3409
  var mergeEntry = async (sourcePath, destPath, overwrite) => {
3326
- const sourceStat = await (0, import_promises2.lstat)(sourcePath);
3410
+ const sourceStat = await (0, import_promises3.lstat)(sourcePath);
3327
3411
  const destStat = await tryLstat(destPath);
3328
3412
  if (sourceStat.isDirectory()) {
3329
3413
  if (destStat && !destStat.isDirectory()) {
3330
3414
  if (!overwrite) {
3331
- await (0, import_promises2.rm)(sourcePath, { recursive: true, force: true });
3415
+ await (0, import_promises3.rm)(sourcePath, { recursive: true, force: true });
3332
3416
  return;
3333
3417
  }
3334
- await (0, import_promises2.rm)(destPath, { recursive: true, force: true });
3418
+ await (0, import_promises3.rm)(destPath, { recursive: true, force: true });
3335
3419
  }
3336
- await (0, import_promises2.mkdir)(destPath, { recursive: true });
3337
- const children = await (0, import_promises2.readdir)(sourcePath);
3420
+ await (0, import_promises3.mkdir)(destPath, { recursive: true });
3421
+ const children = await (0, import_promises3.readdir)(sourcePath);
3338
3422
  for (const child of children) {
3339
3423
  await mergeEntry((0, import_node_path.join)(sourcePath, child), (0, import_node_path.join)(destPath, child), overwrite);
3340
3424
  }
3341
- await (0, import_promises2.rm)(sourcePath, { recursive: true, force: true });
3425
+ await (0, import_promises3.rm)(sourcePath, { recursive: true, force: true });
3342
3426
  return;
3343
3427
  }
3344
3428
  if (destStat) {
3345
3429
  if (!overwrite) {
3346
- await (0, import_promises2.rm)(sourcePath, { recursive: true, force: true });
3430
+ await (0, import_promises3.rm)(sourcePath, { recursive: true, force: true });
3347
3431
  return;
3348
3432
  }
3349
- await (0, import_promises2.rm)(destPath, { recursive: true, force: true });
3433
+ await (0, import_promises3.rm)(destPath, { recursive: true, force: true });
3350
3434
  }
3351
3435
  try {
3352
- await (0, import_promises2.rename)(sourcePath, destPath);
3436
+ await (0, import_promises3.rename)(sourcePath, destPath);
3353
3437
  } catch {
3354
- await (0, import_promises2.copyFile)(sourcePath, destPath);
3355
- await (0, import_promises2.rm)(sourcePath, { recursive: true, force: true });
3438
+ await (0, import_promises3.copyFile)(sourcePath, destPath);
3439
+ await (0, import_promises3.rm)(sourcePath, { recursive: true, force: true });
3356
3440
  }
3357
3441
  };
3358
3442
  var moveFiles = async (sourceDir, destDir, overwrite = false) => {
3359
- await (0, import_promises2.mkdir)(destDir, { recursive: true });
3360
- const files = await (0, import_promises2.readdir)(sourceDir);
3443
+ await (0, import_promises3.mkdir)(destDir, { recursive: true });
3444
+ const files = await (0, import_promises3.readdir)(sourceDir);
3361
3445
  for (const file of files) {
3362
3446
  const sourceFile = (0, import_node_path.join)(sourceDir, file);
3363
3447
  const destFile = (0, import_node_path.join)(destDir, file);
3364
3448
  if (!overwrite) {
3365
3449
  try {
3366
- await (0, import_promises2.access)(destFile, import_node_fs.constants.F_OK);
3367
- await (0, import_promises2.rm)(sourceFile, { recursive: true, force: true });
3450
+ await (0, import_promises3.access)(destFile, import_node_fs.constants.F_OK);
3451
+ await (0, import_promises3.rm)(sourceFile, { recursive: true, force: true });
3368
3452
  continue;
3369
3453
  } catch {
3370
3454
  }
@@ -3377,10 +3461,10 @@ var moveFiles = async (sourceDir, destDir, overwrite = false) => {
3377
3461
  var ProjectTools = class {
3378
3462
  async extractTemplate(zipPath, workspacePath, tempExtractDir, input) {
3379
3463
  await unzipFile(zipPath, tempExtractDir);
3380
- let sourceDir = path10.join(tempExtractDir, input.extractedDirName);
3464
+ let sourceDir = path11.join(tempExtractDir, input.extractedDirName);
3381
3465
  let actualDirName = input.extractedDirName;
3382
3466
  if (!await this.pathExists(sourceDir)) {
3383
- const entries = await fs7.readdir(tempExtractDir, { withFileTypes: true });
3467
+ const entries = await fs8.readdir(tempExtractDir, { withFileTypes: true });
3384
3468
  const directories = entries.filter(
3385
3469
  (entry) => entry.isDirectory() && !entry.name.startsWith(".")
3386
3470
  );
@@ -3392,7 +3476,7 @@ var ProjectTools = class {
3392
3476
  );
3393
3477
  if (selectedDirectory) {
3394
3478
  actualDirName = selectedDirectory;
3395
- sourceDir = path10.join(tempExtractDir, actualDirName);
3479
+ sourceDir = path11.join(tempExtractDir, actualDirName);
3396
3480
  } else if (directories.length === 0) {
3397
3481
  throw new Error(
3398
3482
  `No directory found after extraction. Expected directory: ${input.extractedDirName}`
@@ -3442,7 +3526,7 @@ var ProjectTools = class {
3442
3526
  } else {
3443
3527
  for (const scriptPath of scripts) {
3444
3528
  try {
3445
- await fs7.chmod(scriptPath, 493);
3529
+ await fs8.chmod(scriptPath, 493);
3446
3530
  updatedCount += 1;
3447
3531
  } catch {
3448
3532
  }
@@ -3490,7 +3574,7 @@ var ProjectTools = class {
3490
3574
  };
3491
3575
  }
3492
3576
  async ensurePresetManifest(workspacePath, preset) {
3493
- const presetManifestPath = path10.join(
3577
+ const presetManifestPath = path11.join(
3494
3578
  workspacePath,
3495
3579
  ".ms-scaffold",
3496
3580
  "presets",
@@ -3499,11 +3583,11 @@ var ProjectTools = class {
3499
3583
  if (await this.pathExists(presetManifestPath)) {
3500
3584
  return;
3501
3585
  }
3502
- const projectModePath = path10.join(workspacePath, ".ms-scaffold", "project-mode.json");
3586
+ const projectModePath = path11.join(workspacePath, ".ms-scaffold", "project-mode.json");
3503
3587
  if (!await this.pathExists(projectModePath)) {
3504
3588
  return;
3505
3589
  }
3506
- const projectModeRaw = await fs7.readFile(projectModePath, "utf8");
3590
+ const projectModeRaw = await fs8.readFile(projectModePath, "utf8");
3507
3591
  const projectMode = JSON.parse(projectModeRaw);
3508
3592
  const synthesizedPreset = {
3509
3593
  preset,
@@ -3515,8 +3599,8 @@ var ProjectTools = class {
3515
3599
  mergeManagedFiles: [],
3516
3600
  userOwnedPaths: []
3517
3601
  };
3518
- await fs7.mkdir(path10.dirname(presetManifestPath), { recursive: true });
3519
- await fs7.writeFile(
3602
+ await fs8.mkdir(path11.dirname(presetManifestPath), { recursive: true });
3603
+ await fs8.writeFile(
3520
3604
  presetManifestPath,
3521
3605
  `${JSON.stringify(synthesizedPreset, null, 2)}
3522
3606
  `,
@@ -3527,12 +3611,12 @@ var ProjectTools = class {
3527
3611
  const results = [];
3528
3612
  let entries;
3529
3613
  try {
3530
- entries = await fs7.readdir(dir, { withFileTypes: true });
3614
+ entries = await fs8.readdir(dir, { withFileTypes: true });
3531
3615
  } catch {
3532
3616
  return results;
3533
3617
  }
3534
3618
  for (const entry of entries) {
3535
- const fullPath = path10.join(dir, entry.name);
3619
+ const fullPath = path11.join(dir, entry.name);
3536
3620
  if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
3537
3621
  results.push(...await this.findScripts(fullPath, extensions));
3538
3622
  } else if (entry.isFile() && extensions.some((ext) => entry.name.endsWith(ext))) {
@@ -3543,7 +3627,7 @@ var ProjectTools = class {
3543
3627
  }
3544
3628
  async pathExists(targetPath) {
3545
3629
  try {
3546
- await fs7.access(targetPath);
3630
+ await fs8.access(targetPath);
3547
3631
  return true;
3548
3632
  } catch {
3549
3633
  return false;
@@ -3560,7 +3644,7 @@ var ProjectTools = class {
3560
3644
  const matches = [];
3561
3645
  for (const directoryName of directoryNames) {
3562
3646
  if (await this.directoryMatchesProjectPattern(
3563
- path10.join(tempExtractDir, directoryName),
3647
+ path11.join(tempExtractDir, directoryName),
3564
3648
  projectFilePattern
3565
3649
  )) {
3566
3650
  matches.push(directoryName);
@@ -3572,7 +3656,7 @@ var ProjectTools = class {
3572
3656
  return null;
3573
3657
  }
3574
3658
  async directoryMatchesProjectPattern(directoryPath, projectFilePattern) {
3575
- const entries = await fs7.readdir(directoryPath);
3659
+ const entries = await fs8.readdir(directoryPath);
3576
3660
  if (projectFilePattern.includes("*")) {
3577
3661
  const regex = new RegExp(`^${projectFilePattern.replace("*", ".*")}$`);
3578
3662
  return entries.some((entry) => regex.test(entry));
@@ -3585,8 +3669,8 @@ function createProjectTools() {
3585
3669
  }
3586
3670
 
3587
3671
  // src/repo-manager/index.ts
3588
- var fs8 = __toESM(require("fs/promises"));
3589
- var path11 = __toESM(require("path"));
3672
+ var fs9 = __toESM(require("fs/promises"));
3673
+ var path12 = __toESM(require("path"));
3590
3674
 
3591
3675
  // src/repos/types.ts
3592
3676
  function isDefaultRepo(repo) {
@@ -3668,11 +3752,11 @@ var RepoManager = class {
3668
3752
  const exists = await this.pathExists(localPath);
3669
3753
  if (exists) {
3670
3754
  if (await this.isValidGitRepo(localPath)) continue;
3671
- await fs8.rm(localPath, { recursive: true, force: true });
3755
+ await fs9.rm(localPath, { recursive: true, force: true });
3672
3756
  }
3673
3757
  try {
3674
3758
  if (!this.skipClone) {
3675
- await fs8.mkdir(path11.dirname(localPath), { recursive: true });
3759
+ await fs9.mkdir(path12.dirname(localPath), { recursive: true });
3676
3760
  await this.git.clone(repo.id, repo.url, localPath, repo.branch, true);
3677
3761
  }
3678
3762
  await this.store.updateRepo(repo.id, {
@@ -3707,10 +3791,10 @@ var RepoManager = class {
3707
3791
  const localPath = getRepoDir(repoId);
3708
3792
  const exists = await this.pathExists(localPath);
3709
3793
  if (exists && !await this.isValidGitRepo(localPath)) {
3710
- await fs8.rm(localPath, { recursive: true, force: true });
3794
+ await fs9.rm(localPath, { recursive: true, force: true });
3711
3795
  }
3712
3796
  if (!exists || !await this.pathExists(localPath)) {
3713
- await fs8.mkdir(path11.dirname(localPath), { recursive: true });
3797
+ await fs9.mkdir(path12.dirname(localPath), { recursive: true });
3714
3798
  if (!this.skipClone) {
3715
3799
  await this.git.clone(proxyId, repo.url, localPath, repo.branch, useProxy);
3716
3800
  }
@@ -3810,7 +3894,7 @@ var RepoManager = class {
3810
3894
  let cloned = false;
3811
3895
  if (!this.skipClone) {
3812
3896
  const localPath = getRepoDir(id);
3813
- await fs8.mkdir(path11.dirname(localPath), { recursive: true });
3897
+ await fs9.mkdir(path12.dirname(localPath), { recursive: true });
3814
3898
  await this.git.clone(userProxyId, url, localPath, branch, useProxy);
3815
3899
  cloned = true;
3816
3900
  }
@@ -3835,7 +3919,7 @@ var RepoManager = class {
3835
3919
  await this.store.removeUserRepo(repoId);
3836
3920
  const localPath = getRepoDir(repoId);
3837
3921
  try {
3838
- await fs8.rm(localPath, { recursive: true, force: true });
3922
+ await fs9.rm(localPath, { recursive: true, force: true });
3839
3923
  } catch (err) {
3840
3924
  if (err.code !== "ENOENT") throw err;
3841
3925
  }
@@ -3858,7 +3942,7 @@ var RepoManager = class {
3858
3942
  }
3859
3943
  /** Force-create the SERVICEME home directory tree (idempotent). */
3860
3944
  async ensureHome() {
3861
- await fs8.mkdir(getServicemeHome(), { recursive: true });
3945
+ await fs9.mkdir(getServicemeHome(), { recursive: true });
3862
3946
  }
3863
3947
  /**
3864
3948
  * Returns `true` when `p` contains a `.git` entry — i.e. it is an
@@ -3866,11 +3950,11 @@ var RepoManager = class {
3866
3950
  * (e.g. from an interrupted clone) return `false`.
3867
3951
  */
3868
3952
  async isValidGitRepo(p) {
3869
- return this.pathExists(path11.join(p, ".git"));
3953
+ return this.pathExists(path12.join(p, ".git"));
3870
3954
  }
3871
3955
  async pathExists(p) {
3872
3956
  try {
3873
- await fs8.stat(p);
3957
+ await fs9.stat(p);
3874
3958
  return true;
3875
3959
  } catch {
3876
3960
  return false;
@@ -3995,8 +4079,8 @@ function resolveDefaultRepoId(existing, existingIds) {
3995
4079
  }
3996
4080
 
3997
4081
  // src/repos/loader.ts
3998
- var fs9 = __toESM(require("fs/promises"));
3999
- var path12 = __toESM(require("path"));
4082
+ var fs10 = __toESM(require("fs/promises"));
4083
+ var path13 = __toESM(require("path"));
4000
4084
  var import_zod = require("zod");
4001
4085
  var ISO_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})$/;
4002
4086
  var repoIdSchema = import_zod.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}$/");
@@ -4079,7 +4163,7 @@ var ReposLoader = class {
4079
4163
  this.configPath = options.configPath;
4080
4164
  this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
4081
4165
  this.randomSuffix = options.randomSuffix ?? defaultRandomSuffix;
4082
- this.fileSystem = options.fileSystem ?? fs9;
4166
+ this.fileSystem = options.fileSystem ?? fs10;
4083
4167
  }
4084
4168
  /** Absolute path of the file this loader reads/writes. */
4085
4169
  getConfigPath() {
@@ -4132,7 +4216,7 @@ var ReposLoader = class {
4132
4216
  */
4133
4217
  async save(config) {
4134
4218
  const validated = reposFileSchema.parse(config);
4135
- const dir = path12.dirname(this.configPath);
4219
+ const dir = path13.dirname(this.configPath);
4136
4220
  await this.fileSystem.mkdir(dir, { recursive: true });
4137
4221
  const serialized = `${JSON.stringify(validated, null, 2)}
4138
4222
  `;
@@ -4141,7 +4225,7 @@ var ReposLoader = class {
4141
4225
  try {
4142
4226
  await this.fileSystem.rename(tempPath, this.configPath);
4143
4227
  } catch (error) {
4144
- const unlink2 = this.fileSystem.unlink ?? fs9.unlink;
4228
+ const unlink2 = this.fileSystem.unlink ?? fs10.unlink;
4145
4229
  await unlink2(tempPath).catch(() => void 0);
4146
4230
  throw error;
4147
4231
  }
@@ -4201,7 +4285,7 @@ function narrowRepoConfig(repo) {
4201
4285
 
4202
4286
  // src/repos/store.ts
4203
4287
  var import_node_events2 = require("events");
4204
- var fs10 = __toESM(require("fs"));
4288
+ var fs11 = __toESM(require("fs"));
4205
4289
  var ReposStore = class {
4206
4290
  constructor(options = {}) {
4207
4291
  this.config = null;
@@ -4210,7 +4294,7 @@ var ReposStore = class {
4210
4294
  this.reloadTimer = null;
4211
4295
  this.lastLoadResult = null;
4212
4296
  this.loader = options.loader ?? new ReposLoader({ configPath: "" });
4213
- this.fileSystem = options.fileSystem ?? { watch: fs10.watch };
4297
+ this.fileSystem = options.fileSystem ?? { watch: fs11.watch };
4214
4298
  this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
4215
4299
  this.debounceMs = options.debounceMs ?? 50;
4216
4300
  this.createFsWatcher = options.createFsWatcher ?? ((p, cb) => this.defaultCreateFsWatcher(p, cb));
@@ -4492,17 +4576,17 @@ async function bootstrapDefaults(store) {
4492
4576
  }
4493
4577
 
4494
4578
  // src/scheduled-tasks/daemon/DaemonLogger.ts
4495
- var fs11 = __toESM(require("fs"));
4496
- var path13 = __toESM(require("path"));
4579
+ var fs12 = __toESM(require("fs"));
4580
+ var path14 = __toESM(require("path"));
4497
4581
  var CONFIG_DIR = ".serviceme";
4498
4582
  var LOG_FILE = "scheduler.log";
4499
4583
  var MAX_LOG_SIZE = 1024 * 1024;
4500
4584
  var DaemonLogger = class {
4501
4585
  constructor(workspacePath, options = {}) {
4502
- this.logPath = options.logPath ?? path13.join(workspacePath, CONFIG_DIR, LOG_FILE);
4503
- const dir = path13.dirname(this.logPath);
4504
- if (!fs11.existsSync(dir)) {
4505
- fs11.mkdirSync(dir, { recursive: true });
4586
+ this.logPath = options.logPath ?? path14.join(workspacePath, CONFIG_DIR, LOG_FILE);
4587
+ const dir = path14.dirname(this.logPath);
4588
+ if (!fs12.existsSync(dir)) {
4589
+ fs12.mkdirSync(dir, { recursive: true });
4506
4590
  }
4507
4591
  }
4508
4592
  getLogPath() {
@@ -4513,16 +4597,16 @@ var DaemonLogger = class {
4513
4597
  const line = `[${ts}] [${level.toUpperCase()}] ${message}
4514
4598
  `;
4515
4599
  this.rotateIfNeeded();
4516
- fs11.appendFileSync(this.logPath, line, "utf-8");
4600
+ fs12.appendFileSync(this.logPath, line, "utf-8");
4517
4601
  }
4518
4602
  rotateIfNeeded() {
4519
4603
  try {
4520
- const stats = fs11.statSync(this.logPath);
4604
+ const stats = fs12.statSync(this.logPath);
4521
4605
  if (stats.size > MAX_LOG_SIZE) {
4522
- const content = fs11.readFileSync(this.logPath, "utf-8");
4606
+ const content = fs12.readFileSync(this.logPath, "utf-8");
4523
4607
  const halfIdx = content.indexOf("\n", Math.floor(content.length / 2));
4524
4608
  if (halfIdx > 0) {
4525
- fs11.writeFileSync(this.logPath, content.slice(halfIdx + 1), "utf-8");
4609
+ fs12.writeFileSync(this.logPath, content.slice(halfIdx + 1), "utf-8");
4526
4610
  }
4527
4611
  }
4528
4612
  } catch {
@@ -4531,39 +4615,39 @@ var DaemonLogger = class {
4531
4615
  };
4532
4616
 
4533
4617
  // src/scheduled-tasks/daemon/PidManager.ts
4534
- var fs12 = __toESM(require("fs"));
4535
- var path14 = __toESM(require("path"));
4618
+ var fs13 = __toESM(require("fs"));
4619
+ var path15 = __toESM(require("path"));
4536
4620
  var CONFIG_DIR2 = ".serviceme";
4537
4621
  var PID_FILE = "scheduler.pid";
4538
4622
  var PidManager = class {
4539
4623
  constructor(workspacePath, options = {}) {
4540
- this.pidPath = options.pidPath ?? path14.join(workspacePath, CONFIG_DIR2, PID_FILE);
4624
+ this.pidPath = options.pidPath ?? path15.join(workspacePath, CONFIG_DIR2, PID_FILE);
4541
4625
  }
4542
4626
  getPidPath() {
4543
4627
  return this.pidPath;
4544
4628
  }
4545
4629
  writePid(pid) {
4546
- const dir = path14.dirname(this.pidPath);
4547
- if (!fs12.existsSync(dir)) {
4548
- fs12.mkdirSync(dir, { recursive: true });
4630
+ const dir = path15.dirname(this.pidPath);
4631
+ if (!fs13.existsSync(dir)) {
4632
+ fs13.mkdirSync(dir, { recursive: true });
4549
4633
  }
4550
- fs12.writeFileSync(this.pidPath, String(pid), "utf-8");
4634
+ fs13.writeFileSync(this.pidPath, String(pid), "utf-8");
4551
4635
  }
4552
4636
  readPid() {
4553
4637
  let stat5;
4554
4638
  try {
4555
- stat5 = fs12.statSync(this.pidPath);
4639
+ stat5 = fs13.statSync(this.pidPath);
4556
4640
  } catch {
4557
4641
  return null;
4558
4642
  }
4559
4643
  if (!stat5.isFile()) return null;
4560
- const raw = fs12.readFileSync(this.pidPath, "utf-8").trim();
4644
+ const raw = fs13.readFileSync(this.pidPath, "utf-8").trim();
4561
4645
  const pid = Number.parseInt(raw, 10);
4562
4646
  return Number.isNaN(pid) ? null : pid;
4563
4647
  }
4564
4648
  removePid() {
4565
- if (fs12.existsSync(this.pidPath)) {
4566
- fs12.unlinkSync(this.pidPath);
4649
+ if (fs13.existsSync(this.pidPath)) {
4650
+ fs13.unlinkSync(this.pidPath);
4567
4651
  }
4568
4652
  }
4569
4653
  isProcessRunning(pid) {
@@ -4584,13 +4668,13 @@ var PidManager = class {
4584
4668
  };
4585
4669
 
4586
4670
  // src/scheduled-tasks/daemon/SchedulerDaemon.ts
4587
- var fs17 = __toESM(require("fs"));
4671
+ var fs18 = __toESM(require("fs"));
4588
4672
  var os5 = __toESM(require("os"));
4589
- var path18 = __toESM(require("path"));
4673
+ var path19 = __toESM(require("path"));
4590
4674
 
4591
4675
  // src/scheduled-tasks/executors/GithubCopilotCliExecutor.ts
4592
4676
  var import_node_child_process3 = require("child_process");
4593
- var fs13 = __toESM(require("fs"));
4677
+ var fs14 = __toESM(require("fs"));
4594
4678
 
4595
4679
  // src/scheduled-tasks/executors/timeout.ts
4596
4680
  function resolveConfiguredTimeoutMs(timeoutSeconds, defaultTimeoutMs) {
@@ -4625,7 +4709,7 @@ function redactArgs(args) {
4625
4709
  function writeDiagnostic(message) {
4626
4710
  const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
4627
4711
  if (logPath) {
4628
- fs13.appendFileSync(logPath, message);
4712
+ fs14.appendFileSync(logPath, message);
4629
4713
  return;
4630
4714
  }
4631
4715
  process.stderr.write(message);
@@ -4831,15 +4915,15 @@ ${body}`.trim()
4831
4915
 
4832
4916
  // src/scheduled-tasks/executors/ShellExecutor.ts
4833
4917
  var import_node_child_process4 = require("child_process");
4834
- var fs14 = __toESM(require("fs"));
4835
- var path15 = __toESM(require("path"));
4918
+ var fs15 = __toESM(require("fs"));
4919
+ var path16 = __toESM(require("path"));
4836
4920
  var MAX_OUTPUT_BYTES2 = 1024 * 1024;
4837
4921
  var DEFAULT_TIMEOUT_MS4 = 6e4;
4838
4922
  var POSIX_SHELL_CANDIDATES = ["bash.exe", "sh.exe"];
4839
4923
  function resolveShellExecution(script, options = {}) {
4840
4924
  const platform3 = options.platform ?? process.platform;
4841
4925
  const env = options.env ?? process.env;
4842
- const fileExists = options.fileExists ?? fs14.existsSync;
4926
+ const fileExists = options.fileExists ?? fs15.existsSync;
4843
4927
  if (platform3 === "win32") {
4844
4928
  const posixShell = usesPosixShellSyntax(script) ? findWindowsPosixShell(env, fileExists) : null;
4845
4929
  if (posixShell) {
@@ -4884,10 +4968,10 @@ function findWindowsPosixShell(env, fileExists) {
4884
4968
  if (fileExists(candidate)) return candidate;
4885
4969
  }
4886
4970
  const pathValue = env.Path ?? env.PATH ?? "";
4887
- for (const dir of pathValue.split(path15.win32.delimiter)) {
4971
+ for (const dir of pathValue.split(path16.win32.delimiter)) {
4888
4972
  if (!dir) continue;
4889
4973
  for (const executable of POSIX_SHELL_CANDIDATES) {
4890
- const candidate = path15.win32.join(dir, executable);
4974
+ const candidate = path16.win32.join(dir, executable);
4891
4975
  if (fileExists(candidate) && !isWindowsWslLauncher(candidate)) {
4892
4976
  return candidate;
4893
4977
  }
@@ -4896,13 +4980,13 @@ function findWindowsPosixShell(env, fileExists) {
4896
4980
  return null;
4897
4981
  }
4898
4982
  function isWindowsWslLauncher(candidate) {
4899
- const normalized = path15.win32.normalize(candidate).toLowerCase();
4983
+ const normalized = path16.win32.normalize(candidate).toLowerCase();
4900
4984
  return normalized.endsWith("\\windows\\system32\\bash.exe") || normalized.endsWith("\\windows\\syswow64\\bash.exe");
4901
4985
  }
4902
4986
  function writeDiagnostic2(message) {
4903
4987
  const logPath = process.env.SERVICEME_SCHEDULER_LOG_PATH;
4904
4988
  if (logPath) {
4905
- fs14.appendFileSync(logPath, message);
4989
+ fs15.appendFileSync(logPath, message);
4906
4990
  return;
4907
4991
  }
4908
4992
  process.stderr.write(message);
@@ -5044,10 +5128,10 @@ function getExecutor(taskType) {
5044
5128
  }
5045
5129
 
5046
5130
  // src/scheduled-tasks/TaskConfigManager.ts
5047
- var import_node_crypto5 = require("crypto");
5048
- var fs15 = __toESM(require("fs"));
5131
+ var import_node_crypto6 = require("crypto");
5132
+ var fs16 = __toESM(require("fs"));
5049
5133
  var os4 = __toESM(require("os"));
5050
- var path16 = __toESM(require("path"));
5134
+ var path17 = __toESM(require("path"));
5051
5135
  var import_devtools_protocol8 = require("@serviceme/devtools-protocol");
5052
5136
  function emptyConfig() {
5053
5137
  return { version: 2, tasks: [] };
@@ -5071,7 +5155,7 @@ function v1ContainerShape(value) {
5071
5155
  }
5072
5156
  function defaultWorkspaceContext() {
5073
5157
  const home = os4.homedir() || "/";
5074
- return { path: home, name: path16.basename(home) || home };
5158
+ return { path: home, name: path17.basename(home) || home };
5075
5159
  }
5076
5160
  function requireNonEmptyString(payload, field, taskType) {
5077
5161
  if (!isRecord2(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
@@ -5106,10 +5190,10 @@ var TaskConfigManager = class {
5106
5190
  return this.configPath;
5107
5191
  }
5108
5192
  readConfig() {
5109
- if (!fs15.existsSync(this.configPath)) {
5193
+ if (!fs16.existsSync(this.configPath)) {
5110
5194
  return emptyConfig();
5111
5195
  }
5112
- const raw = fs15.readFileSync(this.configPath, "utf-8");
5196
+ const raw = fs16.readFileSync(this.configPath, "utf-8");
5113
5197
  let parsed;
5114
5198
  try {
5115
5199
  parsed = JSON.parse(raw);
@@ -5162,7 +5246,7 @@ var TaskConfigManager = class {
5162
5246
  const target = this.migrationFailuresPath ?? getMigrationFailuresPath();
5163
5247
  const prior = (() => {
5164
5248
  try {
5165
- return JSON.parse(fs15.readFileSync(target, "utf-8"));
5249
+ return JSON.parse(fs16.readFileSync(target, "utf-8"));
5166
5250
  } catch {
5167
5251
  return [];
5168
5252
  }
@@ -5175,8 +5259,8 @@ var TaskConfigManager = class {
5175
5259
  snippet: raw.slice(0, 500),
5176
5260
  recordedAt: (/* @__PURE__ */ new Date()).toISOString()
5177
5261
  });
5178
- fs15.mkdirSync(path16.dirname(target), { recursive: true });
5179
- fs15.writeFileSync(target, JSON.stringify(failures, null, " "), "utf-8");
5262
+ fs16.mkdirSync(path17.dirname(target), { recursive: true });
5263
+ fs16.writeFileSync(target, JSON.stringify(failures, null, " "), "utf-8");
5180
5264
  } catch (writeError) {
5181
5265
  this.warn(
5182
5266
  `TaskConfigManager: also failed to write migration-failures log: ${String(writeError)}`
@@ -5184,13 +5268,13 @@ var TaskConfigManager = class {
5184
5268
  }
5185
5269
  }
5186
5270
  writeConfig(config) {
5187
- const dir = path16.dirname(this.configPath);
5188
- if (!fs15.existsSync(dir)) {
5189
- fs15.mkdirSync(dir, { recursive: true });
5271
+ const dir = path17.dirname(this.configPath);
5272
+ if (!fs16.existsSync(dir)) {
5273
+ fs16.mkdirSync(dir, { recursive: true });
5190
5274
  }
5191
5275
  const tmp = `${this.configPath}.tmp`;
5192
- fs15.writeFileSync(tmp, JSON.stringify(config, null, " "), "utf-8");
5193
- fs15.renameSync(tmp, this.configPath);
5276
+ fs16.writeFileSync(tmp, JSON.stringify(config, null, " "), "utf-8");
5277
+ fs16.renameSync(tmp, this.configPath);
5194
5278
  }
5195
5279
  listTasks() {
5196
5280
  return this.readConfig().tasks;
@@ -5212,7 +5296,7 @@ var TaskConfigManager = class {
5212
5296
  const config = this.readConfig();
5213
5297
  const now = (/* @__PURE__ */ new Date()).toISOString();
5214
5298
  const task = {
5215
- id: (0, import_node_crypto5.randomUUID)(),
5299
+ id: (0, import_node_crypto6.randomUUID)(),
5216
5300
  name: input.name,
5217
5301
  description: input.description,
5218
5302
  enabled: input.enabled ?? true,
@@ -5467,9 +5551,9 @@ var TaskExecutionEngine = class {
5467
5551
  };
5468
5552
 
5469
5553
  // src/scheduled-tasks/TaskLogManager.ts
5470
- var import_node_crypto6 = require("crypto");
5471
- var fs16 = __toESM(require("fs"));
5472
- var path17 = __toESM(require("path"));
5554
+ var import_node_crypto7 = require("crypto");
5555
+ var fs17 = __toESM(require("fs"));
5556
+ var path18 = __toESM(require("path"));
5473
5557
  var MAX_LOGS = 200;
5474
5558
  function emptyLogFile() {
5475
5559
  return { logs: [] };
@@ -5498,11 +5582,11 @@ var TaskLogManager = class {
5498
5582
  return this.logPath;
5499
5583
  }
5500
5584
  readLogFile() {
5501
- if (!fs16.existsSync(this.logPath)) {
5585
+ if (!fs17.existsSync(this.logPath)) {
5502
5586
  return emptyLogFile();
5503
5587
  }
5504
5588
  try {
5505
- const raw = fs16.readFileSync(this.logPath, "utf-8");
5589
+ const raw = fs17.readFileSync(this.logPath, "utf-8");
5506
5590
  const parsed = JSON.parse(raw);
5507
5591
  const file = validateAndRepairLogFile(parsed);
5508
5592
  if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.logs) || parsed.logs.length !== file.logs.length) {
@@ -5518,26 +5602,26 @@ var TaskLogManager = class {
5518
5602
  }
5519
5603
  backupCorruptedFile() {
5520
5604
  try {
5521
- if (fs16.existsSync(this.logPath)) {
5605
+ if (fs17.existsSync(this.logPath)) {
5522
5606
  const backupPath = `${this.logPath}.corrupted.${Date.now()}`;
5523
- fs16.copyFileSync(this.logPath, backupPath);
5607
+ fs17.copyFileSync(this.logPath, backupPath);
5524
5608
  }
5525
5609
  } catch {
5526
5610
  }
5527
5611
  }
5528
5612
  writeLogFile(file) {
5529
- const dir = path17.dirname(this.logPath);
5530
- if (!fs16.existsSync(dir)) {
5531
- fs16.mkdirSync(dir, { recursive: true });
5613
+ const dir = path18.dirname(this.logPath);
5614
+ if (!fs17.existsSync(dir)) {
5615
+ fs17.mkdirSync(dir, { recursive: true });
5532
5616
  }
5533
5617
  const tmp = `${this.logPath}.tmp`;
5534
- fs16.writeFileSync(tmp, JSON.stringify(file, null, " "), "utf-8");
5535
- fs16.renameSync(tmp, this.logPath);
5618
+ fs17.writeFileSync(tmp, JSON.stringify(file, null, " "), "utf-8");
5619
+ fs17.renameSync(tmp, this.logPath);
5536
5620
  }
5537
5621
  appendLog(input) {
5538
5622
  const file = this.readLogFile();
5539
5623
  const log = {
5540
- id: (0, import_node_crypto6.randomUUID)(),
5624
+ id: (0, import_node_crypto7.randomUUID)(),
5541
5625
  taskId: input.taskId,
5542
5626
  taskName: input.taskName,
5543
5627
  startedAt: input.startedAt,
@@ -5592,12 +5676,12 @@ var SchedulerDaemon = class {
5592
5676
  this.lastRun = /* @__PURE__ */ new Map();
5593
5677
  this.taskRunning = /* @__PURE__ */ new Set();
5594
5678
  this.workspacePath = workspacePath;
5595
- const configDir = path18.join(workspacePath, ".serviceme");
5679
+ const configDir = path19.join(workspacePath, ".serviceme");
5596
5680
  this.configManager = new TaskConfigManager({
5597
- configPath: path18.join(configDir, "scheduled-tasks.json")
5681
+ configPath: path19.join(configDir, "scheduled-tasks.json")
5598
5682
  });
5599
5683
  this.logManager = new TaskLogManager({
5600
- logPath: path18.join(configDir, "scheduled-tasks-log.json")
5684
+ logPath: path19.join(configDir, "scheduled-tasks-log.json")
5601
5685
  });
5602
5686
  this.pidManager = new PidManager(workspacePath);
5603
5687
  this.logger = new DaemonLogger(workspacePath);
@@ -5649,8 +5733,8 @@ var SchedulerDaemon = class {
5649
5733
  const configPath = this.configManager.getConfigPath();
5650
5734
  const dir = configPath.substring(0, configPath.lastIndexOf("/"));
5651
5735
  try {
5652
- if (fs17.existsSync(dir)) {
5653
- this.watcher = fs17.watch(dir, (_eventType, filename) => {
5736
+ if (fs18.existsSync(dir)) {
5737
+ this.watcher = fs18.watch(dir, (_eventType, filename) => {
5654
5738
  if (filename === "scheduled-tasks.json") {
5655
5739
  this.logger.log("info", "Config file changed, reconciling...");
5656
5740
  }
@@ -5803,9 +5887,9 @@ function matchCronField(field, value) {
5803
5887
  }
5804
5888
 
5805
5889
  // src/scheduled-tasks/daemon/SchedulerDaemonV2.ts
5806
- var fs18 = __toESM(require("fs"));
5890
+ var fs19 = __toESM(require("fs"));
5807
5891
  var os6 = __toESM(require("os"));
5808
- var path19 = __toESM(require("path"));
5892
+ var path20 = __toESM(require("path"));
5809
5893
  var TICK_INTERVAL2 = 1e3;
5810
5894
  var MIN_SCHEDULE_INTERVAL2 = 1e3;
5811
5895
  var SCHEDULER_LOG_FILENAME2 = "scheduler.log";
@@ -5825,7 +5909,7 @@ var SchedulerDaemonV2 = class {
5825
5909
  this.logManager = options.logManager ?? new TaskLogManager();
5826
5910
  this.pidManager = options.pidManager ?? new PidManager("", { pidPath: getSchedulerPidPath() });
5827
5911
  this.logger = options.logger ?? new DaemonLogger(os6.homedir(), {
5828
- logPath: path19.join(path19.dirname(this.pidManager.getPidPath()), SCHEDULER_LOG_FILENAME2)
5912
+ logPath: path20.join(path20.dirname(this.pidManager.getPidPath()), SCHEDULER_LOG_FILENAME2)
5829
5913
  });
5830
5914
  this.getExecutor = options.getExecutor ?? getExecutor;
5831
5915
  this.tryAcquireLock = options.tryAcquireLock ?? (() => true);
@@ -5883,7 +5967,7 @@ var SchedulerDaemonV2 = class {
5883
5967
  const now = Date.now();
5884
5968
  for (const task of config.tasks) {
5885
5969
  if (!task.enabled) continue;
5886
- if (!fs18.existsSync(task.workspace.path)) {
5970
+ if (!fs19.existsSync(task.workspace.path)) {
5887
5971
  this.disableTaskForMissingWorkspace(task, config);
5888
5972
  continue;
5889
5973
  }
@@ -6040,21 +6124,21 @@ function matchCronField2(field, value) {
6040
6124
  }
6041
6125
 
6042
6126
  // src/scheduled-tasks/migration/MigrateToGlobal.ts
6043
- var fs19 = __toESM(require("fs"));
6044
- var path20 = __toESM(require("path"));
6127
+ var fs20 = __toESM(require("fs"));
6128
+ var path21 = __toESM(require("path"));
6045
6129
  var import_devtools_protocol9 = require("@serviceme/devtools-protocol");
6046
6130
  var WORKSPACE_DIR = ".serviceme";
6047
6131
  var V1_FILENAME = "scheduled-tasks.json";
6048
6132
  function defaultProbe(workspacePath) {
6049
6133
  return {
6050
6134
  path: workspacePath,
6051
- name: path20.basename(workspacePath) || workspacePath
6135
+ name: path21.basename(workspacePath) || workspacePath
6052
6136
  };
6053
6137
  }
6054
6138
  function readV1Config(v1Path) {
6055
6139
  let raw;
6056
6140
  try {
6057
- raw = fs19.readFileSync(v1Path, "utf-8");
6141
+ raw = fs20.readFileSync(v1Path, "utf-8");
6058
6142
  } catch (err) {
6059
6143
  return {
6060
6144
  ok: false,
@@ -6077,27 +6161,27 @@ function readV1Config(v1Path) {
6077
6161
  }
6078
6162
  function safeDelete(filePath) {
6079
6163
  try {
6080
- fs19.unlinkSync(filePath);
6164
+ fs20.unlinkSync(filePath);
6081
6165
  } catch {
6082
6166
  }
6083
6167
  }
6084
6168
  function ensureDir(filePath) {
6085
- const dir = path20.dirname(filePath);
6086
- if (!fs19.existsSync(dir)) {
6087
- fs19.mkdirSync(dir, { recursive: true });
6169
+ const dir = path21.dirname(filePath);
6170
+ if (!fs20.existsSync(dir)) {
6171
+ fs20.mkdirSync(dir, { recursive: true });
6088
6172
  }
6089
6173
  }
6090
6174
  function readJsonFile(filePath) {
6091
- if (!fs19.existsSync(filePath)) return null;
6175
+ if (!fs20.existsSync(filePath)) return null;
6092
6176
  try {
6093
- return JSON.parse(fs19.readFileSync(filePath, "utf-8"));
6177
+ return JSON.parse(fs20.readFileSync(filePath, "utf-8"));
6094
6178
  } catch {
6095
6179
  return null;
6096
6180
  }
6097
6181
  }
6098
6182
  function writeJsonFile(filePath, data) {
6099
6183
  ensureDir(filePath);
6100
- fs19.writeFileSync(filePath, JSON.stringify(data, null, " "), "utf-8");
6184
+ fs20.writeFileSync(filePath, JSON.stringify(data, null, " "), "utf-8");
6101
6185
  }
6102
6186
  function disambiguateName(task, existingNames, workspaceName) {
6103
6187
  if (!existingNames.has(task.name)) {
@@ -6127,8 +6211,8 @@ async function migrateToGlobal(options) {
6127
6211
  const conflicts = [];
6128
6212
  const issues = [];
6129
6213
  for (const workspacePath of options.workspacePaths) {
6130
- const v1Path = path20.join(workspacePath, WORKSPACE_DIR, V1_FILENAME);
6131
- if (!fs19.existsSync(v1Path)) continue;
6214
+ const v1Path = path21.join(workspacePath, WORKSPACE_DIR, V1_FILENAME);
6215
+ if (!fs20.existsSync(v1Path)) continue;
6132
6216
  const v1 = readV1Config(v1Path);
6133
6217
  if (!v1.ok) {
6134
6218
  failures.push({
@@ -6170,8 +6254,8 @@ async function migrateToGlobal(options) {
6170
6254
  if (migrated > 0) {
6171
6255
  ensureDir(globalConfigPath);
6172
6256
  const tmp = `${globalConfigPath}.tmp`;
6173
- fs19.writeFileSync(tmp, JSON.stringify(baseConfig, null, " "), "utf-8");
6174
- fs19.renameSync(tmp, globalConfigPath);
6257
+ fs20.writeFileSync(tmp, JSON.stringify(baseConfig, null, " "), "utf-8");
6258
+ fs20.renameSync(tmp, globalConfigPath);
6175
6259
  }
6176
6260
  if (failures.length > priorFailures.length) {
6177
6261
  writeJsonFile(migrationFailuresPath, failures);
@@ -6188,8 +6272,8 @@ async function migrateToGlobal(options) {
6188
6272
 
6189
6273
  // src/scheduled-tasks/workspace-probe/WorkspaceProbe.ts
6190
6274
  var import_node_child_process5 = require("child_process");
6191
- var fs20 = __toESM(require("fs"));
6192
- var path21 = __toESM(require("path"));
6275
+ var fs21 = __toESM(require("fs"));
6276
+ var path22 = __toESM(require("path"));
6193
6277
  var DEFAULT_TIMEOUT_MS5 = 2e3;
6194
6278
  var GitTimeoutError = class extends Error {
6195
6279
  constructor() {
@@ -6252,8 +6336,8 @@ var WorkspaceProbe = class {
6252
6336
  }
6253
6337
  }
6254
6338
  async probe(workspacePath) {
6255
- const name = path21.basename(workspacePath) || workspacePath;
6256
- if (!workspacePath || !fs20.existsSync(workspacePath)) {
6339
+ const name = path22.basename(workspacePath) || workspacePath;
6340
+ if (!workspacePath || !fs21.existsSync(workspacePath)) {
6257
6341
  return {
6258
6342
  workspace: { path: workspacePath, name },
6259
6343
  error: "path-not-found"
@@ -6405,8 +6489,8 @@ var SkillReconciler = class {
6405
6489
  };
6406
6490
 
6407
6491
  // src/skills/SkillStore.ts
6408
- var fs21 = __toESM(require("fs/promises"));
6409
- var path22 = __toESM(require("path"));
6492
+ var fs22 = __toESM(require("fs/promises"));
6493
+ var path23 = __toESM(require("path"));
6410
6494
  var USER_SKILL_MARKER_FILE = ".serviceme-skill.json";
6411
6495
  var LEGACY_USER_SKILL_MARKER_FILE = ".ms-devtools-skill.json";
6412
6496
  var WORKSPACE_SKILLS_ROOT_RELATIVE = ".github/skills";
@@ -6422,7 +6506,7 @@ var SkillStore = class {
6422
6506
  constructor(options) {
6423
6507
  this.workspacePath = options.workspacePath;
6424
6508
  this.userSkillsRoot = options.userSkillsRoot;
6425
- this.fileSystem = options.fileSystem ?? fs21;
6509
+ this.fileSystem = options.fileSystem ?? fs22;
6426
6510
  }
6427
6511
  normalizeRemoteSkillId(remoteId) {
6428
6512
  if (remoteId.startsWith("official/")) {
@@ -6441,10 +6525,10 @@ var SkillStore = class {
6441
6525
  return WORKSPACE_SKILLS_MARKER_RELATIVE;
6442
6526
  }
6443
6527
  getUserSkillPath(skillId) {
6444
- return path22.join(this.userSkillsRoot, skillId);
6528
+ return path23.join(this.userSkillsRoot, skillId);
6445
6529
  }
6446
6530
  async listWorkspaceSkillIds() {
6447
- const skillsRootPath = path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE);
6531
+ const skillsRootPath = path23.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE);
6448
6532
  try {
6449
6533
  const entries = await this.fileSystem.readdir(skillsRootPath, {
6450
6534
  withFileTypes: true
@@ -6468,7 +6552,7 @@ var SkillStore = class {
6468
6552
  const targetDir = this.getUserSkillPath(skillId);
6469
6553
  await this.fileSystem.mkdir(targetDir, { recursive: true });
6470
6554
  await this.fileSystem.writeFile(
6471
- path22.join(targetDir, USER_SKILL_MARKER_FILE),
6555
+ path23.join(targetDir, USER_SKILL_MARKER_FILE),
6472
6556
  JSON.stringify({ skillId, installedBy: "serviceme" }, null, 2),
6473
6557
  "utf-8"
6474
6558
  );
@@ -6477,7 +6561,7 @@ var SkillStore = class {
6477
6561
  await this.migrateLegacyUserSkillMarker(skillId);
6478
6562
  try {
6479
6563
  const marker = await this.fileSystem.readFile(
6480
- path22.join(this.getUserSkillPath(skillId), USER_SKILL_MARKER_FILE),
6564
+ path23.join(this.getUserSkillPath(skillId), USER_SKILL_MARKER_FILE),
6481
6565
  "utf-8"
6482
6566
  );
6483
6567
  const parsed = JSON.parse(marker);
@@ -6494,8 +6578,8 @@ var SkillStore = class {
6494
6578
  */
6495
6579
  async migrateLegacyUserSkillMarker(skillId) {
6496
6580
  const targetDir = this.getUserSkillPath(skillId);
6497
- const newPath = path22.join(targetDir, USER_SKILL_MARKER_FILE);
6498
- const legacyPath = path22.join(targetDir, LEGACY_USER_SKILL_MARKER_FILE);
6581
+ const newPath = path23.join(targetDir, USER_SKILL_MARKER_FILE);
6582
+ const legacyPath = path23.join(targetDir, LEGACY_USER_SKILL_MARKER_FILE);
6499
6583
  try {
6500
6584
  await this.fileSystem.readFile(newPath, "utf-8");
6501
6585
  return;
@@ -6508,12 +6592,12 @@ var SkillStore = class {
6508
6592
  }
6509
6593
  }
6510
6594
  async writeSkillFiles(skillId, scope, files) {
6511
- const root = scope === "workspace" ? path22.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
6512
- const targetDir = path22.join(root, skillId);
6595
+ const root = scope === "workspace" ? path23.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
6596
+ const targetDir = path23.join(root, skillId);
6513
6597
  await this.fileSystem.mkdir(targetDir, { recursive: true });
6514
6598
  for (const file of files) {
6515
- const filePath = path22.join(targetDir, file.path);
6516
- await this.fileSystem.mkdir(path22.dirname(filePath), { recursive: true });
6599
+ const filePath = path23.join(targetDir, file.path);
6600
+ await this.fileSystem.mkdir(path23.dirname(filePath), { recursive: true });
6517
6601
  await this.fileSystem.writeFile(filePath, file.content, "utf-8");
6518
6602
  if (file.executable) {
6519
6603
  try {
@@ -6526,8 +6610,8 @@ var SkillStore = class {
6526
6610
  };
6527
6611
 
6528
6612
  // src/submit/index.ts
6529
- var fs22 = __toESM(require("fs/promises"));
6530
- var path23 = __toESM(require("path"));
6613
+ var fs23 = __toESM(require("fs/promises"));
6614
+ var path24 = __toESM(require("path"));
6531
6615
 
6532
6616
  // src/submit/types.ts
6533
6617
  var SubmitError = class extends Error {
@@ -6577,14 +6661,14 @@ var SubmitClient = class {
6577
6661
  throw new SubmitError(v.reason ?? "unknown", v.detail ?? "validation denied");
6578
6662
  }
6579
6663
  const localRepoPath = getRepoDir(repoId);
6580
- const targetDir = path23.join(localRepoPath, "skills", skillName);
6581
- await fs22.mkdir(targetDir, { recursive: true });
6664
+ const targetDir = path24.join(localRepoPath, "skills", skillName);
6665
+ await fs23.mkdir(targetDir, { recursive: true });
6582
6666
  for (const f of files) {
6583
- const full = path23.join(targetDir, f.path);
6584
- await fs22.mkdir(path23.dirname(full), { recursive: true });
6667
+ const full = path24.join(targetDir, f.path);
6668
+ await fs23.mkdir(path24.dirname(full), { recursive: true });
6585
6669
  const tmp = `${full}.${process.pid}.${Date.now()}.tmp`;
6586
- await fs22.writeFile(tmp, f.content, "utf8");
6587
- await fs22.rename(tmp, full);
6670
+ await fs23.writeFile(tmp, f.content, "utf8");
6671
+ await fs23.rename(tmp, full);
6588
6672
  }
6589
6673
  const commitMessage = `feat(skills): add ${skillName}`;
6590
6674
  const { commitSha } = await this.git.commit(localRepoPath, commitMessage);
@@ -6653,8 +6737,8 @@ function touchLastUsedAt(tools, id, when = /* @__PURE__ */ new Date()) {
6653
6737
 
6654
6738
  // src/toolbox/ToolboxStore.ts
6655
6739
  var fsp2 = __toESM(require("fs/promises"));
6656
- var path24 = __toESM(require("path"));
6657
- var import_promises3 = require("timers/promises");
6740
+ var path25 = __toESM(require("path"));
6741
+ var import_promises4 = require("timers/promises");
6658
6742
 
6659
6743
  // src/toolbox/types.ts
6660
6744
  var TOOLBOX_JSON_SCHEMA_VERSION = 1;
@@ -6688,11 +6772,11 @@ var LOCK_DIR_MODE2 = 448;
6688
6772
  var DEFAULT_LOCK_TIMEOUT_MS2 = 5e3;
6689
6773
  var DEFAULT_LOCK_RETRY_MS2 = 25;
6690
6774
  var TMP_SUFFIX2 = ".tmp";
6691
- var WORKSPACE_TOOLBOX_RELATIVE_PATH = path24.join(".github", ".serviceme-toolbox.json");
6775
+ var WORKSPACE_TOOLBOX_RELATIVE_PATH = path25.join(".github", ".serviceme-toolbox.json");
6692
6776
  var LEGACY_WORKSPACE_TOOLBOX_FILENAME = ".ms-devtools-toolbox.json";
6693
6777
  async function migrateLegacyWorkspaceToolboxFile(filePath) {
6694
6778
  if (!filePath) return;
6695
- const legacyPath = path24.join(path24.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
6779
+ const legacyPath = path25.join(path25.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
6696
6780
  if (legacyPath === filePath) return;
6697
6781
  try {
6698
6782
  await fsp2.access(filePath);
@@ -6737,7 +6821,7 @@ var FsToolboxFileBackend = class {
6737
6821
  }
6738
6822
  }
6739
6823
  async write(filePath, payload) {
6740
- await fsp2.mkdir(path24.dirname(filePath), { recursive: true });
6824
+ await fsp2.mkdir(path25.dirname(filePath), { recursive: true });
6741
6825
  const tmpPath = `${filePath}${TMP_SUFFIX2}`;
6742
6826
  const bytes = Buffer.from(JSON.stringify(payload, null, " "), "utf8");
6743
6827
  await fsp2.rm(tmpPath, { force: true });
@@ -6788,7 +6872,7 @@ var ToolboxFileLock = class {
6788
6872
  if (Date.now() - start >= this.timeoutMs) {
6789
6873
  throw new Error(`ToolboxStore lock acquisition timed out for ${this.dirPath}`);
6790
6874
  }
6791
- await (0, import_promises3.setTimeout)(this.retryMs);
6875
+ await (0, import_promises4.setTimeout)(this.retryMs);
6792
6876
  }
6793
6877
  }
6794
6878
  }
@@ -6800,7 +6884,7 @@ var ToolboxFileLock = class {
6800
6884
  };
6801
6885
  function defaultWorkspacePath() {
6802
6886
  if (process.env.SERVICEME_NO_WORKSPACE_TOOLBOX === "1") return null;
6803
- return path24.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
6887
+ return path25.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
6804
6888
  }
6805
6889
  var ToolboxStore = class {
6806
6890
  constructor(opts = {}) {
@@ -7108,6 +7192,7 @@ var ToolboxCore = class {
7108
7192
  SCHEDULER_LOCK_FILENAME,
7109
7193
  SCHEDULER_LOG_FILENAME,
7110
7194
  SCHEDULER_PID_FILENAME,
7195
+ SERVER_PROXY_GLOBAL_FILENAME,
7111
7196
  SERVICEME_DIR_NAME,
7112
7197
  SERVICEME_HOME_ENV,
7113
7198
  SKILL_DRAFTS_SUBDIR,
@@ -7175,6 +7260,7 @@ var ToolboxCore = class {
7175
7260
  getSchedulerLockPath,
7176
7261
  getSchedulerLogPath,
7177
7262
  getSchedulerPidPath,
7263
+ getServerProxyGlobalPath,
7178
7264
  getServicemeHome,
7179
7265
  getSkillDraftsDir,
7180
7266
  getToolboxJsonPath,
@@ -7185,6 +7271,7 @@ var ToolboxCore = class {
7185
7271
  isUserRepo,
7186
7272
  matchesCron,
7187
7273
  mergeWithDefaults,
7274
+ migrateLegacyServerProxyEnabled,
7188
7275
  migrateToGlobal,
7189
7276
  moveFiles,
7190
7277
  narrowRepoConfig,
@@ -7192,6 +7279,7 @@ var ToolboxCore = class {
7192
7279
  parseAgentToolPermissions,
7193
7280
  parseIntervalMs,
7194
7281
  randomInstallationId,
7282
+ readServerProxyGlobal,
7195
7283
  reindexOrder,
7196
7284
  reposFileSchema,
7197
7285
  resetUserHomeOverrides,
@@ -7206,6 +7294,7 @@ var ToolboxCore = class {
7206
7294
  unzipFile,
7207
7295
  userRepoConfigSchema,
7208
7296
  validateReposFile,
7209
- validateTaskPayload
7297
+ validateTaskPayload,
7298
+ writeServerProxyGlobal
7210
7299
  });
7211
7300
  //# sourceMappingURL=index.js.map