@newlandnpt/pep-cli 0.6.1 → 0.8.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.
Files changed (3) hide show
  1. package/README.md +35 -9
  2. package/dist/pep.cjs +130 -48
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -72,16 +72,17 @@ The issuer is fixed at build time:
72
72
  `--issuer` remains available only as a temporary override — it is **not** remembered, so every
73
73
  `auth login` needs it again. That is why the built-in default decides where most users land.
74
74
 
75
- ⚠ **The npm release is currently built from `development`** — it ships
76
- `https://pep-webapp-dev.onrender.com` (see `prepack` in `package.json`). This is a deliberate
77
- temporary state: production is not going live in the near term and this build is for other
78
- departments to use now.
75
+ The npm release is built from `production` — it ships `https://pep.newlandnpt.us` and that
76
+ deployment's `client_id`. Both are baked in at build time, so a release already out in the wild
77
+ cannot be repointed; a change to either needs a new version.
79
78
 
80
- `https://pep.newlandnpt.us/.well-known/openid-configuration` still returns **404** (last checked
81
- 2026-09-09) — the production domain does not serve the authorization server yet, so a
82
- `production` build fails at discovery on the user's very first `auth login`. **Switch `prepack`
83
- back to `production` and publish immediately once that endpoint is live**: the issuer is baked in
84
- at build time, so releases already out in the wild cannot be repointed.
79
+ ⚠ **This package is only ready-to-use against production.** `/authorize` looks the `client_id` up
80
+ in each deployment's own database, so the baked one does not exist on dev or view. To reach a
81
+ non-production deployment you must pass **both** flags, **every login** — neither is remembered:
82
+
83
+ ```powershell
84
+ pep auth login --issuer https://pep-webapp-dev.onrender.com --client-id <that deployment's id>
85
+ ```
85
86
 
86
87
  ## Skills
87
88
 
@@ -193,6 +194,31 @@ offers".
193
194
  Skills that are **new upstream** are still installed by `update` — the test is "was mine and is now
194
195
  gone", not "is absent".
195
196
 
197
+ ## Maven credentials
198
+
199
+ ```powershell
200
+ pep nexus setup
201
+ ```
202
+
203
+ Asks PEP for your Maven repository credential and saves it as the two environment variables the
204
+ Newland Android SDK reads (`NEWLAND_MAVEN_USERNAME` / `NEWLAND_MAVEN_PASSWORD`). Windows uses
205
+ `setx`; macOS keeps a marked block in your shell profile, backed up first.
206
+
207
+ **The password is never printed.** The credential is derived from who you are, so running this
208
+ again — on this machine or any other — hands you the same one; nothing is lost by not showing it.
209
+ Use `--print-env` when you want the two lines on stdout instead:
210
+
211
+ ```bash
212
+ eval "$(pep nexus setup --print-env)" # the shell you are in gets them now
213
+ ```
214
+
215
+ The credential is per person, not per company — colleagues get their own, and so does the same
216
+ account on a second machine.
217
+
218
+ ⚠ Persistence only reaches **new** processes. A running IDE keeps the environment it started with,
219
+ and the Gradle daemon outlives the IDE, so after the first setup: quit Android Studio completely,
220
+ run `gradlew --stop`, then reopen.
221
+
196
222
  `pep auth token` writes only the access token to stdout, so agents can use it without parsing status
197
223
  text. Refresh occurs automatically shortly before expiry and the rotated refresh token replaces the old
198
224
  credential atomically.
package/dist/pep.cjs CHANGED
@@ -9,7 +9,7 @@ var import_node_path2 = require("node:path");
9
9
  var import_promises = require("node:fs/promises");
10
10
  var import_node_os = require("node:os");
11
11
  var import_node_path = require("node:path");
12
- var DEFAULT_CLIENT_ID = "pep-cli";
12
+ var DEFAULT_CLIENT_ID = "a96eccf418a4591f738e395fa6d0a0ef";
13
13
  var DEFAULT_REDIRECT_URI = "http://localhost:53682/callback";
