@s2script/sdk 0.32.0 → 0.34.0

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/cli.js CHANGED
@@ -3517,7 +3517,7 @@ function stripJsonComments(src) {
3517
3517
  // src/gamedata/types.ts
3518
3518
  var PLATFORM = "linuxsteamrt64";
3519
3519
  var ARG_KINDS = ["bool", "int", "float", "string", "utlstring", "vector", "entity", "ptr"];
3520
- var RET_KINDS = ["void", "bool", "int", "float", "entity", "ptr"];
3520
+ var RET_KINDS = ["void", "bool", "int", "float", "entity", "ptr", "utlstringlist"];
3521
3521
  var INT_CLASS_ARGS = /* @__PURE__ */ new Set(["bool", "int", "string", "utlstring", "vector", "entity", "ptr"]);
3522
3522
  var MAX_INT_ARGS = 9;
3523
3523
  var MAX_FLOAT_ARGS = 8;
@@ -3587,11 +3587,14 @@ function validatePluginGamedata(gd, opts) {
3587
3587
  }
3588
3588
  const decl = rawDecl;
3589
3589
  const recv = decl.receiver;
3590
- if (!recv || recv.kind !== "entity" && recv.kind !== "none") {
3591
- errs.push(`${where2}: receiver.kind must be "entity" or "none"`);
3592
- } else if (recv.kind === "none") {
3590
+ if (!recv || recv.kind !== "entity" && recv.kind !== "none" && recv.kind !== "interface") {
3591
+ errs.push(`${where2}: receiver.kind must be "entity", "none" or "interface"`);
3592
+ } else if (recv.kind === "none" || recv.kind === "interface") {
3593
3593
  if (recv.via !== void 0) {
3594
- errs.push(`${where2}: receiver.kind "none" cannot carry a 'via' sub-object hop`);
3594
+ errs.push(`${where2}: receiver.kind "${recv.kind}" cannot carry a 'via' sub-object hop`);
3595
+ }
3596
+ if (recv.kind === "interface" && (typeof recv.name !== "string" || !recv.name.length)) {
3597
+ errs.push(`${where2}: receiver.kind "interface" needs a 'name' (the interface version string)`);
3595
3598
  }
3596
3599
  } else if (recv.via !== void 0) {
3597
3600
  const via = recv.via;
@@ -3959,14 +3962,15 @@ var RET_TS = {
3959
3962
  int: "number | null",
3960
3963
  float: "number | null",
3961
3964
  entity: "EntityRef | null",
3962
- ptr: "Ptr | null"
3965
+ ptr: "Ptr | null",
3966
+ utlstringlist: "string[] | null"
3963
3967
  };
3964
3968
  function generateGamedataTypes(gd) {
3965
3969
  const calls = gd.calls ?? {};
3966
3970
  const lines = Object.keys(calls).sort().map((name) => {
3967
3971
  const decl = calls[name];
3968
3972
  const names = decl.argNames;
3969
- const receiverless = decl.receiver?.kind === "none";
3973
+ const receiverless = decl.receiver?.kind === "none" || decl.receiver?.kind === "interface";
3970
3974
  const params = [
3971
3975
  ...receiverless ? [] : ["self: EntityRef"],
3972
3976
  ...decl.args.map((a2, i2) => `${names?.[i2] ?? `a${i2}`}: ${ARG_TS[a2]}`)
@@ -6591,7 +6595,7 @@ function positionals(args, flagsWithValue) {
6591
6595
 
6592
6596
  // src/workspace/build-all.ts
6593
6597
  import { writeFileSync as writeFileSync4 } from "node:fs";
6594
- import { join as join14 } from "node:path";
6598
+ import { join as join15 } from "node:path";
6595
6599
 
6596
6600
  // src/workspace/graph.ts
6597
6601
  function topoOrder(batch, warn = console.warn) {
@@ -6701,6 +6705,8 @@ function formatRangeViolations(violations) {
6701
6705
  }
6702
6706
 
6703
6707
  // src/workspace/bundle.ts
6708
+ import { existsSync as existsSync11, readFileSync as readFileSync12 } from "node:fs";
6709
+ import { join as join14 } from "node:path";
6704
6710
  var MAX_BUNDLE_MEMBERS = 64;
6705
6711
  function isBundleWorkspace(ws) {
6706
6712
  return ws.pkg.s2script?.kind === "bundle";
@@ -6710,11 +6716,50 @@ function scopeOf(name) {
6710
6716
  const slash = name.indexOf("/");
6711
6717
  return slash > 1 ? name.slice(1, slash) : null;
6712
6718
  }
6713
- function bundleProblems(ws) {
6714
- if (!isBundleWorkspace(ws)) return [];
6715
- const pkg = ws.pkg;
6716
- const problems = [];
6719
+ function bundlesField(ws) {
6720
+ return ws.pkg.s2script?.workspace?.bundles;
6721
+ }
6722
+ function bundleSources(ws) {
6723
+ const raw = bundlesField(ws);
6717
6724
  const where2 = "package.json (workspace root)";
6725
+ if (raw === void 0) return { sources: [], problems: [] };
6726
+ if (!Array.isArray(raw) || raw.some((g) => typeof g !== "string" || g === "")) {
6727
+ return { sources: [], problems: [`${where2}: s2script.workspace.bundles must be an array of directories or globs`] };
6728
+ }
6729
+ const problems = [];
6730
+ const seen = /* @__PURE__ */ new Set();
6731
+ const sources2 = [];
6732
+ for (const glob of raw) {
6733
+ const dirs = expandDirGlob(ws.root, glob).filter((rel) => existsSync11(join14(ws.root, rel, "package.json")));
6734
+ if (dirs.length === 0) {
6735
+ problems.push(`${where2}: s2script.workspace.bundles entry ${JSON.stringify(glob)} matches no directory with a package.json`);
6736
+ continue;
6737
+ }
6738
+ for (const rel of dirs) {
6739
+ if (seen.has(rel)) continue;
6740
+ seen.add(rel);
6741
+ const dir = join14(ws.root, rel);
6742
+ try {
6743
+ sources2.push({ relDir: rel, dir, pkg: JSON.parse(readFileSync12(join14(dir, "package.json"), "utf8")) });
6744
+ } catch (e) {
6745
+ sources2.push({ relDir: rel, dir, pkg: null, error: `cannot read ${rel}/package.json: ${e.message}` });
6746
+ }
6747
+ }
6748
+ }
6749
+ return { sources: sources2.sort((a2, b) => a2.relDir < b.relDir ? -1 : 1), problems };
6750
+ }
6751
+ function isUnder(relDir, bundleRel) {
6752
+ return bundleRel === "" || relDir.startsWith(`${bundleRel}/`);
6753
+ }
6754
+ function membersOf(ws, bundleRel) {
6755
+ return ws.plugins.filter((p) => !p.private && isUnder(p.relDir, bundleRel));
6756
+ }
6757
+ function optionalOf(pkg) {
6758
+ const optional = pkg.s2script?.bundle?.optional;
6759
+ return Array.isArray(optional) ? optional.filter((o) => typeof o === "string") : [];
6760
+ }
6761
+ function declarationProblems(where2, pkg, members) {
6762
+ const problems = [];
6718
6763
  if (typeof pkg.name !== "string" || pkg.name === "") {
6719
6764
  problems.push(`${where2}: a bundle needs a "name" \u2014 it is the bundle's registry name`);
6720
6765
  }
@@ -6723,13 +6768,12 @@ function bundleProblems(ws) {
6723
6768
  }
6724
6769
  if (pkg.private === true) {
6725
6770
  problems.push(
6726
- `${where2}: s2script.kind is "bundle" but the root is "private": true \u2014 a private root is never published; remove "private" or drop the bundle kind`
6771
+ `${where2}: s2script.kind is "bundle" but the package is "private": true \u2014 a private bundle is never published; remove "private" or drop the bundle kind`
6727
6772
  );
6728
6773
  }
6729
6774
  if (pkg.main !== void 0 || pkg.s2script?.main !== void 0) {
6730
6775
  problems.push(`${where2}: a bundle has no code of its own \u2014 remove "main"`);
6731
6776
  }
6732
- const members = ws.plugins.filter((p) => !p.private);
6733
6777
  if (members.length === 0) {
6734
6778
  problems.push(`${where2}: a bundle needs at least one non-private plugin in s2script.workspace.plugins`);
6735
6779
  }
@@ -6762,7 +6806,7 @@ function bundleProblems(ws) {
6762
6806
  for (const name of optional) {
6763
6807
  if (!memberNames.has(name)) {
6764
6808
  problems.push(
6765
- `${where2}: s2script.bundle.optional names ${JSON.stringify(name)}, which is not a non-private plugin of this workspace`
6809
+ `${where2}: s2script.bundle.optional names ${JSON.stringify(name)}, which is not a non-private plugin of this bundle`
6766
6810
  );
6767
6811
  }
6768
6812
  }
@@ -6771,16 +6815,78 @@ function bundleProblems(ws) {
6771
6815
  }
6772
6816
  return problems;
6773
6817
  }
6774
- function readBundle(ws) {
6775
- if (!isBundleWorkspace(ws)) return null;
6776
- const optional = ws.pkg.s2script.bundle?.optional ?? [];
6818
+ function bundleProblems(ws) {
6819
+ const rootBundle = isBundleWorkspace(ws);
6820
+ const { sources: sources2, problems } = bundleSources(ws);
6821
+ if (rootBundle && bundlesField(ws) !== void 0) {
6822
+ problems.push(
6823
+ `package.json (workspace root): s2script.kind is "bundle" and s2script.workspace.bundles is set \u2014 a root bundle cannot also contain bundles; drop the root's kind, or drop the bundles list`
6824
+ );
6825
+ return problems;
6826
+ }
6827
+ if (rootBundle) return [...problems, ...declarationProblems("package.json (workspace root)", ws.pkg, membersOf(ws, ""))];
6828
+ const memberDirs = new Set([...ws.plugins, ...ws.libs].map((m) => m.relDir));
6829
+ const byName = /* @__PURE__ */ new Map();
6830
+ for (const src of sources2) {
6831
+ const where2 = `${src.relDir}/package.json`;
6832
+ if (src.pkg === null) {
6833
+ problems.push(src.error);
6834
+ continue;
6835
+ }
6836
+ if (src.pkg.s2script?.kind !== "bundle") {
6837
+ problems.push(`${where2}: is listed in s2script.workspace.bundles but has no s2script.kind "bundle"`);
6838
+ continue;
6839
+ }
6840
+ if (src.pkg.s2script.workspace !== void 0) {
6841
+ problems.push(
6842
+ `${where2}: a bundle directory must not carry s2script.workspace \u2014 s2s would treat it as its own workspace root when run inside it; remove the block (the parent root is the workspace)`
6843
+ );
6844
+ }
6845
+ if (memberDirs.has(src.relDir)) {
6846
+ problems.push(
6847
+ `${src.relDir}: is both a workspace package and a bundle directory \u2014 narrow the root's "workspaces" globs so the bundle descriptor is not a package`
6848
+ );
6849
+ }
6850
+ const nested = sources2.find((o) => o !== src && isUnder(src.relDir, o.relDir));
6851
+ if (nested) {
6852
+ problems.push(`${src.relDir}: is inside bundle directory ${nested.relDir} \u2014 bundle directories cannot nest`);
6853
+ }
6854
+ if (typeof src.pkg.name === "string" && src.pkg.name !== "") {
6855
+ const first = byName.get(src.pkg.name);
6856
+ if (first !== void 0) {
6857
+ problems.push(`${src.relDir}: duplicate bundle name ${JSON.stringify(src.pkg.name)} \u2014 already declared by ${first}`);
6858
+ } else {
6859
+ byName.set(src.pkg.name, src.relDir);
6860
+ }
6861
+ }
6862
+ problems.push(...declarationProblems(where2, src.pkg, membersOf(ws, src.relDir)));
6863
+ }
6864
+ return problems;
6865
+ }
6866
+ function toBundle(ws, relDir, dir, pkg) {
6777
6867
  return {
6778
- name: ws.pkg.name,
6779
- version: ws.pkg.version,
6780
- members: ws.plugins.filter((p) => !p.private),
6781
- optional: new Set(optional)
6868
+ name: pkg.name,
6869
+ version: pkg.version,
6870
+ dir,
6871
+ relDir,
6872
+ pkg,
6873
+ members: membersOf(ws, relDir),
6874
+ optional: new Set(optionalOf(pkg))
6782
6875
  };
6783
6876
  }
6877
+ function readBundle(ws) {
6878
+ return isBundleWorkspace(ws) ? toBundle(ws, "", ws.root, ws.pkg) : null;
6879
+ }
6880
+ function readBundles(ws) {
6881
+ const root = readBundle(ws);
6882
+ if (root) return [root];
6883
+ return bundleSources(ws).sources.filter((s) => s.pkg?.s2script?.kind === "bundle").map((s) => toBundle(ws, s.relDir, s.dir, s.pkg));
6884
+ }
6885
+ function bundleOfPlugin(bundles) {
6886
+ const out = /* @__PURE__ */ new Map();
6887
+ for (const b of bundles) for (const m of b.members) out.set(m.name, b.name);
6888
+ return out;
6889
+ }
6784
6890
  function bundleMembers(bundle) {
6785
6891
  const out = {};
6786
6892
  for (const m of bundle.members) {
@@ -6911,7 +7017,7 @@ function stampWorkspaceVersion(ws, version) {
6911
7017
  dirty = true;
6912
7018
  }
6913
7019
  }
6914
- if (dirty) writeFileSync4(join14(p.dir, "package.json"), `${JSON.stringify(next, null, 2)}
7020
+ if (dirty) writeFileSync4(join15(p.dir, "package.json"), `${JSON.stringify(next, null, 2)}
6915
7021
  `);
6916
7022
  }
6917
7023
  return result;
@@ -8392,11 +8498,11 @@ async function runWorkspace(argv2, root, interactive, filters, stampVersion) {
8392
8498
  import { resolve as resolve16 } from "node:path";
8393
8499
 
8394
8500
  // src/registry/deploy.ts
8395
- import { readdirSync as readdirSync6, readFileSync as readFileSync15 } from "node:fs";
8501
+ import { readdirSync as readdirSync6, readFileSync as readFileSync16 } from "node:fs";
8396
8502
  import { resolve as resolve15 } from "node:path";
8397
8503
 
8398
8504
  // src/types-pack.ts
8399
- import { readFileSync as readFileSync12 } from "node:fs";
8505
+ import { readFileSync as readFileSync13 } from "node:fs";
8400
8506
 
8401
8507
  // src/tar.ts
8402
8508
  import { gzipSync } from "node:zlib";
@@ -8452,7 +8558,7 @@ function packTar(files, opts = {}) {
8452
8558
 
8453
8559
  // src/types-pack.ts
8454
8560
  function packTypesTarball(input) {
8455
- const dts = readFileSync12(input.typesPath);
8561
+ const dts = readFileSync13(input.typesPath);
8456
8562
  const pkgJson = Buffer.from(
8457
8563
  JSON.stringify(
8458
8564
  {
@@ -8477,8 +8583,8 @@ function packTypesTarball(input) {
8477
8583
 
8478
8584
  // src/source-pack.ts
8479
8585
  var import_ignore = __toESM(require_ignore(), 1);
8480
- import { readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
8481
- import { dirname as dirname6, join as join15, relative as relative3, resolve as resolve14, sep as sep4 } from "node:path";
8586
+ import { readdirSync as readdirSync5, readFileSync as readFileSync14, statSync as statSync5 } from "node:fs";
8587
+ import { dirname as dirname6, join as join16, relative as relative3, resolve as resolve14, sep as sep4 } from "node:path";
8482
8588
 
8483
8589
  // ../../node_modules/balanced-match/dist/esm/index.js
8484
8590
  var balanced = (a2, b, str) => {
@@ -10376,7 +10482,7 @@ function readIgnoreFile(dir) {
10376
10482
  for (const name of [".npmignore", ".gitignore"]) {
10377
10483
  let text3;
10378
10484
  try {
10379
- text3 = readFileSync13(join15(dir, name), "utf8");
10485
+ text3 = readFileSync14(join16(dir, name), "utf8");
10380
10486
  } catch {
10381
10487
  continue;
10382
10488
  }
@@ -10433,7 +10539,7 @@ function entryPoints(pkg) {
10433
10539
  function npmWorkspaceRoot(absDir) {
10434
10540
  for (let d = dirname6(absDir); ; d = dirname6(d)) {
10435
10541
  try {
10436
- const pj = JSON.parse(readFileSync13(join15(d, "package.json"), "utf8"));
10542
+ const pj = JSON.parse(readFileSync14(join16(d, "package.json"), "utf8"));
10437
10543
  if (pj && pj.workspaces) return d;
10438
10544
  } catch {
10439
10545
  }
@@ -10452,7 +10558,7 @@ function workspaceRulesets(absDir) {
10452
10558
  }
10453
10559
  function listPackageFiles(dir, pkg) {
10454
10560
  const absDir = resolve14(dir);
10455
- const pj = pkg ?? JSON.parse(readFileSync13(join15(absDir, "package.json"), "utf8"));
10561
+ const pj = pkg ?? JSON.parse(readFileSync14(join16(absDir, "package.json"), "utf8"));
10456
10562
  const files = filesPatterns(pj.files);
10457
10563
  const never = (0, import_ignore.default)().add(NEVER_PACKED);
10458
10564
  const forced = new Set(entryPoints(pj));
@@ -10465,7 +10571,7 @@ function listPackageFiles(dir, pkg) {
10465
10571
  (a2, b) => a2.name < b.name ? -1 : a2.name > b.name ? 1 : 0
10466
10572
  );
10467
10573
  for (const entry of entries) {
10468
- const childAbs = join15(abs, entry.name);
10574
+ const childAbs = join16(abs, entry.name);
10469
10575
  const rel = toPosix2(relative3(absDir, childAbs));
10470
10576
  if (entry.isSymbolicLink()) continue;
10471
10577
  if (entry.isDirectory()) {
@@ -10490,8 +10596,8 @@ function listPackageFiles(dir, pkg) {
10490
10596
  function packSourceTarball(dir, pkg) {
10491
10597
  const absDir = resolve14(dir);
10492
10598
  const files = listPackageFiles(absDir, pkg).map((path2) => {
10493
- const abs = join15(absDir, path2);
10494
- const content = readFileSync13(abs);
10599
+ const abs = join16(absDir, path2);
10600
+ const content = readFileSync14(abs);
10495
10601
  const mode = statSync5(abs).mode & 73 ? 493 : 420;
10496
10602
  return { path: path2, content, mode };
10497
10603
  });
@@ -10518,11 +10624,11 @@ function tarballFilename(name, version) {
10518
10624
  }
10519
10625
 
10520
10626
  // src/registry/credentials.ts
10521
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
10627
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "node:fs";
10522
10628
  import { homedir } from "node:os";
10523
- import { join as join16 } from "node:path";
10629
+ import { join as join17 } from "node:path";
10524
10630
  function credentialsPath() {
10525
- return join16(homedir(), ".s2script", "credentials.json");
10631
+ return join17(homedir(), ".s2script", "credentials.json");
10526
10632
  }
10527
10633
  function normalizeRegistryUrl(url) {
10528
10634
  const trimmed = url.replace(/\/$/, "");
@@ -10540,9 +10646,9 @@ function loadCredentials() {
10540
10646
  return { registryUrl: defaultRegistryUrl(), token: fromEnv };
10541
10647
  }
10542
10648
  const p = credentialsPath();
10543
- if (!existsSync11(p)) return null;
10649
+ if (!existsSync12(p)) return null;
10544
10650
  try {
10545
- const j = JSON.parse(readFileSync14(p, "utf8"));
10651
+ const j = JSON.parse(readFileSync15(p, "utf8"));
10546
10652
  if (!j.token) return null;
10547
10653
  return {
10548
10654
  registryUrl: normalizeRegistryUrl(j.registryUrl || defaultRegistryUrl()),
@@ -10553,7 +10659,7 @@ function loadCredentials() {
10553
10659
  }
10554
10660
  }
10555
10661
  function saveCredentials(creds) {
10556
- const dir = join16(homedir(), ".s2script");
10662
+ const dir = join17(homedir(), ".s2script");
10557
10663
  mkdirSync4(dir, { recursive: true });
10558
10664
  writeFileSync5(
10559
10665
  credentialsPath(),
@@ -10804,7 +10910,7 @@ function readPackageReadme(pluginDir) {
10804
10910
  const names = readdirSync6(pluginDir).filter((n3) => /^readme(\.(md|markdown))?$/i.test(n3));
10805
10911
  if (names.length === 0) return null;
10806
10912
  const name = names.find((n3) => n3 === "README.md") ?? names.sort()[0];
10807
- const text3 = readFileSync15(resolve15(pluginDir, name), "utf8").trim();
10913
+ const text3 = readFileSync16(resolve15(pluginDir, name), "utf8").trim();
10808
10914
  if (!text3) return null;
10809
10915
  if (text3.length > MAX_README_CHARS) {
10810
10916
  throw new Error(
@@ -10828,7 +10934,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
10828
10934
  const absDir = resolve15(pluginDir);
10829
10935
  const access = opts.access ?? resolveAccess(pkg);
10830
10936
  if (packageKind(pkg) === "library") {
10831
- const lib = readFileSync15(outPath);
10937
+ const lib = readFileSync16(outPath);
10832
10938
  const manifestEntry2 = unzipSync(lib)["manifest.json"];
10833
10939
  if (!manifestEntry2) {
10834
10940
  throw new Error(`built archive missing manifest.json: ${outPath}`);
@@ -10845,7 +10951,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
10845
10951
  }
10846
10952
  const gate = assertPublishesTypes(pkg, absDir);
10847
10953
  if (!gate.ok) throw new Error(`publish gate failed: ${gate.error}`);
10848
- const s2sp = readFileSync15(outPath);
10954
+ const s2sp = readFileSync16(outPath);
10849
10955
  const manifestEntry = unzipSync(s2sp)["manifest.json"];
10850
10956
  if (!manifestEntry) {
10851
10957
  throw new Error(`built archive missing manifest.json: ${outPath}`);
@@ -10871,7 +10977,7 @@ function assembleDeployArchive(pluginDir, pkg, outPath, opts = {}) {
10871
10977
  }
10872
10978
  async function deployPlugin(opts) {
10873
10979
  const absDir = resolve15(opts.dir);
10874
- const pkg = JSON.parse(readFileSync15(resolve15(absDir, "package.json"), "utf8"));
10980
+ const pkg = JSON.parse(readFileSync16(resolve15(absDir, "package.json"), "utf8"));
10875
10981
  assertDeployable(pkg, absDir);
10876
10982
  const access = resolveAccess(pkg, opts.access);
10877
10983
  assertAccessAllowed(pkg.name ?? absDir, access);
@@ -10966,7 +11072,8 @@ async function uploadPlan(plan, built, client, opts = {}) {
10966
11072
  const archive = assembleDeployArchive(b.plugin.dir, b.plugin.pkg, b.outPath, {
10967
11073
  access: opts.access
10968
11074
  });
10969
- if (opts.bundle !== void 0) archive.manifest = { ...archive.manifest, bundle: opts.bundle };
11075
+ const bundle = typeof opts.bundle === "string" ? opts.bundle : opts.bundle?.get(entry.plugin.name);
11076
+ if (bundle !== void 0) archive.manifest = { ...archive.manifest, bundle };
10970
11077
  const res = await client.deploy(archive);
10971
11078
  results.push({ plugin: entry.plugin, status: "published", detail: res.reviewState });
10972
11079
  } catch (e) {
@@ -11128,11 +11235,17 @@ async function runWorkspaceDeploy(opts) {
11128
11235
  }
11129
11236
  const { ordered, built, unpublishableLibraries } = builtPluginsFromOutcomes(ws, build3.outcomes);
11130
11237
  const plan = await computePlan(ordered, (name, version) => isAlreadyPublished(client, name, version));
11131
- const bundle = readBundle(ws);
11132
- const bundleEntry = bundle ? await planBundle(bundle, client) : null;
11238
+ const inRun = new Set(ordered.map((p) => p.name));
11239
+ const bundles = readBundles(ws);
11240
+ const planned = bundles.filter((b) => b.members.every((m) => inRun.has(m.name)));
11241
+ const bundleEntries = [];
11242
+ for (const b of planned) bundleEntries.push(await planBundle(b, client));
11133
11243
  label("plan:");
11134
11244
  console.log(formatPlan(plan));
11135
- if (bundleEntry) console.log(formatBundlePlan(bundleEntry));
11245
+ for (const entry of bundleEntries) console.log(formatBundlePlan(entry));
11246
+ for (const b of bundles) {
11247
+ if (!planned.includes(b)) console.log(` ${b.name} ${b.version} skip (not every member is in --filter)`);
11248
+ }
11136
11249
  if (unpublishableLibraries.length > 0) {
11137
11250
  console.log(formatUnpublishableLibraries(unpublishableLibraries));
11138
11251
  }
@@ -11143,14 +11256,15 @@ async function runWorkspaceDeploy(opts) {
11143
11256
  assertAccessAllowed(e.plugin.name, a2);
11144
11257
  if (a2 === "restricted") restricted.push(e.plugin.name);
11145
11258
  }
11146
- if (bundleEntry?.reason === "PUBLISH") {
11147
- const a2 = accessFlag ?? resolveAccess(ws.pkg);
11148
- assertAccessAllowed(bundleEntry.bundle.name, a2);
11149
- if (a2 !== void 0) bundleEntry.manifest = { ...bundleEntry.manifest, access: a2 };
11150
- if (a2 === "restricted") restricted.push(bundleEntry.bundle.name);
11259
+ for (const entry of bundleEntries) {
11260
+ if (entry.reason !== "PUBLISH") continue;
11261
+ const a2 = accessFlag ?? resolveAccess(entry.bundle.pkg);
11262
+ assertAccessAllowed(entry.bundle.name, a2);
11263
+ if (a2 !== void 0) entry.manifest = { ...entry.manifest, access: a2 };
11264
+ if (a2 === "restricted") restricted.push(entry.bundle.name);
11151
11265
  }
11152
11266
  if (restricted.length > 0) console.log(` restricted: ${restricted.join(", ")}`);
11153
- const bundlePublishes = bundleEntry?.reason === "PUBLISH" ? 1 : 0;
11267
+ const bundlePublishes = bundleEntries.filter((e) => e.reason === "PUBLISH").length;
11154
11268
  const toPublish = publishCount(plan) + bundlePublishes;
11155
11269
  const noun = (n3) => `${n3} package${n3 === 1 ? "" : "s"}`;
11156
11270
  if (toPublish === 0) {
@@ -11182,7 +11296,7 @@ async function runWorkspaceDeploy(opts) {
11182
11296
  process.exit(130);
11183
11297
  }
11184
11298
  }
11185
- const results = await uploadPlan(plan, built, client, { bundle: bundle?.name, access: accessFlag });
11299
+ const results = await uploadPlan(plan, built, client, { bundle: bundleOfPlugin(bundles), access: accessFlag });
11186
11300
  let failures = 0;
11187
11301
  for (const r2 of results) {
11188
11302
  if (r2.status === "failed") failures++;
@@ -11193,8 +11307,9 @@ async function runWorkspaceDeploy(opts) {
11193
11307
  console.log(line);
11194
11308
  }
11195
11309
  }
11196
- if (bundleEntry) {
11197
- const r2 = await uploadBundle(bundleEntry, results, client);
11310
+ for (const entry of bundleEntries) {
11311
+ const members = new Set(entry.bundle.members.map((m) => m.name));
11312
+ const r2 = await uploadBundle(entry, results.filter((m) => members.has(m.plugin.name)), client);
11198
11313
  if (r2.status === "failed") failures++;
11199
11314
  const line = `${r2.bundle.name}@${r2.bundle.version} (bundle): ${r2.status}${r2.detail ? ` (${r2.detail})` : ""}`;
11200
11315
  if (interactive) {
@@ -11212,14 +11327,14 @@ async function runWorkspaceDeploy(opts) {
11212
11327
  import { resolve as resolve17 } from "node:path";
11213
11328
 
11214
11329
  // src/version/version.ts
11215
- import { existsSync as existsSync12 } from "node:fs";
11216
- import { join as join20 } from "node:path";
11330
+ import { existsSync as existsSync13 } from "node:fs";
11331
+ import { join as join21 } from "node:path";
11217
11332
 
11218
11333
  // src/version/changesets.ts
11219
11334
  var import_semver = __toESM(require_semver2(), 1);
11220
- import { readFileSync as readFileSync16 } from "node:fs";
11335
+ import { readFileSync as readFileSync17 } from "node:fs";
11221
11336
  import { createRequire as createRequire2 } from "node:module";
11222
- import { join as join17 } from "node:path";
11337
+ import { join as join18 } from "node:path";
11223
11338
  import { pathToFileURL } from "node:url";
11224
11339
  var SUPPORTED = {
11225
11340
  "@changesets/assemble-release-plan": ">=6.0.0 <7.0.0",
@@ -11239,7 +11354,7 @@ function named(mod, key) {
11239
11354
  return outer?.[key];
11240
11355
  }
11241
11356
  async function loadChangesets(workspaceRoot) {
11242
- const require3 = createRequire2(join17(workspaceRoot, "package.json"));
11357
+ const require3 = createRequire2(join18(workspaceRoot, "package.json"));
11243
11358
  const missing = [];
11244
11359
  const wrongVersion = [];
11245
11360
  const resolved = /* @__PURE__ */ new Map();
@@ -11254,7 +11369,7 @@ async function loadChangesets(workspaceRoot) {
11254
11369
  missing.push(name);
11255
11370
  continue;
11256
11371
  }
11257
- const version = String(JSON.parse(readFileSync16(manifest, "utf8")).version ?? "");
11372
+ const version = String(JSON.parse(readFileSync17(manifest, "utf8")).version ?? "");
11258
11373
  if (!(0, import_semver.satisfies)(version, range2, { includePrerelease: true })) {
11259
11374
  wrongVersion.push(`${name}@${version} (supported: ${range2})`);
11260
11375
  continue;
@@ -11354,8 +11469,8 @@ function mirrorPackages(ws) {
11354
11469
 
11355
11470
  // src/version/ranges.ts
11356
11471
  var import_semver2 = __toESM(require_semver2(), 1);
11357
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "node:fs";
11358
- import { join as join18 } from "node:path";
11472
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync6 } from "node:fs";
11473
+ import { join as join19 } from "node:path";
11359
11474
  var BUMP_LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
11360
11475
  function rangePrefix(range2) {
11361
11476
  if (range2.startsWith(">=")) return ">=";
@@ -11374,7 +11489,7 @@ function shouldUpdate(release, range2, config) {
11374
11489
  return BUMP_LEVEL[release.type] >= minLevel;
11375
11490
  }
11376
11491
  function readJsonFile(path2) {
11377
- const raw = readFileSync17(path2, "utf8");
11492
+ const raw = readFileSync18(path2, "utf8");
11378
11493
  const match2 = /^[ \t]*[{[]\s*\n([ \t]+)/.exec(raw);
11379
11494
  return {
11380
11495
  json: JSON.parse(raw),
@@ -11415,7 +11530,7 @@ function rewriteSiblingRanges(ws, releases, config) {
11415
11530
  for (const [consumerName, ifaceRanges] of edits) {
11416
11531
  const plugin = ws.plugins.find((p) => p.name === consumerName);
11417
11532
  if (plugin === void 0) continue;
11418
- const path2 = join18(plugin.dir, "package.json");
11533
+ const path2 = join19(plugin.dir, "package.json");
11419
11534
  const { json, indent, eol } = readJsonFile(path2);
11420
11535
  const s2 = json.s2script;
11421
11536
  if (s2?.pluginDependencies === void 0) continue;
@@ -11429,42 +11544,46 @@ function rewriteSiblingRanges(ws, releases, config) {
11429
11544
  // src/version/bundle-bump.ts
11430
11545
  var import_semver3 = __toESM(require_semver2(), 1);
11431
11546
  import { writeFileSync as writeFileSync7 } from "node:fs";
11432
- import { join as join19 } from "node:path";
11547
+ import { join as join20 } from "node:path";
11433
11548
  var LEVEL = { none: 0, patch: 1, minor: 2, major: 3 };
11434
- function plannedBundleBump(ws, releases) {
11435
- const bundle = readBundle(ws);
11436
- if (!bundle) return null;
11549
+ function plannedBundleBump(bundle, releases) {
11437
11550
  const members = new Set(bundle.members.map((m) => m.name));
11438
11551
  const memberReleases = releases.filter((r2) => members.has(r2.name) && r2.type !== "none");
11439
11552
  if (memberReleases.length === 0) return null;
11440
11553
  const type = memberReleases.reduce((t2, r2) => LEVEL[r2.type] > LEVEL[t2] ? r2.type : t2, "none");
11441
11554
  const to = (0, import_semver3.inc)(bundle.version, type);
11442
11555
  if (to === null) {
11443
- throw new Error(`s2s version: the bundle's version ${JSON.stringify(bundle.version)} is not valid semver`);
11556
+ throw new Error(
11557
+ `s2s version: the bundle ${bundle.name}'s version ${JSON.stringify(bundle.version)} is not valid semver`
11558
+ );
11444
11559
  }
11445
11560
  return {
11446
11561
  name: bundle.name,
11447
11562
  from: bundle.version,
11448
11563
  to,
11449
11564
  type,
11450
- because: memberReleases.map((r2) => `${r2.name}@${r2.newVersion}`)
11565
+ because: memberReleases.map((r2) => `${r2.name}@${r2.newVersion}`),
11566
+ path: join20(bundle.dir, "package.json")
11451
11567
  };
11452
11568
  }
11453
- function bumpBundle(ws, releases) {
11454
- const bump = plannedBundleBump(ws, releases);
11455
- if (!bump) return { bump: null, touchedFiles: [] };
11456
- const path2 = join19(ws.root, "package.json");
11457
- const { json, indent, eol } = readJsonFile(path2);
11458
- json.version = bump.to;
11459
- writeFileSync7(path2, JSON.stringify(json, null, indent) + eol);
11460
- return { bump, touchedFiles: [path2] };
11569
+ function plannedBundleBumps(ws, releases) {
11570
+ return readBundles(ws).map((b) => plannedBundleBump(b, releases)).filter((b) => b !== null);
11571
+ }
11572
+ function bumpBundles(ws, releases) {
11573
+ const bumps = plannedBundleBumps(ws, releases);
11574
+ for (const bump of bumps) {
11575
+ const { json, indent, eol } = readJsonFile(bump.path);
11576
+ json.version = bump.to;
11577
+ writeFileSync7(bump.path, JSON.stringify(json, null, indent) + eol);
11578
+ }
11579
+ return { bumps, touchedFiles: bumps.map((b) => b.path) };
11461
11580
  }
11462
11581
 
11463
11582
  // src/version/version.ts
11464
11583
  async function versionWorkspace(root, opts = {}) {
11465
11584
  const ws = loadWorkspace(root);
11466
- const configPath = join20(ws.root, ".changeset", "config.json");
11467
- if (!existsSync12(configPath)) {
11585
+ const configPath = join21(ws.root, ".changeset", "config.json");
11586
+ if (!existsSync13(configPath)) {
11468
11587
  throw new Error(
11469
11588
  `s2s version: ${configPath} does not exist \u2014 this workspace is not set up for changesets. Run \`npx changeset init\` at ${ws.root}.`
11470
11589
  );
@@ -11478,15 +11597,15 @@ async function versionWorkspace(root, opts = {}) {
11478
11597
  const plan = cs.assembleReleasePlan(changesets, mirror, config, preState);
11479
11598
  const touchedFiles = await cs.applyReleasePlan(plan, real, config);
11480
11599
  const ranges = rewriteSiblingRanges(ws, plan.releases, config);
11481
- const bundle = bumpBundle(ws, plan.releases);
11600
+ const bundles = bumpBundles(ws, plan.releases);
11482
11601
  return {
11483
11602
  root: ws.root,
11484
11603
  changesetCount: changesets.length,
11485
11604
  releases: plan.releases,
11486
11605
  rewrites: ranges.rewrites,
11487
11606
  skips: ranges.skips,
11488
- bundleBump: bundle.bump,
11489
- touchedFiles: [...touchedFiles, ...ranges.touchedFiles, ...bundle.touchedFiles],
11607
+ bundleBumps: bundles.bumps,
11608
+ touchedFiles: [...touchedFiles, ...ranges.touchedFiles, ...bundles.touchedFiles],
11490
11609
  changesetsVersions: cs.versions
11491
11610
  };
11492
11611
  }
@@ -11522,8 +11641,7 @@ async function run3(argv2) {
11522
11641
  for (const r2 of result.releases) {
11523
11642
  lines.push(`${r2.name} ${r2.oldVersion} -> ${r2.newVersion} (${r2.type})`);
11524
11643
  }
11525
- if (result.bundleBump) {
11526
- const b = result.bundleBump;
11644
+ for (const b of result.bundleBumps) {
11527
11645
  lines.push(`${b.name} ${b.from} -> ${b.to} (${b.type}, bundle \u2014 follows ${b.because.join(", ")})`);
11528
11646
  }
11529
11647
  for (const rw of result.rewrites) {
@@ -11551,15 +11669,15 @@ import { resolve as resolve19 } from "node:path";
11551
11669
  import {
11552
11670
  mkdirSync as mkdirSync6,
11553
11671
  writeFileSync as writeFileSync10,
11554
- readFileSync as readFileSync19,
11555
- existsSync as existsSync14
11672
+ readFileSync as readFileSync20,
11673
+ existsSync as existsSync15
11556
11674
  } from "node:fs";
11557
- import { join as join23, resolve as resolve18 } from "node:path";
11675
+ import { join as join24, resolve as resolve18 } from "node:path";
11558
11676
  import { gunzipSync } from "node:zlib";
11559
11677
 
11560
11678
  // src/registry/npmrc.ts
11561
- import { existsSync as existsSync13, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "node:fs";
11562
- import { join as join21 } from "node:path";
11679
+ import { existsSync as existsSync14, readFileSync as readFileSync19, writeFileSync as writeFileSync8 } from "node:fs";
11680
+ import { join as join22 } from "node:path";
11563
11681
  function npmCompatRegistryUrl(registryUrl) {
11564
11682
  return `${registryUrl.replace(/\/$/, "")}/npm/`;
11565
11683
  }
@@ -11575,8 +11693,8 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
11575
11693
  const compat = npmCompatRegistryUrl(registryUrl);
11576
11694
  const key = `@${scope}:registry`;
11577
11695
  const line = `${key}=${compat}`;
11578
- const npmrcPath = join21(projectDir, ".npmrc");
11579
- let existing = existsSync13(npmrcPath) ? readFileSync18(npmrcPath, "utf8") : "";
11696
+ const npmrcPath = join22(projectDir, ".npmrc");
11697
+ let existing = existsSync14(npmrcPath) ? readFileSync19(npmrcPath, "utf8") : "";
11580
11698
  const lines = existing.split(/\r?\n/);
11581
11699
  const idx = lines.findIndex((l2) => l2.trimStart().startsWith(`${key}=`) || l2.trimStart().startsWith(`${key} =`));
11582
11700
  if (idx >= 0) {
@@ -11592,7 +11710,7 @@ function ensureScopeNpmrc(projectDir, packageName, registryUrl) {
11592
11710
 
11593
11711
  // src/registry/lib-extract.ts
11594
11712
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync9 } from "node:fs";
11595
- import { join as join22 } from "node:path";
11713
+ import { join as join23 } from "node:path";
11596
11714
  var WANTED = /* @__PURE__ */ new Set(["index.js", "index.d.ts"]);
11597
11715
  function extractLibArchive(s2lib, outDir, meta) {
11598
11716
  const entries = unzipSync(new Uint8Array(s2lib));
@@ -11601,7 +11719,7 @@ function extractLibArchive(s2lib, outDir, meta) {
11601
11719
  mkdirSync5(outDir, { recursive: true });
11602
11720
  for (const [name, bytes] of Object.entries(entries)) {
11603
11721
  if (!WANTED.has(name)) continue;
11604
- writeFileSync9(join22(outDir, name), Buffer.from(bytes));
11722
+ writeFileSync9(join23(outDir, name), Buffer.from(bytes));
11605
11723
  }
11606
11724
  let apiVersion = "1.x";
11607
11725
  try {
@@ -11610,7 +11728,7 @@ function extractLibArchive(s2lib, outDir, meta) {
11610
11728
  } catch {
11611
11729
  }
11612
11730
  writeFileSync9(
11613
- join22(outDir, "package.json"),
11731
+ join23(outDir, "package.json"),
11614
11732
  JSON.stringify(
11615
11733
  { name: meta.name, version: meta.version, main: "index.js", types: "index.d.ts", s2script: { kind: "library", apiVersion } },
11616
11734
  null,
@@ -11647,13 +11765,13 @@ function extractTypesTarball(tgz, outDir) {
11647
11765
  if (!name || name.endsWith("/")) continue;
11648
11766
  const base = name.replace(/^package\//, "");
11649
11767
  if (base === "package.json") {
11650
- writeFileSync10(join23(outDir, "package.json"), content);
11768
+ writeFileSync10(join24(outDir, "package.json"), content);
11651
11769
  } else if (base === "api.d.ts" || base === "index.d.ts") {
11652
- writeFileSync10(join23(outDir, "index.d.ts"), content);
11770
+ writeFileSync10(join24(outDir, "index.d.ts"), content);
11653
11771
  wroteContract = true;
11654
11772
  }
11655
11773
  }
11656
- if (!wroteContract && !existsSync14(join23(outDir, "index.d.ts"))) {
11774
+ if (!wroteContract && !existsSync15(join24(outDir, "index.d.ts"))) {
11657
11775
  throw new Error("types tarball missing package/api.d.ts (or index.d.ts)");
11658
11776
  }
11659
11777
  }
@@ -11678,10 +11796,10 @@ async function addPackage(opts) {
11678
11796
  }
11679
11797
  if (resolved.kind === "library") {
11680
11798
  const s2lib = await client.downloadLib(name, resolved.version);
11681
- const libDir = join23(absDir, ".s2script", "libs", ...name.split("/"));
11799
+ const libDir = join24(absDir, ".s2script", "libs", ...name.split("/"));
11682
11800
  extractLibArchive(s2lib, libDir, { name, version: resolved.version });
11683
- const pkgPath2 = join23(absDir, "package.json");
11684
- const pkg2 = JSON.parse(readFileSync19(pkgPath2, "utf8"));
11801
+ const pkgPath2 = join24(absDir, "package.json");
11802
+ const pkg2 = JSON.parse(readFileSync20(pkgPath2, "utf8"));
11685
11803
  pkg2.s2script = pkg2.s2script ?? {};
11686
11804
  pkg2.s2script.libraries = pkg2.s2script.libraries ?? {};
11687
11805
  pkg2.s2script.libraries[name] = rangeForResolved(range2, resolved.version);
@@ -11702,10 +11820,10 @@ async function addPackage(opts) {
11702
11820
  throw new Error(`${name}@${resolved.version} has no types artifact (runtime-only package?)`);
11703
11821
  }
11704
11822
  const tgz = await client.downloadTypes(name, resolved.version);
11705
- const typesDir = join23(absDir, ".s2script", "types", ...name.split("/"));
11823
+ const typesDir = join24(absDir, ".s2script", "types", ...name.split("/"));
11706
11824
  extractTypesTarball(tgz, typesDir);
11707
- const pkgPath = join23(absDir, "package.json");
11708
- const pkg = JSON.parse(readFileSync19(pkgPath, "utf8"));
11825
+ const pkgPath = join24(absDir, "package.json");
11826
+ const pkg = JSON.parse(readFileSync20(pkgPath, "utf8"));
11709
11827
  pkg.s2script = pkg.s2script ?? {};
11710
11828
  pkg.s2script.pluginDependencies = pkg.s2script.pluginDependencies ?? {};
11711
11829
  pkg.s2script.pluginDependencies[name] = rangeForResolved(range2, resolved.version);
@@ -11786,37 +11904,37 @@ async function run4(argv2) {
11786
11904
  }
11787
11905
 
11788
11906
  // src/commands/install.ts
11789
- import { existsSync as existsSync19, writeFileSync as writeFileSync15 } from "node:fs";
11790
- import { join as join27 } from "node:path";
11907
+ import { existsSync as existsSync20, writeFileSync as writeFileSync15 } from "node:fs";
11908
+ import { join as join28 } from "node:path";
11791
11909
 
11792
11910
  // src/server/manifest.ts
11793
11911
  var import_semver4 = __toESM(require_semver2(), 1);
11794
- import { existsSync as existsSync15, readFileSync as readFileSync20, renameSync, writeFileSync as writeFileSync11 } from "node:fs";
11795
- import { basename as basename2, join as join24, resolve as resolve20 } from "node:path";
11912
+ import { existsSync as existsSync16, readFileSync as readFileSync21, renameSync, writeFileSync as writeFileSync11 } from "node:fs";
11913
+ import { basename as basename2, join as join25, resolve as resolve20 } from "node:path";
11796
11914
  var SERVER_MANIFEST = "plugins.json";
11797
11915
  var SERVER_LOCK = "plugins-lock.json";
11798
11916
  var PLUGINS_SUBDIR = "plugins";
11799
11917
  var DISABLED_SUBDIR = "disabled";
11800
11918
  function readJson(path2) {
11801
- const j = JSON.parse(readFileSync20(path2, "utf8"));
11919
+ const j = JSON.parse(readFileSync21(path2, "utf8"));
11802
11920
  if (!j || typeof j !== "object" || Array.isArray(j)) throw new Error(`${path2}: must be a JSON object`);
11803
11921
  return j;
11804
11922
  }
11805
11923
  function findServerRoot(start) {
11806
11924
  for (const dir of [resolve20(start), resolve20(start, "addons", "s2script")]) {
11807
- if (existsSync15(join24(dir, SERVER_MANIFEST))) return dir;
11925
+ if (existsSync16(join25(dir, SERVER_MANIFEST))) return dir;
11808
11926
  }
11809
11927
  return null;
11810
11928
  }
11811
11929
  function findAddonRoot(start) {
11812
11930
  const found = findServerRoot(start);
11813
11931
  if (found) return found;
11814
- if (existsSync15(resolve20(start, PLUGINS_SUBDIR))) return resolve20(start);
11932
+ if (existsSync16(resolve20(start, PLUGINS_SUBDIR))) return resolve20(start);
11815
11933
  const nested = resolve20(start, "addons", "s2script");
11816
- return existsSync15(nested) ? nested : null;
11934
+ return existsSync16(nested) ? nested : null;
11817
11935
  }
11818
11936
  function parseServerManifest(root, raw) {
11819
- const label = join24(root, SERVER_MANIFEST);
11937
+ const label = join25(root, SERVER_MANIFEST);
11820
11938
  const depsRaw = raw.dependencies ?? {};
11821
11939
  if (typeof depsRaw !== "object" || Array.isArray(depsRaw)) {
11822
11940
  throw new Error(`${label}: "dependencies" must be an object (plugin name \u2192 version range)`);
@@ -11865,8 +11983,8 @@ function parseServerManifest(root, raw) {
11865
11983
  };
11866
11984
  }
11867
11985
  function readServerManifest(root) {
11868
- const path2 = join24(root, SERVER_MANIFEST);
11869
- if (!existsSync15(path2)) throw new Error(`no ${SERVER_MANIFEST} in ${root} \u2014 run \`s2s server init\` first`);
11986
+ const path2 = join25(root, SERVER_MANIFEST);
11987
+ if (!existsSync16(path2)) throw new Error(`no ${SERVER_MANIFEST} in ${root} \u2014 run \`s2s server init\` first`);
11870
11988
  return parseServerManifest(root, readJson(path2));
11871
11989
  }
11872
11990
  function newServerManifestJson(name, dependencies) {
@@ -11880,15 +11998,15 @@ function writeServerManifest(m) {
11880
11998
  else delete out.with;
11881
11999
  if (m.disabled.length > 0) out.disabled = [...m.disabled].sort();
11882
12000
  else delete out.disabled;
11883
- const path2 = join24(m.root, SERVER_MANIFEST);
12001
+ const path2 = join25(m.root, SERVER_MANIFEST);
11884
12002
  const tmp = `${path2}.${process.pid}.tmp`;
11885
12003
  writeFileSync11(tmp, JSON.stringify(out, null, 2) + "\n");
11886
12004
  renameSync(tmp, path2);
11887
12005
  }
11888
12006
 
11889
12007
  // src/server/commands.ts
11890
- import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "node:fs";
11891
- import { join as join26, resolve as resolve22 } from "node:path";
12008
+ import { existsSync as existsSync19, readdirSync as readdirSync7, readFileSync as readFileSync24, writeFileSync as writeFileSync14 } from "node:fs";
12009
+ import { join as join27, resolve as resolve22 } from "node:path";
11892
12010
  var import_semver5 = __toESM(require_semver2(), 1);
11893
12011
 
11894
12012
  // src/registry/install.ts
@@ -11941,7 +12059,7 @@ async function resolveMerged(client, specs, withMembers = {}) {
11941
12059
 
11942
12060
  // src/server/lock.ts
11943
12061
  import { createHash as createHash4 } from "node:crypto";
11944
- import { existsSync as existsSync16, readFileSync as readFileSync21, renameSync as renameSync2, writeFileSync as writeFileSync12 } from "node:fs";
12062
+ import { existsSync as existsSync17, readFileSync as readFileSync22, renameSync as renameSync2, writeFileSync as writeFileSync12 } from "node:fs";
11945
12063
  var LOCKFILE_VERSION = 3;
11946
12064
  function integrityFromSha256Hex(hex) {
11947
12065
  return `sha256-${Buffer.from(hex, "hex").toString("base64")}`;
@@ -12015,8 +12133,8 @@ function parseLock(text3, label = "plugins-lock.json") {
12015
12133
  };
12016
12134
  }
12017
12135
  function readLock(path2) {
12018
- if (!existsSync16(path2)) return null;
12019
- return parseLock(readFileSync21(path2, "utf8"), path2);
12136
+ if (!existsSync17(path2)) return null;
12137
+ return parseLock(readFileSync22(path2, "utf8"), path2);
12020
12138
  }
12021
12139
  function writeLock(path2, lock) {
12022
12140
  const tmp = `${path2}.${process.pid}.tmp`;
@@ -12025,8 +12143,8 @@ function writeLock(path2, lock) {
12025
12143
  }
12026
12144
 
12027
12145
  // src/server/sync.ts
12028
- import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync22, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync13 } from "node:fs";
12029
- import { dirname as dirname7, join as join25, resolve as resolve21, sep as sep5 } from "node:path";
12146
+ import { existsSync as existsSync18, mkdirSync as mkdirSync7, readFileSync as readFileSync23, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync13 } from "node:fs";
12147
+ import { dirname as dirname7, join as join26, resolve as resolve21, sep as sep5 } from "node:path";
12030
12148
  function relPath(t2) {
12031
12149
  return t2.disabled ? `${DISABLED_SUBDIR}/${t2.filename}` : t2.filename;
12032
12150
  }
@@ -12107,18 +12225,18 @@ async function syncPlugins(opts) {
12107
12225
  try {
12108
12226
  for (const t2 of opts.targets) {
12109
12227
  const key = lockKey(relPath(t2));
12110
- const dest = join25(dir, relPath(t2));
12228
+ const dest = join26(dir, relPath(t2));
12111
12229
  result.plugins[key] = {
12112
12230
  name: t2.name,
12113
12231
  version: t2.version,
12114
12232
  resolved: t2.url,
12115
12233
  integrity: integrityFromSha256Hex(t2.sha256)
12116
12234
  };
12117
- if (existsSync17(dest) && sha256Hex(readFileSync22(dest)) === t2.sha256) {
12235
+ if (existsSync18(dest) && sha256Hex(readFileSync23(dest)) === t2.sha256) {
12118
12236
  result.kept.push(t2.filename);
12119
12237
  continue;
12120
12238
  }
12121
- const movedFrom = Object.entries(opts.oldLock?.plugins ?? {}).filter(([k, p]) => k !== key && p.name === t2.name).map(([k]) => join25(opts.root, k)).find((f) => existsSync17(f) && sha256Hex(readFileSync22(f)) === t2.sha256);
12239
+ const movedFrom = Object.entries(opts.oldLock?.plugins ?? {}).filter(([k, p]) => k !== key && p.name === t2.name).map(([k]) => join26(opts.root, k)).find((f) => existsSync18(f) && sha256Hex(readFileSync23(f)) === t2.sha256);
12122
12240
  if (movedFrom) {
12123
12241
  result.moved.push(t2.filename);
12124
12242
  if (opts.dryRun) log3(`would ${t2.disabled ? "disable" : "enable"} ${t2.name}@${t2.version}`);
@@ -12155,10 +12273,10 @@ async function syncPlugins(opts) {
12155
12273
  }
12156
12274
  for (const [key, old] of Object.entries(opts.oldLock?.plugins ?? {})) {
12157
12275
  if (key in result.plugins) continue;
12158
- const file = join25(opts.root, key);
12159
- if (!existsSync17(file)) continue;
12276
+ const file = join26(opts.root, key);
12277
+ if (!existsSync18(file)) continue;
12160
12278
  const want = sha256HexFromIntegrity(old.integrity);
12161
- if (want && sha256Hex(readFileSync22(file)) === want) {
12279
+ if (want && sha256Hex(readFileSync23(file)) === want) {
12162
12280
  if (opts.dryRun) log3(`would remove ${old.name}@${old.version} (${key})`);
12163
12281
  else {
12164
12282
  rmSync3(file);
@@ -12210,7 +12328,7 @@ async function serverInstall(opts) {
12210
12328
  }
12211
12329
  manifest = { ...manifest, with: { ...manifest.with, [parseSpec2(opts.specs[0]).name]: opts.with } };
12212
12330
  }
12213
- const lockPath = join26(opts.root, SERVER_LOCK);
12331
+ const lockPath = join27(opts.root, SERVER_LOCK);
12214
12332
  const lock = readLock(lockPath);
12215
12333
  if (opts.disabled) {
12216
12334
  if (!opts.specs?.length) throw new Error("--disabled needs the plugins to install: s2s install <name> --disabled");
@@ -12261,7 +12379,7 @@ async function serverUpdate(opts) {
12261
12379
  const log3 = opts.log ?? (() => {
12262
12380
  });
12263
12381
  const manifest = readServerManifest(opts.root);
12264
- const lockPath = join26(opts.root, SERVER_LOCK);
12382
+ const lockPath = join27(opts.root, SERVER_LOCK);
12265
12383
  const lock = readLock(lockPath);
12266
12384
  const names = opts.names && opts.names.length > 0 ? opts.names : Object.keys(manifest.dependencies);
12267
12385
  for (const n3 of names) {
@@ -12279,12 +12397,12 @@ async function serverUpdate(opts) {
12279
12397
  }
12280
12398
  function scanLocalPlugins(root, onUnreadable = () => {
12281
12399
  }) {
12282
- const dir = join26(root, PLUGINS_SUBDIR);
12283
- if (!existsSync18(dir)) return [];
12400
+ const dir = join27(root, PLUGINS_SUBDIR);
12401
+ if (!existsSync19(dir)) return [];
12284
12402
  const out = [];
12285
12403
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
12286
12404
  if (!entry.isFile() || !entry.name.endsWith(".s2sp")) continue;
12287
- const bytes = readFileSync23(join26(dir, entry.name));
12405
+ const bytes = readFileSync24(join27(dir, entry.name));
12288
12406
  try {
12289
12407
  const files = unzipSync(new Uint8Array(bytes), { filter: (f) => f.name === "manifest.json" });
12290
12408
  const m = JSON.parse(Buffer.from(files["manifest.json"]).toString("utf8"));
@@ -12298,8 +12416,8 @@ function scanLocalPlugins(root, onUnreadable = () => {
12298
12416
  }
12299
12417
  async function serverInit(opts) {
12300
12418
  const root = resolve22(opts.root);
12301
- const pkgPath = join26(root, SERVER_MANIFEST);
12302
- if (existsSync18(pkgPath) && !opts.force) {
12419
+ const pkgPath = join27(root, SERVER_MANIFEST);
12420
+ if (existsSync19(pkgPath) && !opts.force) {
12303
12421
  throw new Error(`${pkgPath} already exists \u2014 pass --force to replace it`);
12304
12422
  }
12305
12423
  const report = { managed: [], unmanaged: [] };
@@ -12340,7 +12458,7 @@ async function serverInit(opts) {
12340
12458
  const raw = newServerManifestJson(opts.name ?? "s2script-server", dependencies);
12341
12459
  writeFileSync14(pkgPath, JSON.stringify(raw, null, 2) + "\n");
12342
12460
  const manifest = parseServerManifest(root, raw);
12343
- writeLock(join26(root, SERVER_LOCK), lockFor(manifest, plugins));
12461
+ writeLock(join27(root, SERVER_LOCK), lockFor(manifest, plugins));
12344
12462
  return report;
12345
12463
  }
12346
12464
  async function serverSetEnabled(opts) {
@@ -12358,7 +12476,7 @@ async function serverSetEnabled(opts) {
12358
12476
  else set.add(n3);
12359
12477
  }
12360
12478
  manifest = { ...manifest, disabled: [...set].sort() };
12361
- const lockPath = join26(opts.root, SERVER_LOCK);
12479
+ const lockPath = join27(opts.root, SERVER_LOCK);
12362
12480
  const lock = readLock(lockPath);
12363
12481
  const specs = pinnedSpecs(manifest, lock, sat);
12364
12482
  const { targets } = await resolveTargets(opts.client, specs, manifest.with, {
@@ -12430,11 +12548,11 @@ async function run5(argv2) {
12430
12548
  }
12431
12549
  await runServer(async () => {
12432
12550
  const withMembers = collectWith(argv2);
12433
- if (!existsSync19(join27(root, SERVER_MANIFEST))) {
12551
+ if (!existsSync20(join28(root, SERVER_MANIFEST))) {
12434
12552
  if (dryRun) throw new Error(`no ${SERVER_MANIFEST} in ${root} yet \u2014 run without --dry-run to create one`);
12435
12553
  const fresh = newServerManifestJson("s2script-server", {});
12436
- writeFileSync15(join27(root, SERVER_MANIFEST), JSON.stringify(fresh, null, 2) + "\n");
12437
- console.log(`created ${join27(root, SERVER_MANIFEST)}`);
12554
+ writeFileSync15(join28(root, SERVER_MANIFEST), JSON.stringify(fresh, null, 2) + "\n");
12555
+ console.log(`created ${join28(root, SERVER_MANIFEST)}`);
12438
12556
  }
12439
12557
  return serverInstall({
12440
12558
  root,
@@ -12455,26 +12573,26 @@ import { resolve as resolve25 } from "node:path";
12455
12573
  import {
12456
12574
  mkdirSync as mkdirSync8,
12457
12575
  writeFileSync as writeFileSync16,
12458
- existsSync as existsSync20,
12576
+ existsSync as existsSync21,
12459
12577
  readdirSync as readdirSync8,
12460
- readFileSync as readFileSync24,
12578
+ readFileSync as readFileSync25,
12461
12579
  symlinkSync
12462
12580
  } from "node:fs";
12463
- import { dirname as dirname8, isAbsolute, join as join28, relative as relative4, resolve as resolve23, basename as basename4 } from "node:path";
12581
+ import { dirname as dirname8, isAbsolute, join as join29, relative as relative4, resolve as resolve23, basename as basename4 } from "node:path";
12464
12582
  import { spawnSync } from "node:child_process";
12465
12583
  import { fileURLToPath as fileURLToPath2 } from "node:url";
12466
12584
  function readCliVersion() {
12467
12585
  const here = dirname8(fileURLToPath2(import.meta.url));
12468
12586
  const candidates = [
12469
- join28(here, "..", "package.json"),
12587
+ join29(here, "..", "package.json"),
12470
12588
  // dist/cli.js → packages/sdk/package.json
12471
- join28(here, "..", "..", "package.json")
12589
+ join29(here, "..", "..", "package.json")
12472
12590
  // src/create → packages/sdk/package.json
12473
12591
  ];
12474
12592
  for (const p of candidates) {
12475
- if (!existsSync20(p)) continue;
12593
+ if (!existsSync21(p)) continue;
12476
12594
  try {
12477
- const pkg = JSON.parse(readFileSync24(p, "utf8"));
12595
+ const pkg = JSON.parse(readFileSync25(p, "utf8"));
12478
12596
  if (pkg.name === "@s2script/sdk" && pkg.version) return pkg.version;
12479
12597
  } catch {
12480
12598
  }
@@ -12484,9 +12602,9 @@ function readCliVersion() {
12484
12602
  function findLocalPackagesDir() {
12485
12603
  const here = dirname8(fileURLToPath2(import.meta.url));
12486
12604
  const candidates = [
12487
- join28(here, "..", ".."),
12605
+ join29(here, "..", ".."),
12488
12606
  // dist/cli.js → packages
12489
- join28(here, "..", "..", "..")
12607
+ join29(here, "..", "..", "..")
12490
12608
  // src/create → packages
12491
12609
  ];
12492
12610
  for (const c2 of candidates) {
@@ -12502,7 +12620,7 @@ function defaultNameFromPath(dir, kind = "plugin") {
12502
12620
  return `@${kind}/${slugifyBasename(dir)}`;
12503
12621
  }
12504
12622
  function assertEmptyTarget(targetPath) {
12505
- if (!existsSync20(targetPath)) return;
12623
+ if (!existsSync21(targetPath)) return;
12506
12624
  const kids = readdirSync8(targetPath);
12507
12625
  const meaningful = kids.filter((k) => k !== ".git");
12508
12626
  if (meaningful.length) {
@@ -12551,8 +12669,8 @@ function registryDevDeps(game, sdkVersion, resolve29 = resolvePublishedVersion)
12551
12669
  function fileDevDeps(packagesDir, game) {
12552
12670
  const deps = {};
12553
12671
  for (const n3 of createPackageNames(game)) {
12554
- const abs = join28(packagesDir, n3);
12555
- if (!existsSync20(join28(abs, "package.json"))) return void 0;
12672
+ const abs = join29(packagesDir, n3);
12673
+ if (!existsSync21(join29(abs, "package.json"))) return void 0;
12556
12674
  deps[`@s2script/${n3}`] = `file:${abs}`;
12557
12675
  }
12558
12676
  return deps;
@@ -12617,7 +12735,7 @@ function tsconfigJson() {
12617
12735
  ) + "\n";
12618
12736
  }
12619
12737
  function workspaceTsconfigJson(targetPath, workspaceRoot) {
12620
- const rel = relative4(targetPath, join28(workspaceRoot, "tsconfig.base.json")).replace(/\\/g, "/");
12738
+ const rel = relative4(targetPath, join29(workspaceRoot, "tsconfig.base.json")).replace(/\\/g, "/");
12621
12739
  return JSON.stringify(
12622
12740
  {
12623
12741
  extends: rel.startsWith(".") ? rel : `./${rel}`,
@@ -12693,10 +12811,10 @@ dist/
12693
12811
  `;
12694
12812
  }
12695
12813
  function linkLocalPackagesForNoInstall(targetPath, localPackagesDir) {
12696
- const nm = join28(targetPath, "node_modules");
12814
+ const nm = join29(targetPath, "node_modules");
12697
12815
  mkdirSync8(nm, { recursive: true });
12698
- const dest = join28(nm, "@s2script");
12699
- if (!existsSync20(dest)) symlinkSync(localPackagesDir, dest);
12816
+ const dest = join29(nm, "@s2script");
12817
+ if (!existsSync21(dest)) symlinkSync(localPackagesDir, dest);
12700
12818
  }
12701
12819
  function runInstall(dir, pm) {
12702
12820
  if (pm === "none") return;
@@ -12725,7 +12843,7 @@ async function createPlugin(opts = {}) {
12725
12843
  );
12726
12844
  }
12727
12845
  let slug = workspaceRoot !== void 0 && opts.path !== void 0 ? assertBareSlug(opts.path) : opts.path;
12728
- let targetPath = workspaceRoot === void 0 ? resolve23(opts.path ?? ".") : slug === void 0 ? void 0 : join28(workspaceRoot, "plugins", slug);
12846
+ let targetPath = workspaceRoot === void 0 ? resolve23(opts.path ?? ".") : slug === void 0 ? void 0 : join29(workspaceRoot, "plugins", slug);
12729
12847
  if (targetPath !== void 0) assertEmptyTarget(targetPath);
12730
12848
  if (interactive) {
12731
12849
  intro2("Create an s2script plugin");
@@ -12735,7 +12853,7 @@ async function createPlugin(opts = {}) {
12735
12853
  slug = assertBareSlug(
12736
12854
  await text2({ message: "Plugin name (directory under plugins/)", placeholder: "myplugin" })
12737
12855
  );
12738
- targetPath = join28(workspaceRoot, "plugins", slug);
12856
+ targetPath = join29(workspaceRoot, "plugins", slug);
12739
12857
  assertEmptyTarget(targetPath);
12740
12858
  }
12741
12859
  }
@@ -12798,37 +12916,37 @@ async function createPlugin(opts = {}) {
12798
12916
  install = workspaceRoot !== void 0 ? "none" : install ?? (opts.noInstall ? "none" : "npm");
12799
12917
  const finalTargetPath = targetPath;
12800
12918
  const localPackagesDir = workspaceRoot === void 0 ? findLocalPackagesDir() : void 0;
12801
- mkdirSync8(join28(finalTargetPath, "src"), { recursive: true });
12919
+ mkdirSync8(join29(finalTargetPath, "src"), { recursive: true });
12802
12920
  if (workspaceRoot !== void 0) {
12803
- writeFileSync16(join28(finalTargetPath, "package.json"), minimalPackageJsonContent(name));
12921
+ writeFileSync16(join29(finalTargetPath, "package.json"), minimalPackageJsonContent(name));
12804
12922
  writeFileSync16(
12805
- join28(finalTargetPath, "tsconfig.json"),
12923
+ join29(finalTargetPath, "tsconfig.json"),
12806
12924
  workspaceTsconfigJson(finalTargetPath, workspaceRoot)
12807
12925
  );
12808
12926
  } else if (kind === "library") {
12809
12927
  const version = readCliVersion();
12810
12928
  writeFileSync16(
12811
- join28(finalTargetPath, "package.json"),
12929
+ join29(finalTargetPath, "package.json"),
12812
12930
  libraryPackageJsonContent(name, game, version, localPackagesDir)
12813
12931
  );
12814
- writeFileSync16(join28(finalTargetPath, "tsconfig.json"), tsconfigJson());
12815
- writeFileSync16(join28(finalTargetPath, "eslint.config.mjs"), eslintConfig());
12932
+ writeFileSync16(join29(finalTargetPath, "tsconfig.json"), tsconfigJson());
12933
+ writeFileSync16(join29(finalTargetPath, "eslint.config.mjs"), eslintConfig());
12816
12934
  } else {
12817
12935
  const version = readCliVersion();
12818
12936
  writeFileSync16(
12819
- join28(finalTargetPath, "package.json"),
12937
+ join29(finalTargetPath, "package.json"),
12820
12938
  packageJsonContent(name, game, version, localPackagesDir)
12821
12939
  );
12822
- writeFileSync16(join28(finalTargetPath, "tsconfig.json"), tsconfigJson());
12823
- writeFileSync16(join28(finalTargetPath, "eslint.config.mjs"), eslintConfig());
12940
+ writeFileSync16(join29(finalTargetPath, "tsconfig.json"), tsconfigJson());
12941
+ writeFileSync16(join29(finalTargetPath, "eslint.config.mjs"), eslintConfig());
12824
12942
  }
12825
12943
  if (kind === "library") {
12826
- writeFileSync16(join28(finalTargetPath, "src", "index.ts"), LIBRARY_ENTRY);
12827
- writeFileSync16(join28(finalTargetPath, "src", "index.d.ts"), LIBRARY_TYPES);
12944
+ writeFileSync16(join29(finalTargetPath, "src", "index.ts"), LIBRARY_ENTRY);
12945
+ writeFileSync16(join29(finalTargetPath, "src", "index.d.ts"), LIBRARY_TYPES);
12828
12946
  } else {
12829
- writeFileSync16(join28(finalTargetPath, "src", "plugin.ts"), pluginSource(game));
12947
+ writeFileSync16(join29(finalTargetPath, "src", "plugin.ts"), pluginSource(game));
12830
12948
  }
12831
- writeFileSync16(join28(finalTargetPath, ".gitignore"), gitignore());
12949
+ writeFileSync16(join29(finalTargetPath, ".gitignore"), gitignore());
12832
12950
  let installed = false;
12833
12951
  if (workspaceRoot === void 0) {
12834
12952
  if (install !== "none") {
@@ -12856,7 +12974,7 @@ async function createPlugin(opts = {}) {
12856
12974
 
12857
12975
  // src/create/workspace.ts
12858
12976
  import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync17 } from "node:fs";
12859
- import { join as join29, resolve as resolve24 } from "node:path";
12977
+ import { join as join30, resolve as resolve24 } from "node:path";
12860
12978
  var ROOT_DEFAULT_GAME = "cs2";
12861
12979
  var CHANGESETS_CLI_RANGE = "^2.29.5";
12862
12980
  function defaultWorkspaceName(dir) {
@@ -12940,14 +13058,14 @@ async function createWorkspace(opts = {}) {
12940
13058
  name = name ?? defaultWorkspaceName(targetPath);
12941
13059
  const version = readCliVersion();
12942
13060
  const localPackagesDir = findLocalPackagesDir();
12943
- mkdirSync9(join29(targetPath, "plugins"), { recursive: true });
12944
- mkdirSync9(join29(targetPath, "packages"), { recursive: true });
12945
- mkdirSync9(join29(targetPath, ".changeset"), { recursive: true });
12946
- writeFileSync17(join29(targetPath, "package.json"), rootPackageJsonContent(name, version, localPackagesDir));
12947
- writeFileSync17(join29(targetPath, "tsconfig.base.json"), tsconfigBaseJson());
12948
- writeFileSync17(join29(targetPath, "eslint.config.mjs"), eslintConfig());
12949
- writeFileSync17(join29(targetPath, ".changeset", "config.json"), changesetConfigJson());
12950
- writeFileSync17(join29(targetPath, ".gitignore"), gitignore());
13061
+ mkdirSync9(join30(targetPath, "plugins"), { recursive: true });
13062
+ mkdirSync9(join30(targetPath, "packages"), { recursive: true });
13063
+ mkdirSync9(join30(targetPath, ".changeset"), { recursive: true });
13064
+ writeFileSync17(join30(targetPath, "package.json"), rootPackageJsonContent(name, version, localPackagesDir));
13065
+ writeFileSync17(join30(targetPath, "tsconfig.base.json"), tsconfigBaseJson());
13066
+ writeFileSync17(join30(targetPath, "eslint.config.mjs"), eslintConfig());
13067
+ writeFileSync17(join30(targetPath, ".changeset", "config.json"), changesetConfigJson());
13068
+ writeFileSync17(join30(targetPath, ".gitignore"), gitignore());
12951
13069
  return { dir: targetPath, name };
12952
13070
  }
12953
13071
 
@@ -13183,8 +13301,8 @@ async function run7(argv2) {
13183
13301
  }
13184
13302
 
13185
13303
  // src/config/gen.ts
13186
- import { readFileSync as readFileSync25, writeFileSync as writeFileSync18, mkdirSync as mkdirSync10 } from "node:fs";
13187
- import { join as join30 } from "node:path";
13304
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync18, mkdirSync as mkdirSync10 } from "node:fs";
13305
+ import { join as join31 } from "node:path";
13188
13306
 
13189
13307
  // src/config/config-path.ts
13190
13308
  function configFileName(id) {
@@ -13231,12 +13349,12 @@ function genConfigFromManifest(manifest, outDir) {
13231
13349
  const id = typeof manifest.id === "string" ? manifest.id : "";
13232
13350
  if (!id) throw new Error("config gen: manifest declares config but has no id");
13233
13351
  mkdirSync10(outDir, { recursive: true });
13234
- const path2 = join30(outDir, configFileName(id));
13352
+ const path2 = join31(outDir, configFileName(id));
13235
13353
  writeFileSync18(path2, generateDefaultJsonc(config));
13236
13354
  return path2;
13237
13355
  }
13238
13356
  function genConfigForS2sp(s2spPath, outDir) {
13239
- const entry = unzipSync(readFileSync25(s2spPath))["manifest.json"];
13357
+ const entry = unzipSync(readFileSync26(s2spPath))["manifest.json"];
13240
13358
  if (!entry) throw new Error(`config gen: ${s2spPath} has no manifest.json`);
13241
13359
  const manifest = JSON.parse(Buffer.from(entry).toString("utf8"));
13242
13360
  return genConfigFromManifest(manifest, outDir);
@@ -13283,12 +13401,12 @@ async function run8(argv2) {
13283
13401
  }
13284
13402
 
13285
13403
  // src/commands/codegen.ts
13286
- import { dirname as dirname9, join as join35 } from "node:path";
13404
+ import { dirname as dirname9, join as join36 } from "node:path";
13287
13405
  import { fileURLToPath as fileURLToPath3 } from "node:url";
13288
13406
 
13289
13407
  // src/schemagen/gen.ts
13290
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync19 } from "node:fs";
13291
- import { join as join31 } from "node:path";
13408
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync19 } from "node:fs";
13409
+ import { join as join32 } from "node:path";
13292
13410
 
13293
13411
  // src/schemagen/model.ts
13294
13412
  function enumMemberNames(enumName, members) {
@@ -13837,16 +13955,16 @@ var EMBED_PATH = "games/cs2/codegen-embedded.json";
13837
13955
  var JS_OUT = "games/cs2/js/schema.generated.js";
13838
13956
  var DTS_OUT = "packages/cs2/schema.generated.d.ts";
13839
13957
  function runGenSchema(repoRoot2, opts) {
13840
- const catalog = JSON.parse(readFileSync26(join31(repoRoot2, CATALOG_PATH), "utf8"));
13841
- const list = JSON.parse(readFileSync26(join31(repoRoot2, LIST_PATH), "utf8"));
13958
+ const catalog = JSON.parse(readFileSync27(join32(repoRoot2, CATALOG_PATH), "utf8"));
13959
+ const list = JSON.parse(readFileSync27(join32(repoRoot2, LIST_PATH), "utf8"));
13842
13960
  let embed = [];
13843
13961
  try {
13844
- embed = JSON.parse(readFileSync26(join31(repoRoot2, EMBED_PATH), "utf8"));
13962
+ embed = JSON.parse(readFileSync27(join32(repoRoot2, EMBED_PATH), "utf8"));
13845
13963
  } catch {
13846
13964
  }
13847
13965
  let enumCatalog = {};
13848
13966
  try {
13849
- enumCatalog = JSON.parse(readFileSync26(join31(repoRoot2, ENUMS_PATH), "utf8"));
13967
+ enumCatalog = JSON.parse(readFileSync27(join32(repoRoot2, ENUMS_PATH), "utf8"));
13850
13968
  } catch {
13851
13969
  }
13852
13970
  const model = buildModel(catalog, list, embed, enumCatalog);
@@ -13857,11 +13975,11 @@ function runGenSchema(repoRoot2, opts) {
13857
13975
  const drift = [];
13858
13976
  const files = [[JS_OUT, js], [DTS_OUT, dts]];
13859
13977
  for (const [rel, content] of files) {
13860
- const abs = join31(repoRoot2, rel);
13978
+ const abs = join32(repoRoot2, rel);
13861
13979
  if (opts.check) {
13862
13980
  let cur = "";
13863
13981
  try {
13864
- cur = readFileSync26(abs, "utf8");
13982
+ cur = readFileSync27(abs, "utf8");
13865
13983
  } catch {
13866
13984
  }
13867
13985
  if (cur !== content) drift.push(rel);
@@ -13876,8 +13994,8 @@ function runGenSchema(repoRoot2, opts) {
13876
13994
  }
13877
13995
 
13878
13996
  // src/eventgen/gen.ts
13879
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync20 } from "node:fs";
13880
- import { join as join32 } from "node:path";
13997
+ import { readFileSync as readFileSync28, writeFileSync as writeFileSync20 } from "node:fs";
13998
+ import { join as join33 } from "node:path";
13881
13999
 
13882
14000
  // src/eventgen/model.ts
13883
14001
  var TYPE_TO_GETTER = {
@@ -13962,15 +14080,15 @@ function emitEventDts(model) {
13962
14080
  var CATALOG_PATH2 = "games/cs2/gamedata/event-catalog.json";
13963
14081
  var DTS_OUT2 = "packages/cs2/events.generated.d.ts";
13964
14082
  function runGenEvents(repoRoot2, opts) {
13965
- const catalog = JSON.parse(readFileSync27(join32(repoRoot2, CATALOG_PATH2), "utf8"));
14083
+ const catalog = JSON.parse(readFileSync28(join33(repoRoot2, CATALOG_PATH2), "utf8"));
13966
14084
  const model = buildEventModel(catalog);
13967
14085
  const dts = emitEventDts(model);
13968
14086
  const drift = [];
13969
- const abs = join32(repoRoot2, DTS_OUT2);
14087
+ const abs = join33(repoRoot2, DTS_OUT2);
13970
14088
  if (opts.check) {
13971
14089
  let cur = "";
13972
14090
  try {
13973
- cur = readFileSync27(abs, "utf8");
14091
+ cur = readFileSync28(abs, "utf8");
13974
14092
  } catch {
13975
14093
  }
13976
14094
  if (cur !== dts) drift.push(DTS_OUT2);
@@ -13981,8 +14099,8 @@ function runGenEvents(repoRoot2, opts) {
13981
14099
  }
13982
14100
 
13983
14101
  // src/navgen/gen.ts
13984
- import { readFileSync as readFileSync28, writeFileSync as writeFileSync21 } from "node:fs";
13985
- import { join as join33 } from "node:path";
14102
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "node:fs";
14103
+ import { join as join34 } from "node:path";
13986
14104
 
13987
14105
  // src/navgen/model.ts
13988
14106
  var SUPPORTED_NAV_KINDS = /* @__PURE__ */ new Set([
@@ -14196,8 +14314,8 @@ var CATALOG_PATH3 = "games/cs2/gamedata/schema-catalog.json";
14196
14314
  var JS_OUT2 = "games/cs2/js/nav.generated.js";
14197
14315
  var DTS_OUT3 = "packages/cs2/nav.generated.d.ts";
14198
14316
  function runGenNav(repoRoot2, opts) {
14199
- const config = JSON.parse(readFileSync28(join33(repoRoot2, TARGETS_PATH), "utf8"));
14200
- const catalog = JSON.parse(readFileSync28(join33(repoRoot2, CATALOG_PATH3), "utf8"));
14317
+ const config = JSON.parse(readFileSync29(join34(repoRoot2, TARGETS_PATH), "utf8"));
14318
+ const catalog = JSON.parse(readFileSync29(join34(repoRoot2, CATALOG_PATH3), "utf8"));
14201
14319
  const model = buildNavModel(config, catalog);
14202
14320
  const js = emitNavJs(model);
14203
14321
  const dts = emitNavDts(model);
@@ -14205,11 +14323,11 @@ function runGenNav(repoRoot2, opts) {
14205
14323
  const drift = [];
14206
14324
  const files = [[JS_OUT2, js], [DTS_OUT3, dts]];
14207
14325
  for (const [rel, content] of files) {
14208
- const abs = join33(repoRoot2, rel);
14326
+ const abs = join34(repoRoot2, rel);
14209
14327
  if (opts.check) {
14210
14328
  let cur = "";
14211
14329
  try {
14212
- cur = readFileSync28(abs, "utf8");
14330
+ cur = readFileSync29(abs, "utf8");
14213
14331
  } catch {
14214
14332
  }
14215
14333
  if (cur !== content) drift.push(rel);
@@ -14221,22 +14339,22 @@ function runGenNav(repoRoot2, opts) {
14221
14339
  }
14222
14340
 
14223
14341
  // src/hookgen/gen.ts
14224
- import { readFileSync as readFileSync29, writeFileSync as writeFileSync22 } from "node:fs";
14225
- import { join as join34 } from "node:path";
14342
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
14343
+ import { join as join35 } from "node:path";
14226
14344
  var GAMEDATA_PATH = "games/cs2/gamedata/game.cs2.jsonc";
14227
14345
  var DTS_OUT4 = "packages/cs2/hooks.generated.d.ts";
14228
14346
  function runGenHooks(repoRoot2, opts) {
14229
- const raw = readFileSync29(join34(repoRoot2, GAMEDATA_PATH), "utf8");
14347
+ const raw = readFileSync30(join35(repoRoot2, GAMEDATA_PATH), "utf8");
14230
14348
  const gd = JSON.parse(stripJsonComments(raw));
14231
14349
  const hooks = gd.hooks ?? {};
14232
14350
  const model = buildHookModel(hooks);
14233
14351
  const dts = emitHookDts(model);
14234
14352
  const drift = [];
14235
- const abs = join34(repoRoot2, DTS_OUT4);
14353
+ const abs = join35(repoRoot2, DTS_OUT4);
14236
14354
  if (opts.check) {
14237
14355
  let cur = "";
14238
14356
  try {
14239
- cur = readFileSync29(abs, "utf8");
14357
+ cur = readFileSync30(abs, "utf8");
14240
14358
  } catch {
14241
14359
  }
14242
14360
  if (cur !== dts) drift.push(DTS_OUT4);
@@ -14249,7 +14367,7 @@ function runGenHooks(repoRoot2, opts) {
14249
14367
 
14250
14368
  // src/commands/codegen.ts
14251
14369
  function repoRoot() {
14252
- return join35(dirname9(fileURLToPath3(import.meta.url)), "..", "..", "..");
14370
+ return join36(dirname9(fileURLToPath3(import.meta.url)), "..", "..", "..");
14253
14371
  }
14254
14372
  async function run9(kind, argv2) {
14255
14373
  const root = repoRoot();
@@ -14306,9 +14424,9 @@ async function run9(kind, argv2) {
14306
14424
  }
14307
14425
 
14308
14426
  // src/commands/inspect.ts
14309
- import { readFileSync as readFileSync30 } from "node:fs";
14427
+ import { readFileSync as readFileSync31 } from "node:fs";
14310
14428
  function inspectArchive(path2) {
14311
- const files = unzipSync(readFileSync30(path2));
14429
+ const files = unzipSync(readFileSync31(path2));
14312
14430
  if (!files["manifest.json"]) throw new Error(`${path2}: missing manifest.json`);
14313
14431
  const manifest = JSON.parse(Buffer.from(files["manifest.json"]).toString("utf8"));
14314
14432
  const lines = [`plugin: ${manifest.id ?? "(unknown)"}`];
@@ -14337,8 +14455,8 @@ async function run10(argv2) {
14337
14455
  }
14338
14456
 
14339
14457
  // src/engine-functions/migrate-v1.ts
14340
- import { closeSync, existsSync as existsSync21, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync11, openSync, readFileSync as readFileSync31, readdirSync as readdirSync9, renameSync as renameSync4, unlinkSync, writeFileSync as writeFileSync23 } from "node:fs";
14341
- import { dirname as dirname10, isAbsolute as isAbsolute2, join as join36, relative as relative5, resolve as resolve26, sep as sep6 } from "node:path";
14458
+ import { closeSync, existsSync as existsSync22, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync11, openSync, readFileSync as readFileSync32, readdirSync as readdirSync9, renameSync as renameSync4, unlinkSync, writeFileSync as writeFileSync23 } from "node:fs";
14459
+ import { dirname as dirname10, isAbsolute as isAbsolute2, join as join37, relative as relative5, resolve as resolve26, sep as sep6 } from "node:path";
14342
14460
  import { createHash as createHash6, randomUUID } from "node:crypto";
14343
14461
  import ts6 from "typescript";
14344
14462
  var PLATFORM3 = "linuxsteamrt64";
@@ -14465,11 +14583,11 @@ function hookOf(name, value, signatures, errors) {
14465
14583
  }
14466
14584
  function sourceFiles(dir, pkg, errors) {
14467
14585
  const result = /* @__PURE__ */ new Set();
14468
- const src = join36(dir, "src");
14586
+ const src = join37(dir, "src");
14469
14587
  function walk(at) {
14470
- if (!existsSync21(at)) return;
14588
+ if (!existsSync22(at)) return;
14471
14589
  for (const item of readdirSync9(at, { withFileTypes: true })) {
14472
- const p = join36(at, item.name);
14590
+ const p = join37(at, item.name);
14473
14591
  if (item.isDirectory()) walk(p);
14474
14592
  else if (item.isFile() && /\.[cm]?[jt]sx?$/.test(item.name)) result.add(p);
14475
14593
  }
@@ -14477,12 +14595,12 @@ function sourceFiles(dir, pkg, errors) {
14477
14595
  walk(src);
14478
14596
  if (valid2(pkg.main)) {
14479
14597
  const p = resolve26(dir, pkg.main);
14480
- if (contained(dir, p) && existsSync21(p) && lstatSync2(p).isFile()) result.add(p);
14598
+ if (contained(dir, p) && existsSync22(p) && lstatSync2(p).isFile()) result.add(p);
14481
14599
  }
14482
14600
  const queue = [...result];
14483
14601
  for (let i2 = 0; i2 < queue.length; i2++) {
14484
14602
  const file = queue[i2];
14485
- const ast = ts6.createSourceFile(file, readFileSync31(file, "utf8"), ts6.ScriptTarget.Latest, true);
14603
+ const ast = ts6.createSourceFile(file, readFileSync32(file, "utf8"), ts6.ScriptTarget.Latest, true);
14486
14604
  const follow = (spec, node) => {
14487
14605
  if (!spec.startsWith(".")) return;
14488
14606
  const at = `${relative5(dir, file)}:${ast.getLineAndCharacterOfPosition(node.getStart(ast)).line + 1}`;
@@ -14492,8 +14610,8 @@ function sourceFiles(dir, pkg, errors) {
14492
14610
  return;
14493
14611
  }
14494
14612
  const stem = base.replace(/\.[cm]?[jt]sx?$/, "");
14495
- const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) => join36(base, x))];
14496
- const found = candidates.find((p) => contained(dir, p) && existsSync21(p) && lstatSync2(p).isFile());
14613
+ const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs"].map((x) => stem + x), ...["index.ts", "index.tsx", "index.js", "index.jsx"].map((x) => join37(base, x))];
14614
+ const found = candidates.find((p) => contained(dir, p) && existsSync22(p) && lstatSync2(p).isFile());
14497
14615
  if (!found) {
14498
14616
  errors.push(`${at}: unresolved local module ${JSON.stringify(spec)}`);
14499
14617
  return;
@@ -14523,7 +14641,7 @@ function sourceFiles(dir, pkg, errors) {
14523
14641
  function scanSource(files, calls, hooks, report) {
14524
14642
  const namespaces = new Set(hooks.values());
14525
14643
  for (const file of files) {
14526
- const source = ts6.createSourceFile(file, readFileSync31(file, "utf8"), ts6.ScriptTarget.Latest, true);
14644
+ const source = ts6.createSourceFile(file, readFileSync32(file, "utf8"), ts6.ScriptTarget.Latest, true);
14527
14645
  if (source.parseDiagnostics?.length) report.ambiguities.push(`${relative5(report.package, file)}: source syntax errors prevent reliable reference analysis`);
14528
14646
  const ambiguity = (node, message) => {
14529
14647
  report.ambiguities.push(`${relative5(report.package, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}: ${message}`);
@@ -14663,12 +14781,12 @@ function scanSource(files, calls, hooks, report) {
14663
14781
  }
14664
14782
  function analyzeV1Migration(pluginDir, options = {}) {
14665
14783
  const dir = resolve26(pluginDir);
14666
- const destination = join36(dir, "gamedata", "functions.jsonc");
14784
+ const destination = join37(dir, "gamedata", "functions.jsonc");
14667
14785
  const report = { scope: SCOPE, package: dir, destination, entries: [], permissions: [], sourceReferences: [], generatedDeclarations: [], generatedDeclarationHashes: {}, recommendedEdits: [], ambiguities: [], filesChanged: [] };
14668
14786
  if (pathExists(destination) && !options.force) report.ambiguities.push(`${destination}: destination already exists; use --force to replace it`);
14669
14787
  let pkg;
14670
14788
  try {
14671
- pkg = parseFunctionFile(join36(dir, "package.json"), readFileSync31(join36(dir, "package.json"), "utf8"));
14789
+ pkg = parseFunctionFile(join37(dir, "package.json"), readFileSync32(join37(dir, "package.json"), "utf8"));
14672
14790
  } catch (e) {
14673
14791
  report.ambiguities.push(`package.json: ${e.message}`);
14674
14792
  return report;
@@ -14690,7 +14808,7 @@ function analyzeV1Migration(pluginDir, options = {}) {
14690
14808
  }
14691
14809
  let gd;
14692
14810
  try {
14693
- gd = parseFunctionFile(input, readFileSync31(input, "utf8"));
14811
+ gd = parseFunctionFile(input, readFileSync32(input, "utf8"));
14694
14812
  } catch (e) {
14695
14813
  report.ambiguities.push(`gamedata: ${e.message}`);
14696
14814
  return report;
@@ -14790,10 +14908,10 @@ function analyzeV1Migration(pluginDir, options = {}) {
14790
14908
  }
14791
14909
  }
14792
14910
  report.output = author;
14793
- report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) => join36(dir, ".s2script", n3)).filter(existsSync21);
14911
+ report.generatedDeclarations = ["gamedata.d.ts", "hooks.d.ts"].map((n3) => join37(dir, ".s2script", n3)).filter(existsSync22);
14794
14912
  for (const file of report.generatedDeclarations) {
14795
14913
  try {
14796
- report.generatedDeclarationHashes[file] = createHash6("sha256").update(readFileSync31(file)).digest("hex");
14914
+ report.generatedDeclarationHashes[file] = createHash6("sha256").update(readFileSync32(file)).digest("hex");
14797
14915
  } catch (e) {
14798
14916
  report.ambiguities.push(`${file}: generated declaration could not be read: ${e.message}`);
14799
14917
  }
@@ -14812,7 +14930,7 @@ function migrateV1Package(pluginDir, options = {}) {
14812
14930
  const report = analyzeV1Migration(pluginDir, options);
14813
14931
  if (report.ambiguities.length || !report.output) return report;
14814
14932
  const dest = report.destination;
14815
- const temp = join36(dirname10(dest), `.functions.jsonc.${process.pid}.${randomUUID()}.tmp`);
14933
+ const temp = join37(dirname10(dest), `.functions.jsonc.${process.pid}.${randomUUID()}.tmp`);
14816
14934
  try {
14817
14935
  mkdirSync11(dirname10(dest), { recursive: true });
14818
14936
  const fd2 = openSync(temp, "wx", 384);
@@ -14834,7 +14952,7 @@ function migrateV1Package(pluginDir, options = {}) {
14834
14952
  report.publication = void 0;
14835
14953
  report.ambiguities.push(`${dest}: publication failed: ${e.message}`);
14836
14954
  } finally {
14837
- if (existsSync21(temp)) unlinkSync(temp);
14955
+ if (existsSync22(temp)) unlinkSync(temp);
14838
14956
  }
14839
14957
  return report;
14840
14958
  }
@@ -14854,8 +14972,8 @@ async function run11(argv2) {
14854
14972
 
14855
14973
  // src/commands/pack.ts
14856
14974
  import { createHash as createHash7 } from "node:crypto";
14857
- import { readFileSync as readFileSync32, writeFileSync as writeFileSync24 } from "node:fs";
14858
- import { join as join37, resolve as resolve27 } from "node:path";
14975
+ import { readFileSync as readFileSync33, writeFileSync as writeFileSync24 } from "node:fs";
14976
+ import { join as join38, resolve as resolve27 } from "node:path";
14859
14977
  function formatBytes(n3) {
14860
14978
  if (n3 < 1e3) return `${n3}B`;
14861
14979
  if (n3 < 1e3 * 1e3) return `${(n3 / 1e3).toFixed(1)}kB`;
@@ -14863,9 +14981,9 @@ function formatBytes(n3) {
14863
14981
  }
14864
14982
  function packPackage(dir) {
14865
14983
  const absDir = resolve27(dir);
14866
- const pkg = JSON.parse(readFileSync32(join37(absDir, "package.json"), "utf8"));
14984
+ const pkg = JSON.parse(readFileSync33(join38(absDir, "package.json"), "utf8"));
14867
14985
  if (typeof pkg.name !== "string" || typeof pkg.version !== "string") {
14868
- throw new Error(`${join37(absDir, "package.json")}: "name" and "version" are required to pack`);
14986
+ throw new Error(`${join38(absDir, "package.json")}: "name" and "version" are required to pack`);
14869
14987
  }
14870
14988
  const pack = packSourceTarball(absDir, pkg);
14871
14989
  return {
@@ -14923,8 +15041,8 @@ async function run12(argv2) {
14923
15041
  }
14924
15042
 
14925
15043
  // src/commands/server.ts
14926
- import { existsSync as existsSync22 } from "node:fs";
14927
- import { join as join38, resolve as resolve28 } from "node:path";
15044
+ import { existsSync as existsSync23 } from "node:fs";
15045
+ import { join as join39, resolve as resolve28 } from "node:path";
14928
15046
  async function run13(argv2) {
14929
15047
  const [sub, dir] = positionals(argv2, ["--registry", "--name"]);
14930
15048
  if (sub !== "init") {
@@ -14933,7 +15051,7 @@ async function run13(argv2) {
14933
15051
  }
14934
15052
  const root = dir ? resolve28(dir) : findAddonRoot(".") ?? resolve28("addons", "s2script");
14935
15053
  try {
14936
- if (!existsSync22(join38(root, "plugins"))) {
15054
+ if (!existsSync23(join39(root, "plugins"))) {
14937
15055
  throw new Error(`${root} has no plugins/ directory \u2014 pass your addons/s2script directory`);
14938
15056
  }
14939
15057
  const report = await serverInit({
@@ -14945,7 +15063,7 @@ async function run13(argv2) {
14945
15063
  for (const m of report.managed) console.log(`managed ${m.name}@${m.version} (${m.filename})`);
14946
15064
  for (const u4 of report.unmanaged) console.log(`unmanaged ${u4.filename}: ${u4.reason}`);
14947
15065
  console.log(
14948
- `wrote ${join38(root, "plugins.json")} and plugins-lock.json \u2014 ${report.managed.length} managed, ${report.unmanaged.length} left as they are`
15066
+ `wrote ${join39(root, "plugins.json")} and plugins-lock.json \u2014 ${report.managed.length} managed, ${report.unmanaged.length} left as they are`
14949
15067
  );
14950
15068
  } catch (e) {
14951
15069
  console.error(String(e instanceof Error ? e.message : e));