@camstack/agent 1.1.43 → 1.1.45

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.
@@ -65,6 +65,9 @@ var require_dist = __commonJS({
65
65
  var src_exports = {};
66
66
  __export(src_exports, {
67
67
  AGENT_ROOT_SPEC: () => AGENT_ROOT_SPEC,
68
+ DEV_UPLOADS_DIRNAME: () => DEV_UPLOADS_DIRNAME,
69
+ DEV_UPLOADS_KEEP_COUNT: () => DEV_UPLOADS_KEEP_COUNT,
70
+ DEV_UPLOAD_MANIFEST_FILE: () => DEV_UPLOAD_MANIFEST_FILE,
68
71
  HOST_EXTERNAL_SPECIFIERS: () => HOST_EXTERNAL_SPECIFIERS,
69
72
  HUB_ROOT_SPEC: () => HUB_ROOT_SPEC,
70
73
  RESTART_INTENT_FILE: () => RESTART_INTENT_FILE,
@@ -74,11 +77,17 @@ var require_dist = __commonJS({
74
77
  clearRestartIntentMarker: () => clearRestartIntentMarker,
75
78
  compareSemver: () => compareSemver,
76
79
  detectWorkspaceRoot: () => detectWorkspaceRoot,
80
+ devChannelEpoch: () => devChannelEpoch,
81
+ devUploadManifestPath: () => devUploadManifestPath,
82
+ devUploadVersionDir: () => devUploadVersionDir,
83
+ devUploadsDir: () => devUploadsDir,
77
84
  emptyServerRootState: () => emptyServerRootState,
85
+ isDevChannelVersion: () => isDevChannelVersion,
78
86
  isHostExternal: () => isHostExternal,
79
87
  isServerRootState: () => isServerRootState,
80
88
  minNodeMajorOf: () => minNodeMajorOf,
81
89
  planBoot: () => planBoot,
90
+ readDevUploadManifest: () => readDevUploadManifest,
82
91
  readRestartIntentMarker: () => readRestartIntentMarker,
83
92
  readServerRootState: () => readServerRootState,
84
93
  registerActiveRootResolver: () => registerActiveRootResolver,
@@ -91,10 +100,58 @@ var require_dist = __commonJS({
91
100
  validateVersionDir: () => validateVersionDir,
92
101
  versionDir: () => versionDir,
93
102
  versionsDir: () => versionsDir,
103
+ writeDevUploadManifest: () => writeDevUploadManifest,
94
104
  writeRestartIntentMarker: () => writeRestartIntentMarker,
95
105
  writeServerRootState: () => writeServerRootState
96
106
  });
97
107
  module.exports = __toCommonJS(src_exports);
108
+ var fs = __toESM2(__require("fs"));
109
+ var path = __toESM2(__require("path"));
110
+ var DEV_UPLOADS_DIRNAME = "dev-uploads";
111
+ var DEV_UPLOAD_MANIFEST_FILE = "manifest.json";
112
+ var DEV_UPLOADS_KEEP_COUNT = 3;
113
+ var DEV_CHANNEL_VERSION_RE = /-dev\.\d+$/;
114
+ function isDevChannelVersion(version) {
115
+ return DEV_CHANNEL_VERSION_RE.test(version);
116
+ }
117
+ function devChannelEpoch(version) {
118
+ const match = /-dev\.(\d+)$/.exec(version);
119
+ if (match === null) return null;
120
+ const epoch = Number.parseInt(match[1] ?? "", 10);
121
+ return Number.isNaN(epoch) ? null : epoch;
122
+ }
123
+ function devUploadsDir(rootDir) {
124
+ return path.join(rootDir, DEV_UPLOADS_DIRNAME);
125
+ }
126
+ function devUploadVersionDir(rootDir, version) {
127
+ return path.join(devUploadsDir(rootDir), version);
128
+ }
129
+ function devUploadManifestPath(versionDirPath) {
130
+ return path.join(versionDirPath, DEV_UPLOAD_MANIFEST_FILE);
131
+ }
132
+ function isDevUploadManifest(v) {
133
+ if (typeof v !== "object" || v === null) return false;
134
+ const m = v;
135
+ if (typeof m["version"] !== "string") return false;
136
+ const packages = m["packages"];
137
+ if (typeof packages !== "object" || packages === null || Array.isArray(packages)) return false;
138
+ return Object.values(packages).every((filename) => typeof filename === "string");
139
+ }
140
+ function readDevUploadManifest(versionDirPath) {
141
+ try {
142
+ const raw = JSON.parse(fs.readFileSync(devUploadManifestPath(versionDirPath), "utf-8"));
143
+ return isDevUploadManifest(raw) ? raw : null;
144
+ } catch {
145
+ return null;
146
+ }
147
+ }
148
+ function writeDevUploadManifest(versionDirPath, manifest) {
149
+ fs.mkdirSync(versionDirPath, { recursive: true });
150
+ const target = devUploadManifestPath(versionDirPath);
151
+ const tmp = `${target}.tmp`;
152
+ fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), "utf-8");
153
+ fs.renameSync(tmp, target);
154
+ }
98
155
  var HUB_ROOT_SPEC = {
99
156
  packageName: "@camstack/server",
100
157
  entryRelPath: ["dist", "launcher.js"]
@@ -103,8 +160,8 @@ var require_dist = __commonJS({
103
160
  packageName: "@camstack/agent",
104
161
  entryRelPath: ["dist", "cli.js"]
105
162
  };
106
- var fs = __toESM2(__require("fs"));
107
- var path = __toESM2(__require("path"));
163
+ var fs2 = __toESM2(__require("fs"));
164
+ var path2 = __toESM2(__require("path"));
108
165
  var SERVER_ROOT_DIRNAME = "server-root";
109
166
  var SERVER_ROOT_STATE_FILE = "state.json";
110
167
  var RESTART_INTENT_FILE = ".restart-intent";
@@ -118,22 +175,22 @@ var require_dist = __commonJS({
118
175
  };
119
176
  }
120
177
  function serverRootDir(dataDir) {
121
- return path.join(dataDir, SERVER_ROOT_DIRNAME);
178
+ return path2.join(dataDir, SERVER_ROOT_DIRNAME);
122
179
  }
123
180
  function versionsDir(rootDir) {
124
- return path.join(rootDir, "versions");
181
+ return path2.join(rootDir, "versions");
125
182
  }
126
183
  function versionDir(rootDir, version) {
127
- return path.join(versionsDir(rootDir), version);
184
+ return path2.join(versionsDir(rootDir), version);
128
185
  }
129
186
  function rootPackageDir(versionDirPath, spec) {
130
- return path.join(versionDirPath, "node_modules", ...spec.packageName.split("/"));
187
+ return path2.join(versionDirPath, "node_modules", ...spec.packageName.split("/"));
131
188
  }
132
189
  function rootEntryPath(versionDirPath, spec) {
133
- return path.join(rootPackageDir(versionDirPath, spec), ...spec.entryRelPath);
190
+ return path2.join(rootPackageDir(versionDirPath, spec), ...spec.entryRelPath);
134
191
  }
135
192
  function stateFilePath(rootDir) {
136
- return path.join(rootDir, SERVER_ROOT_STATE_FILE);
193
+ return path2.join(rootDir, SERVER_ROOT_STATE_FILE);
137
194
  }
138
195
  function isNullableString(v) {
139
196
  return v === null || typeof v === "string";
@@ -160,21 +217,21 @@ var require_dist = __commonJS({
160
217
  }
161
218
  function readServerRootState(rootDir) {
162
219
  try {
163
- const raw = JSON.parse(fs.readFileSync(stateFilePath(rootDir), "utf-8"));
220
+ const raw = JSON.parse(fs2.readFileSync(stateFilePath(rootDir), "utf-8"));
164
221
  return isServerRootState(raw) ? raw : null;
165
222
  } catch {
166
223
  return null;
167
224
  }
168
225
  }
169
226
  function writeServerRootState(rootDir, state) {
170
- fs.mkdirSync(rootDir, { recursive: true });
227
+ fs2.mkdirSync(rootDir, { recursive: true });
171
228
  const target = stateFilePath(rootDir);
172
229
  const tmp = `${target}.tmp`;
173
- fs.writeFileSync(tmp, JSON.stringify(state, null, 2), "utf-8");
174
- fs.renameSync(tmp, target);
230
+ fs2.writeFileSync(tmp, JSON.stringify(state, null, 2), "utf-8");
231
+ fs2.renameSync(tmp, target);
175
232
  }
176
233
  function restartIntentMarkerPath(rootDir) {
177
- return path.join(rootDir, RESTART_INTENT_FILE);
234
+ return path2.join(rootDir, RESTART_INTENT_FILE);
178
235
  }
179
236
  function isRestartIntentMarker(v) {
180
237
  if (typeof v !== "object" || v === null) return false;
@@ -182,15 +239,15 @@ var require_dist = __commonJS({
182
239
  return typeof m["requestedAtMs"] === "number" && typeof m["reason"] === "string";
183
240
  }
184
241
  function writeRestartIntentMarker(rootDir, marker) {
185
- fs.mkdirSync(rootDir, { recursive: true });
242
+ fs2.mkdirSync(rootDir, { recursive: true });
186
243
  const target = restartIntentMarkerPath(rootDir);
187
244
  const tmp = `${target}.tmp`;
188
- fs.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
189
- fs.renameSync(tmp, target);
245
+ fs2.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
246
+ fs2.renameSync(tmp, target);
190
247
  }
191
248
  function readRestartIntentMarker(rootDir) {
192
249
  try {
193
- const raw = JSON.parse(fs.readFileSync(restartIntentMarkerPath(rootDir), "utf-8"));
250
+ const raw = JSON.parse(fs2.readFileSync(restartIntentMarkerPath(rootDir), "utf-8"));
194
251
  return isRestartIntentMarker(raw) ? raw : null;
195
252
  } catch {
196
253
  return null;
@@ -198,7 +255,7 @@ var require_dist = __commonJS({
198
255
  }
199
256
  function clearRestartIntentMarker(rootDir) {
200
257
  try {
201
- fs.rmSync(restartIntentMarkerPath(rootDir), { force: true });
258
+ fs2.rmSync(restartIntentMarkerPath(rootDir), { force: true });
202
259
  } catch {
203
260
  }
204
261
  }
@@ -211,13 +268,13 @@ var require_dist = __commonJS({
211
268
  function validateVersionDir(rootDir, version, nodeMajor, spec) {
212
269
  const vDir = versionDir(rootDir, version);
213
270
  const entry = rootEntryPath(vDir, spec);
214
- if (!fs.existsSync(entry)) {
271
+ if (!fs2.existsSync(entry)) {
215
272
  return `root entry missing: ${entry}`;
216
273
  }
217
- const pkgJsonPath = path.join(rootPackageDir(vDir, spec), "package.json");
274
+ const pkgJsonPath = path2.join(rootPackageDir(vDir, spec), "package.json");
218
275
  let pkg;
219
276
  try {
220
- const raw = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
277
+ const raw = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
221
278
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
222
279
  return `package.json malformed: ${pkgJsonPath}`;
223
280
  }
@@ -364,25 +421,25 @@ var require_dist = __commonJS({
364
421
  if (pa.prerelease > pb.prerelease) return 1;
365
422
  return 0;
366
423
  }
367
- var fs2 = __toESM2(__require("fs"));
368
- var path2 = __toESM2(__require("path"));
424
+ var fs3 = __toESM2(__require("fs"));
425
+ var path3 = __toESM2(__require("path"));
369
426
  function detectWorkspaceRoot(fromDir) {
370
- let dir = path2.resolve(fromDir);
427
+ let dir = path3.resolve(fromDir);
371
428
  for (; ; ) {
372
- const pkgPath = path2.join(dir, "package.json");
429
+ const pkgPath = path3.join(dir, "package.json");
373
430
  try {
374
- const raw = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
431
+ const raw = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
375
432
  if (typeof raw === "object" && raw !== null && raw["workspaces"] !== void 0) {
376
433
  return dir;
377
434
  }
378
435
  } catch {
379
436
  }
380
- const parent = path2.dirname(dir);
437
+ const parent = path3.dirname(dir);
381
438
  if (parent === dir) return null;
382
439
  dir = parent;
383
440
  }
384
441
  }
385
- var path3 = __toESM2(__require("path"));
442
+ var path4 = __toESM2(__require("path"));
386
443
  var import_node_url = __require("url");
387
444
  var HOST_EXTERNAL_SPECIFIERS = [
388
445
  "@camstack/system",
@@ -410,7 +467,7 @@ var require_dist = __commonJS({
410
467
  return;
411
468
  }
412
469
  const anchorURL = (0, import_node_url.pathToFileURL)(
413
- path3.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")
470
+ path4.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")
414
471
  ).href;
415
472
  const hooks = {
416
473
  resolve: (specifier, context, nextResolve) => {
@@ -488,8 +545,8 @@ var require_dist = __commonJS({
488
545
  options.loadEntry(options.seedEntry);
489
546
  }
490
547
  var import_node_child_process = __require("child_process");
491
- var fs3 = __toESM2(__require("fs"));
492
- var path4 = __toESM2(__require("path"));
548
+ var fs4 = __toESM2(__require("fs"));
549
+ var path5 = __toESM2(__require("path"));
493
550
  var import_node_util = __require("util");
494
551
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
495
552
  function buildNpmRegistryArgs(registry) {
@@ -501,7 +558,7 @@ var require_dist = __commonJS({
501
558
  var RESTART_REASON_PREFIX = "server-update";
502
559
  function readPackageVersion(pkgJsonPath) {
503
560
  try {
504
- const raw = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
561
+ const raw = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
505
562
  if (typeof raw === "object" && raw !== null) {
506
563
  const version = raw["version"];
507
564
  if (typeof version === "string") return version;
@@ -528,7 +585,7 @@ var require_dist = __commonJS({
528
585
  this.envNames = options.envNames;
529
586
  this.logger = options.logger;
530
587
  this.restartServerFn = options.restartServer;
531
- this.dataDir = path4.resolve(options.dataDir);
588
+ this.dataDir = path5.resolve(options.dataDir);
532
589
  this.execNpm = options.execNpm ?? (async (args, opts) => {
533
590
  const { stdout } = await execFileAsync("npm", [...args], {
534
591
  cwd: opts.cwd,
@@ -557,7 +614,7 @@ var require_dist = __commonJS({
557
614
  seedVersion() {
558
615
  const seedDir = this.env[this.envNames.seedDir];
559
616
  if (seedDir === void 0 || seedDir.length === 0) return null;
560
- return readPackageVersion(path4.join(seedDir, "package.json"));
617
+ return readPackageVersion(path5.join(seedDir, "package.json"));
561
618
  }
562
619
  rootDir() {
563
620
  return serverRootDir(this.dataDir);
@@ -575,7 +632,7 @@ var require_dist = __commonJS({
575
632
  const rootDir = this.rootDir();
576
633
  const raw = readServerRootState(rootDir);
577
634
  if (raw !== null) return { state: raw, corrupt: false };
578
- return { state: emptyServerRootState(), corrupt: fs3.existsSync(stateFilePath(rootDir)) };
635
+ return { state: emptyServerRootState(), corrupt: fs4.existsSync(stateFilePath(rootDir)) };
579
636
  }
580
637
  updateState(state) {
581
638
  if (this.inFlight === "checking") return "checking";
@@ -715,6 +772,17 @@ var require_dist = __commonJS({
715
772
  message: `Refused: ${this.spec.packageName}@${target} is already running.`
716
773
  };
717
774
  }
775
+ if (isDevChannelVersion(target)) {
776
+ const uploadsDir = devUploadVersionDir(this.rootDir(), target);
777
+ if (!fs4.existsSync(uploadsDir)) {
778
+ return {
779
+ accepted: false,
780
+ targetVersion: target,
781
+ restarting: false,
782
+ message: `Refused: dev-channel version ${target} has no uploaded tarballs on this node (${uploadsDir} is missing). Dev server deploys are hub-only in this phase \u2014 upload via \`camstack deploy-server\` against this node first.`
783
+ };
784
+ }
785
+ }
718
786
  this.inFlight = "staging";
719
787
  try {
720
788
  await this.stageAndActivate(target);
@@ -761,34 +829,40 @@ var require_dist = __commonJS({
761
829
  async stageAndActivate(target) {
762
830
  const rootDir = this.rootDir();
763
831
  const vDir = versionsDir(rootDir);
764
- fs3.mkdirSync(vDir, { recursive: true });
765
- const stagingDir = path4.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`);
766
- fs3.mkdirSync(stagingDir, { recursive: true });
832
+ fs4.mkdirSync(vDir, { recursive: true });
833
+ const stagingDir = path5.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`);
834
+ fs4.mkdirSync(stagingDir, { recursive: true });
767
835
  try {
768
- fs3.writeFileSync(
769
- path4.join(stagingDir, "package.json"),
770
- JSON.stringify({ name: "camstack-node-root", private: true }, null, 2),
771
- "utf-8"
772
- );
836
+ const devDir = devUploadVersionDir(rootDir, target);
773
837
  const registry = this.env["CAMSTACK_NPM_REGISTRY"];
774
- await this.execNpm(
775
- [
776
- "install",
777
- "--omit=dev",
778
- "--no-audit",
779
- "--no-fund",
780
- "--loglevel=error",
781
- `${this.spec.packageName}@${target}`,
782
- ...buildNpmRegistryArgs(registry)
783
- ],
784
- { cwd: stagingDir, timeoutMs: NPM_INSTALL_TIMEOUT_MS }
785
- );
838
+ const installArgs = ["install", "--omit=dev", "--no-audit", "--no-fund", "--loglevel=error"];
839
+ if (fs4.existsSync(devDir)) {
840
+ fs4.writeFileSync(
841
+ path5.join(stagingDir, "package.json"),
842
+ JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2),
843
+ "utf-8"
844
+ );
845
+ await this.execNpm([...installArgs, ...buildNpmRegistryArgs(registry)], {
846
+ cwd: stagingDir,
847
+ timeoutMs: NPM_INSTALL_TIMEOUT_MS
848
+ });
849
+ } else {
850
+ fs4.writeFileSync(
851
+ path5.join(stagingDir, "package.json"),
852
+ JSON.stringify({ name: "camstack-node-root", private: true }, null, 2),
853
+ "utf-8"
854
+ );
855
+ await this.execNpm(
856
+ [...installArgs, `${this.spec.packageName}@${target}`, ...buildNpmRegistryArgs(registry)],
857
+ { cwd: stagingDir, timeoutMs: NPM_INSTALL_TIMEOUT_MS }
858
+ );
859
+ }
786
860
  const entry = rootEntryPath(stagingDir, this.spec);
787
- if (!fs3.existsSync(entry)) {
861
+ if (!fs4.existsSync(entry)) {
788
862
  throw new Error(`staged closure is missing the root entry (${entry})`);
789
863
  }
790
864
  const stagedVersion = readPackageVersion(
791
- path4.join(rootPackageDir(stagingDir, this.spec), "package.json")
865
+ path5.join(rootPackageDir(stagingDir, this.spec), "package.json")
792
866
  );
793
867
  if (stagedVersion !== target) {
794
868
  throw new Error(
@@ -796,17 +870,61 @@ var require_dist = __commonJS({
796
870
  );
797
871
  }
798
872
  const dest = versionDir(rootDir, target);
799
- if (fs3.existsSync(dest)) {
873
+ if (fs4.existsSync(dest)) {
800
874
  const aside = `${dest}.evicted-${this.now()}`;
801
- await fs3.promises.rename(dest, aside);
802
- await fs3.promises.rm(aside, { recursive: true, force: true }).catch(() => void 0);
875
+ await fs4.promises.rename(dest, aside);
876
+ await fs4.promises.rm(aside, { recursive: true, force: true }).catch(() => void 0);
803
877
  }
804
- await fs3.promises.rename(stagingDir, dest);
878
+ await fs4.promises.rename(stagingDir, dest);
805
879
  } catch (err) {
806
- await fs3.promises.rm(stagingDir, { recursive: true, force: true }).catch(() => void 0);
880
+ await fs4.promises.rm(stagingDir, { recursive: true, force: true }).catch(() => void 0);
807
881
  throw err;
808
882
  }
809
883
  }
884
+ /**
885
+ * Synthetic staging package.json for the dev server-deploy channel:
886
+ * `dependencies` carries the root package as a `file:` ref to its uploaded
887
+ * tgz; `overrides` maps EVERY OTHER uploaded `@camstack/<name>` to its tgz
888
+ * so any transitive occurrence resolves to the uploaded copy, never npm.
889
+ * Fail-closed: a missing/invalid manifest, a manifest for a different
890
+ * version, a missing root package, or a listed-but-absent tgz all throw
891
+ * (surfaced by `applyServerUpdate` as a staging failure).
892
+ */
893
+ buildDevUploadsPackageJson(devDir, target) {
894
+ const manifest = readDevUploadManifest(devDir);
895
+ if (manifest === null) {
896
+ throw new Error(`dev-uploads manifest missing or invalid in ${devDir}`);
897
+ }
898
+ if (manifest.version !== target) {
899
+ throw new Error(
900
+ `dev-uploads manifest version mismatch: dir is for ${target}, manifest says ${manifest.version}`
901
+ );
902
+ }
903
+ const rootTgz = manifest.packages[this.spec.packageName];
904
+ if (rootTgz === void 0) {
905
+ throw new Error(
906
+ `dev-uploads for ${target} do not include the root package ${this.spec.packageName}`
907
+ );
908
+ }
909
+ const fileRef = (filename) => {
910
+ const abs = path5.join(devDir, filename);
911
+ if (!fs4.existsSync(abs)) {
912
+ throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`);
913
+ }
914
+ return `file:${abs}`;
915
+ };
916
+ const overrides = {};
917
+ for (const [pkgName, filename] of Object.entries(manifest.packages)) {
918
+ if (pkgName === this.spec.packageName) continue;
919
+ overrides[pkgName] = fileRef(filename);
920
+ }
921
+ return {
922
+ name: "camstack-node-root",
923
+ private: true,
924
+ dependencies: { [this.spec.packageName]: fileRef(rootTgz) },
925
+ ...Object.keys(overrides).length > 0 ? { overrides } : {}
926
+ };
927
+ }
810
928
  // ── Rollback ──────────────────────────────────────────────────────────
811
929
  async rollbackServerUpdate() {
812
930
  if (this.inFlight !== "idle") {
@@ -936,6 +1054,7 @@ var require_dist = __commonJS({
936
1054
  (v) => typeof v === "string"
937
1055
  )
938
1056
  );
1057
+ this.sweepDevUploads(DEV_UPLOADS_KEEP_COUNT);
939
1058
  this.logger.info("root package update confirmed healthy", {
940
1059
  meta: {
941
1060
  version: promoted.currentVersion,
@@ -959,23 +1078,23 @@ var require_dist = __commonJS({
959
1078
  const vDir = versionsDir(this.rootDir());
960
1079
  let entries;
961
1080
  try {
962
- entries = fs3.readdirSync(vDir);
1081
+ entries = fs4.readdirSync(vDir);
963
1082
  } catch {
964
1083
  return;
965
1084
  }
966
1085
  for (const entry of entries) {
967
1086
  if (keep.includes(entry)) continue;
968
- const full = path4.join(vDir, entry);
1087
+ const full = path5.join(vDir, entry);
969
1088
  if (entry.startsWith(".")) {
970
1089
  try {
971
- const ageMs = this.now() - fs3.statSync(full).mtimeMs;
1090
+ const ageMs = this.now() - fs4.statSync(full).mtimeMs;
972
1091
  if (ageMs < _RootUpdateService.STALE_TRANSIENT_MS) continue;
973
1092
  } catch {
974
1093
  continue;
975
1094
  }
976
1095
  }
977
1096
  try {
978
- fs3.rmSync(full, { recursive: true, force: true });
1097
+ fs4.rmSync(full, { recursive: true, force: true });
979
1098
  this.logger.debug("pruned server-root version dir", { meta: { entry } });
980
1099
  } catch (err) {
981
1100
  this.logger.warn("failed to prune server-root version dir", {
@@ -984,6 +1103,56 @@ var require_dist = __commonJS({
984
1103
  }
985
1104
  }
986
1105
  }
1106
+ /**
1107
+ * Promote-time sweep of `server-root/dev-uploads/`: keep only the
1108
+ * `keepCount` most recent entries (ordered by the self-describing
1109
+ * `-dev.<epochSeconds>` suffix; non-dev-shaped residue counts as oldest).
1110
+ * Uses the same rename-aside graveyard pattern as the addon installer —
1111
+ * a rename is a metadata op that succeeds even when a tarball is held
1112
+ * open, and residue in the graveyard is re-swept on the next promote.
1113
+ */
1114
+ sweepDevUploads(keepCount) {
1115
+ const dir = devUploadsDir(this.rootDir());
1116
+ let entries;
1117
+ try {
1118
+ entries = fs4.readdirSync(dir);
1119
+ } catch {
1120
+ return;
1121
+ }
1122
+ const graveyard = path5.join(dir, ".sweeping");
1123
+ try {
1124
+ for (const residue of fs4.readdirSync(graveyard)) {
1125
+ try {
1126
+ fs4.rmSync(path5.join(graveyard, residue), { recursive: true, force: true });
1127
+ } catch {
1128
+ }
1129
+ }
1130
+ } catch {
1131
+ }
1132
+ const versions = entries.filter((name) => !name.startsWith("."));
1133
+ const byNewestFirst = [...versions].sort(
1134
+ (a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1)
1135
+ );
1136
+ const doomed = byNewestFirst.slice(keepCount);
1137
+ if (doomed.length === 0) return;
1138
+ fs4.mkdirSync(graveyard, { recursive: true });
1139
+ for (const entry of doomed) {
1140
+ const aside = path5.join(graveyard, `${entry}-${this.now()}`);
1141
+ try {
1142
+ fs4.renameSync(path5.join(dir, entry), aside);
1143
+ } catch (err) {
1144
+ this.logger.warn("failed to move dev-uploads entry aside for sweep", {
1145
+ meta: { entry, error: err instanceof Error ? err.message : String(err) }
1146
+ });
1147
+ continue;
1148
+ }
1149
+ try {
1150
+ fs4.rmSync(aside, { recursive: true, force: true });
1151
+ this.logger.debug("swept dev-uploads entry", { meta: { entry } });
1152
+ } catch {
1153
+ }
1154
+ }
1155
+ }
987
1156
  /** Transient (.staging- / .evicted-) dirs younger than this are never pruned. */
988
1157
  static STALE_TRANSIENT_MS = 24 * 60 * 60 * 1e3;
989
1158
  };
@@ -995,4 +1164,4 @@ export {
995
1164
  __toESM,
996
1165
  require_dist
997
1166
  };
998
- //# sourceMappingURL=chunk-L34OOQI3.mjs.map
1167
+ //# sourceMappingURL=chunk-Y6BUFOWG.mjs.map