14
14
  var DEFAULT_SCOPES = [
15
15
  "openid",
@@ -21,13 +21,13 @@ var DEFAULT_SCOPES = [
21
21
  ];
22
22
  var DEFAULT_RESOURCES = ["urn:newland:pep:docs"];
23
23
  var LEGACY_PACKAGE = "semi-integration";
24
- var DEFAULT_DOCS_URL = "https://pep-developer-docs.onrender.com";
24
+ var DEFAULT_DOCS_URL = "https://docs.newlandnpt.us";
25
25
  function issuerForEnvironment(environment) {
26
26
  if (environment === "production") return "https://pep.newlandnpt.us";
27
27
  if (environment === "view") return "https://pep-webapp-view.onrender.com";
28
28
  return "https://pep-webapp-dev.onrender.com";
29
29
  }
30
- var BUILD_ENVIRONMENT = false ? "development" : "development";
30
+ var BUILD_ENVIRONMENT = false ? "development" : "production";
31
31
  var DEFAULT_ISSUER = issuerForEnvironment(BUILD_ENVIRONMENT);
32
32
  function configuredIssuer(explicitIssuer) {
33
33
  return explicitIssuer ?? DEFAULT_ISSUER;
@@ -51,6 +51,9 @@ function defaultSkillsDirectory() {
51
51
  function claudeSkillsDirectory() {
52
52
  return (0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills");
53
53
  }
54
+ function samePlace(a, b) {
55
+ return a.toLowerCase() === b.toLowerCase();
56
+ }
54
57
  function userSkillsTarget() {
55
58
  return { directory: defaultSkillsDirectory(), linkInto: claudeSkillsDirectory() };
56
59
  }
@@ -971,7 +974,7 @@ function describeFailure2(status, code) {
971
974
  return "This access token carries no `nexus-credentials:write` scope. Ask an operator to add it to this client's allowed_scopes in PEP, then run `pep auth login` again \u2014 existing tokens do not gain new scopes.";
972
975
  }
973
976
  if (status === 409) {
974
- return "This organisation already has a Maven credential. PEP does not store the password, so it cannot be shown again \u2014 ask an operator to reset it in Nexus, or reuse the one you saved earlier.";
977
+ return "This PEP deployment still issues one Maven credential per company, so it cannot give you yours again. Newer PEP issues one per person and can always re-derive it \u2014 ask an operator to upgrade this deployment; until then, copy the credential from the machine that has it.";
975
978
  }
976
979
  if (status === 503) {
977
980
  return "PEP could not reach Nexus (not configured, or upstream is down). This is a platform-side problem \u2014 retrying will not help. Report it to a PEP operator.";
@@ -1102,6 +1105,14 @@ function readTar(bytes) {
1102
1105
 
1103
1106
  // src/skills-service.ts
1104
1107
  var ARCHIVE_PATH = "/api/skills/archive";
1108
+ var MAX_ARCHIVE_BYTES = 64 * 1024 * 1024;
1109
+ var MAX_UNPACKED_BYTES = 256 * 1024 * 1024;
1110
+ var MAX_ENTRIES = 1e4;
1111
+ function tooBig(what, limit) {
1112
+ return new Error(
1113
+ `The skills archive is too large (${what} exceeds ${Math.round(limit / 1024 / 1024)} MiB). Refusing to unpack it.`
1114
+ );
1115
+ }
1105
1116
  var SKILL_MANIFEST = "SKILL.md";
1106
1117
  function planSkillFiles(entries) {
1107
1118
  const roots = [];
@@ -1116,13 +1127,13 @@ function planSkillFiles(entries) {
1116
1127
  for (const root of roots) {
1117
1128
  const name = root[root.length - 1];
1118
1129
  const where = root.join("/");
1119
- const first = seen.get(name);
1130
+ const first = seen.get(name.toLowerCase());
1120
1131
  if (first !== void 0) {
1121
1132
  throw new Error(
1122
1133
  `Two skills in this package would both be called "${name}": ${first} and ${where}. Skill names come from the directory name, so they must be unique within a package.`
1123
1134
  );
1124
1135
  }
1125
- seen.set(name, where);
1136
+ seen.set(name.toLowerCase(), where);
1126
1137
  }
1127
1138
  const files = [];
1128
1139
  for (const entry of entries) {
@@ -1137,9 +1148,38 @@ function planSkillFiles(entries) {
1137
1148
  }
1138
1149
  return files;
1139
1150
  }
1151
+ async function readCapped(response, limit) {
1152
+ const reader = response.body?.getReader();
1153
+ if (!reader) return new Uint8Array(await response.arrayBuffer());
1154
+ const chunks = [];
1155
+ let total = 0;
1156
+ for (; ; ) {
1157
+ const { done, value } = await reader.read();
1158
+ if (done) break;
1159
+ total += value.byteLength;
1160
+ if (total > limit) {
1161
+ await reader.cancel();
1162
+ throw tooBig("the download", limit);
1163
+ }
1164
+ chunks.push(value);
1165
+ }
1166
+ const out = new Uint8Array(total);
1167
+ let at = 0;
1168
+ for (const chunk of chunks) {
1169
+ out.set(chunk, at);
1170
+ at += chunk.byteLength;
1171
+ }
1172
+ return out;
1173
+ }
1174
+ function assertInside(base, target) {
1175
+ const rel = (0, import_node_path4.relative)((0, import_node_path4.resolve)(base), (0, import_node_path4.resolve)(target));
1176
+ if (rel === "" || rel.startsWith("..") || (0, import_node_path4.isAbsolute)(rel)) {
1177
+ throw new Error(`Refusing an archive entry that escapes its directory: ${target}`);
1178
+ }
1179
+ }
1140
1180
  function segmentsOf(path) {
1141
- const segments = path.split("/").filter((one) => one !== "" && one !== ".");
1142
- if (segments.some((one) => one === "..")) {
1181
+ const segments = path.split(/[\\/]+/).filter((one) => one !== "" && one !== ".");
1182
+ if (segments.some((one) => one === ".." || /^[a-z]:$/i.test(one))) {
1143
1183
  throw new Error(`Refusing an archive entry that escapes its directory: ${path}`);
1144
1184
  }
1145
1185
  return segments;
@@ -1195,6 +1235,12 @@ function hashSkill(files) {
1195
1235
  }
1196
1236
  return hash.digest("hex").slice(0, 32);
1197
1237
  }
1238
+ function otherClaimant(packages, self, directory, skill) {
1239
+ const wanted = skill.toLowerCase();
1240
+ return Object.entries(packages).find(
1241
+ ([other, pkg]) => other !== self && samePlace(pkg.directory, directory) && Object.keys(pkg.skills).some((one) => one.toLowerCase() === wanted)
1242
+ )?.[0];
1243
+ }
1198
1244
  async function removeSkills(name, store) {
1199
1245
  const state = await store.read();
1200
1246
  const pkg = state?.packages[name];
@@ -1204,9 +1250,7 @@ async function removeSkills(name, store) {
1204
1250
  const deleted = [];
1205
1251
  const keptForOthers = [];
1206
1252
  for (const skill of Object.keys(pkg.skills).sort()) {
1207
- const owner = Object.entries(state.packages).find(
1208
- ([other, one]) => other !== name && one.directory === pkg.directory && skill in one.skills
1209
- )?.[0];
1253
+ const owner = otherClaimant(state.packages, name, pkg.directory, skill);
1210
1254
  if (owner !== void 0) {
1211
1255
  keptForOthers.push({ skill, owner });
1212
1256
  continue;
@@ -1248,10 +1292,8 @@ async function updateSkills(dependencies) {
1248
1292
  const commit = response.headers.get("x-skills-commit") ?? void 0;
1249
1293
  const state = await dependencies.stateStore.read();
1250
1294
  const previous = state?.packages[name];
1251
- const sameTarget = previous?.directory === dependencies.directory && previous?.linkedInto === dependencies.linkInto;
1252
- const claimedElsewhere = (skill) => Object.entries(state?.packages ?? {}).find(
1253
- ([other, pkg]) => other !== name && pkg.directory === dependencies.directory && skill in pkg.skills
1254
- )?.[0];
1295
+ const sameTarget = previous !== void 0 && samePlace(previous.directory, dependencies.directory) && (previous.linkedInto === void 0 ? dependencies.linkInto === void 0 : dependencies.linkInto !== void 0 && samePlace(previous.linkedInto, dependencies.linkInto));
1296
+ const claimedElsewhere = (skill) => otherClaimant(state?.packages ?? {}, name, dependencies.directory, skill);
1255
1297
  const gone = previous !== void 0 && sameTarget ? await missingSkills(previous.directory, Object.keys(previous.skills)) : /* @__PURE__ */ new Set();
1256
1298
  const nothingToRestore = !dependencies.restoreMissing || gone.size === 0;
1257
1299
  const standing = Object.keys(previous?.skills ?? {}).flatMap((skill) => {
@@ -1262,8 +1304,23 @@ async function updateSkills(dependencies) {
1262
1304
  await response.body?.cancel();
1263
1305
  return { status: "unchanged", name, commit, conflicts: standing };
1264
1306
  }
1265
- const gzipped = new Uint8Array(await response.arrayBuffer());
1266
- const files = planSkillFiles(readTar((0, import_node_zlib.gunzipSync)(gzipped)));
1307
+ const gzipped = await readCapped(response, dependencies.maxArchiveBytes ?? MAX_ARCHIVE_BYTES);
1308
+ let unpacked;
1309
+ try {
1310
+ unpacked = (0, import_node_zlib.gunzipSync)(gzipped, { maxOutputLength: MAX_UNPACKED_BYTES });
1311
+ } catch (error) {
1312
+ if (error.code === "ERR_BUFFER_TOO_LARGE") {
1313
+ throw tooBig("the unpacked archive", MAX_UNPACKED_BYTES);
1314
+ }
1315
+ throw error;
1316
+ }
1317
+ const entries = readTar(unpacked);
1318
+ if (entries.length > MAX_ENTRIES) {
1319
+ throw new Error(
1320
+ `The skills archive holds ${entries.length} files (limit ${MAX_ENTRIES}). Refusing to unpack it.`
1321
+ );
1322
+ }
1323
+ const files = planSkillFiles(entries);
1267
1324
  const bySkill = /* @__PURE__ */ new Map();
1268
1325
  for (const file of files) {
1269
1326
  const group = bySkill.get(file.skill);
@@ -1300,6 +1357,7 @@ async function updateSkills(dependencies) {
1300
1357
  if (previous !== void 0) {
1301
1358
  const stale = sameTarget ? removed : Object.keys(previous.skills);
1302
1359
  for (const skill of stale) {
1360
+ if (otherClaimant(state?.packages ?? {}, name, previous.directory, skill)) continue;
1303
1361
  await (0, import_promises4.rm)((0, import_node_path4.join)(previous.directory, skill), { recursive: true, force: true });
1304
1362
  if (previous.linkedInto !== void 0) {
1305
1363
  await (0, import_promises4.rm)((0, import_node_path4.join)(previous.linkedInto, skill), { recursive: true, force: true });
@@ -1313,6 +1371,7 @@ async function updateSkills(dependencies) {
1313
1371
  for (const file of files) {
1314
1372
  if (untouched.has(file.skill)) continue;
1315
1373
  const target = (0, import_node_path4.join)(dependencies.directory, file.skill, ...file.path.split("/"));
1374
+ assertInside(dependencies.directory, target);
1316
1375
  await (0, import_promises4.mkdir)((0, import_node_path4.dirname)(target), { recursive: true });
1317
1376
  await (0, import_promises4.writeFile)(target, file.data);
1318
1377
  }
@@ -1353,7 +1412,9 @@ async function updateSkills(dependencies) {
1353
1412
  updated,
1354
1413
  unchanged,
1355
1414
  skills,
1356
- fileCount: files.filter((one) => !skipped.includes(one.skill)).length,
1415
+ // ⚠ 扣掉的是 `untouched` 全部(用户删的 + 让给别的包的),不只是 skipped ——
1416
+ // 让开没写的那些文件算进去,「N file(s)」就是句假话。
1417
+ fileCount: files.filter((one) => !untouched.has(one.skill)).length,
1357
1418
  removed,
1358
1419
  skipped,
1359
1420
  conflicts,
@@ -1365,7 +1426,7 @@ async function updateSkills(dependencies) {
1365
1426
  }
1366
1427
 
1367
1428
  // src/cli.ts
1368
- var VERSION = false ? "0.0.0-dev" : "0.6.1";
1429
+ var VERSION = false ? "0.0.0-dev" : "0.8.0";
1369
1430
  function usage() {
1370
1431
  return `PEP CLI ${VERSION}
1371
1432
 
@@ -1380,7 +1441,7 @@ Usage:
1380
1441
  pep skills remove <repo>
1381
1442
  pep docs list [--docs-url <url>]
1382
1443
  pep docs get <path> [--docs-url <url>]
1383
- pep nexus setup
1444
+ pep nexus setup [--print-env]
1384
1445
 
1385
1446
  The issuer is built into this executable. --issuer overrides it for that one command and is
1386
1447
  NOT remembered \u2014 pass it every time you log in against a non-default deployment.
@@ -1441,15 +1502,20 @@ hand is left alone.
1441
1502
  straight to \`pep docs get\` to print that document as markdown on stdout. The documentation
1442
1503
  site is built in (${DEFAULT_DOCS_URL}); --docs-url overrides it and is then remembered.
1443
1504
 
1444
- \`pep nexus setup\` asks PEP for this organisation's Maven repository credential and saves it as
1445
- the two environment variables the Newland Android SDK reads \u2014 \`${USERNAME_VAR}\` and
1446
- \`${PASSWORD_VAR}\` \u2014 so you do not copy anything by hand. On Windows it writes them to your user
1447
- environment (\`setx\`); on macOS it keeps a marked block in your shell profile, backing the file up
1448
- first and touching nothing else. Either way persistence only affects NEW shells, so the two lines
1449
- are also printed on stdout: \`eval "$(pep nexus setup)"\` uses them in the current one.
1450
- Only Android needs this \u2014 the Windows and iOS SDKs are cloned from Git, not pulled from Maven.
1451
- The password is shown by PEP once and never stored, so a second run reports 409 rather than
1452
- handing it out again.`;
1505
+ \`pep nexus setup\` asks PEP for your Maven repository credential and saves it as the two
1506
+ environment variables the Newland Android SDK reads \u2014 \`${USERNAME_VAR}\` and \`${PASSWORD_VAR}\`
1507
+ \u2014 so you do not copy anything by hand. On Windows it writes them to your user environment
1508
+ (\`setx\`); on macOS it keeps a marked block in your shell profile, backing the file up first and
1509
+ touching nothing else. Either way persistence only affects NEW shells.
1510
+
1511
+ **The password is never printed.** The credential is derived from who you are, so running this
1512
+ again \u2014 on this machine or any other \u2014 hands you the same one. Nothing is lost by not showing it.
1513
+ \`--print-env\` writes the two lines to stdout instead, for
1514
+ \`eval "$(pep nexus setup --print-env)"\` when you want the shell you are in to have them now.
1515
+
1516
+ The credential is per person, not per company: your colleagues get their own, and so does the same
1517
+ account on a second machine. Only Android needs this \u2014 the Windows and iOS SDKs are cloned from
1518
+ Git, not pulled from Maven.`;
1453
1519
  }
1454
1520
  function reportUpdate(result) {
1455
1521
  const conflicts = () => {
@@ -1561,6 +1627,33 @@ function targetForSource(chosen, recorded) {
1561
1627
  ...recorded.linkedInto !== void 0 ? { linkInto: recorded.linkedInto } : {}
1562
1628
  };
1563
1629
  }
1630
+ function nexusReport(result, printEnv) {
1631
+ const stdout = printEnv ? [result.lines] : [];
1632
+ const stderr = [];
1633
+ const persisted = result.persisted;
1634
+ if (persisted.status === "windows") {
1635
+ stderr.push(`Saved ${USERNAME_VAR} and ${PASSWORD_VAR} to your Windows user environment.`);
1636
+ stderr.push("Existing terminals do not see them \u2014 open a new one.");
1637
+ stderr.push("Android Studio / IntelliJ must be fully quit and reopened \u2014 its built-in");
1638
+ stderr.push("terminal inherits the old environment too.");
1639
+ stderr.push("Then stop the Gradle daemon, which outlives the IDE: `gradlew --stop`.");
1640
+ } else if (persisted.status === "manual") {
1641
+ stderr.push(
1642
+ `Nothing was written${persisted.path ? ` to ${persisted.path}` : ""}: ${persisted.reason}`
1643
+ );
1644
+ stderr.push("Run this again to get the same credential \u2014 it is derived, not stored.");
1645
+ } else {
1646
+ stderr.push(
1647
+ persisted.status === "profile-replaced" ? `Replaced the pep-cli block in ${persisted.path}` : `Appended a pep-cli block to ${persisted.path}`
1648
+ );
1649
+ if (persisted.backupPath) stderr.push(`Backup: ${persisted.backupPath}`);
1650
+ stderr.push("New shells will have it; this one will not until you re-source the profile.");
1651
+ stderr.push("Android Studio / IntelliJ must be fully quit and reopened, then");
1652
+ stderr.push("stop the Gradle daemon, which outlives it: `./gradlew --stop`.");
1653
+ }
1654
+ stderr.push(`Nexus user: ${result.username}`);
1655
+ return { stdout, stderr };
1656
+ }
1564
1657
  async function main() {
1565
1658
  const args = process.argv.slice(2);
1566
1659
  if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
@@ -1618,30 +1711,16 @@ ${usage()}`);
1618
1711
  if (command !== "setup") throw new Error(`Unknown nexus command.
1619
1712
 
1620
1713
  ${usage()}`);
1714
+ const printEnv = flag(args, "--print-env");
1621
1715
  if (args.length > 0) throw new Error(`Unknown option: ${args[0]}`);
1622
1716
  const authorization = await auth.currentAuthorization();
1623
1717
  const result = await setupNexusCredential({
1624
1718
  issuer: authorization.issuer,
1625
1719
  accessToken: authorization.accessToken
1626
1720
  });
1627
- console.log(result.lines);
1628
- const persisted = result.persisted;
1629
- if (persisted.status === "windows") {
1630
- console.error(`Saved ${USERNAME_VAR} and ${PASSWORD_VAR} to your Windows user environment.`);
1631
- console.error("Existing terminals do not see them \u2014 open a new one (or use the lines above).");
1632
- } else if (persisted.status === "manual") {
1633
- console.error(
1634
- `Nothing was written${persisted.path ? ` to ${persisted.path}` : ""}: ${persisted.reason}`
1635
- );
1636
- console.error("The two lines above are the only copy \u2014 PEP does not store the password.");
1637
- } else {
1638
- console.error(
1639
- persisted.status === "profile-replaced" ? `Replaced the pep-cli block in ${persisted.path}` : `Appended a pep-cli block to ${persisted.path}`
1640
- );
1641
- if (persisted.backupPath) console.error(`Backup: ${persisted.backupPath}`);
1642
- console.error("New shells will have it; this one will not until you re-source the profile.");
1643
- }
1644
- console.error(`Nexus user: ${result.username}`);
1721
+ const report = nexusReport(result, printEnv);
1722
+ for (const line of report.stdout) console.log(line);
1723
+ for (const line of report.stderr) console.error(line);
1645
1724
  return;
1646
1725
  }
1647
1726
  if (group === "skills") {
@@ -1723,7 +1802,10 @@ ${usage()}`);
1723
1802
  );
1724
1803
  }
1725
1804
  const wanted = named.length > 0 ? named : installed;
1726
- const targets = chosenTarget ? wanted.filter((one) => state?.packages[one]?.directory === chosenTarget.directory) : wanted;
1805
+ const targets = chosenTarget ? wanted.filter((one) => {
1806
+ const at = state?.packages[one]?.directory;
1807
+ return at !== void 0 && samePlace(at, chosenTarget.directory);
1808
+ }) : wanted;
1727
1809
  if (targets.length === 0) {
1728
1810
  console.error(`No skills are installed in ${chosenTarget?.directory}.`);
1729
1811
  console.error("`pep skills update` (no flag) refreshes every repository where it lives;");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newlandnpt/pep-cli",
3
- "version": "0.6.1",
3
+ "version": "0.8.0",
4
4
  "description": "PEP CLI —— 凭 PEP 身份读取 Newland 开发者文档与 agent skills",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -28,7 +28,7 @@
28
28
  "build:installer": "node scripts/build-installer.mjs production",
29
29
  "build:installer:dev": "node scripts/build-installer.mjs development",
30
30
  "build:installer:prod": "node scripts/build-installer.mjs production",
31
- "prepack": "node scripts/build-js.mjs development",
31
+ "prepack": "node scripts/build-js.mjs production",
32
32
  "build:exe:view": "node scripts/build-exe.mjs view",
33
33
  "build:installer:view": "node scripts/build-installer.mjs view"
34
34
  },