@highstate/cli 0.26.0 → 0.28.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.
@@ -4,12 +4,6 @@ import {
4
4
  int32ToBytes
5
5
  } from "./chunk-vcev74he.js";
6
6
 
7
- // src/commands/backend/identity.ts
8
- import { hostname } from "os";
9
- import { loadConfig } from "@highstate/backend";
10
- import { identityToRecipient } from "age-encryption";
11
- import { Command } from "clipanion";
12
-
13
7
  // src/shared/bin-transformer.ts
14
8
  import { readFile } from "fs/promises";
15
9
 
@@ -354,10 +348,29 @@ async function getProjectPlatformVersion(projectRoot) {
354
348
  packageName: "@highstate/pulumi"
355
349
  });
356
350
  }
351
+ async function getProjectPulumiSdkVersion(projectRoot) {
352
+ return await getProjectOverrideVersion(projectRoot, {
353
+ packageName: "@pulumi/pulumi"
354
+ });
355
+ }
357
356
  // src/shared/pulumi-cli.ts
358
357
  import { execFile } from "child_process";
359
358
  import { promisify } from "util";
360
359
  var execFileAsync = promisify(execFile);
360
+ async function getPulumiCliVersion(cwd, commandPath = "pulumi") {
361
+ try {
362
+ const { stdout } = await execFileAsync(commandPath, ["version"], {
363
+ cwd
364
+ });
365
+ const raw = stdout.trim();
366
+ if (raw.length === 0) {
367
+ return null;
368
+ }
369
+ return raw.startsWith("v") ? raw.slice(1) : raw;
370
+ } catch {
371
+ return null;
372
+ }
373
+ }
361
374
  // src/shared/schema-transformer.ts
362
375
  import { readFile as readFile4 } from "fs/promises";
363
376
  import MagicString from "magic-string";
@@ -569,7 +582,7 @@ function findFirstReturnArgument(node) {
569
582
  return null;
570
583
  }
571
584
  const body = node.value.body;
572
- if (!body || body.type !== "BlockStatement") {
585
+ if (body?.type !== "BlockStatement") {
573
586
  return null;
574
587
  }
575
588
  for (const statement of body.body) {
@@ -632,7 +645,7 @@ function getHelperFunctionForProperty(parentStack) {
632
645
  return null;
633
646
  }
634
647
  const objectExpression = parentStack[parentStack.length - 2];
635
- if (!objectExpression || objectExpression.type !== "ObjectExpression") {
648
+ if (objectExpression?.type !== "ObjectExpression") {
636
649
  return null;
637
650
  }
638
651
  const containerParent = parentStack[parentStack.length - 3];
@@ -698,7 +711,7 @@ function isZodObjectCall(memberExpression) {
698
711
  return false;
699
712
  }
700
713
  function startsWithZodCall(callExpression) {
701
- if (!callExpression || callExpression.type !== "CallExpression") {
714
+ if (callExpression?.type !== "CallExpression") {
702
715
  return false;
703
716
  }
704
717
  if (callExpression.callee.type === "MemberExpression") {
@@ -993,6 +1006,32 @@ class SourceHashCalculator {
993
1006
  }
994
1007
  }
995
1008
  }
1009
+ // src/shared/version.ts
1010
+ import { readFile as readFile6 } from "fs/promises";
1011
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join2 } from "path";
1012
+ import { fileURLToPath as fileURLToPath2 } from "url";
1013
+ async function readCurrentPackageVersion(moduleUrl) {
1014
+ let directory = dirname3(moduleUrl.startsWith("file:") ? fileURLToPath2(moduleUrl) : isAbsolute2(moduleUrl) ? moduleUrl : process.cwd());
1015
+ while (true) {
1016
+ const packageJsonPath = join2(directory, "package.json");
1017
+ try {
1018
+ const packageJson = JSON.parse(await readFile6(packageJsonPath, "utf8"));
1019
+ if (!packageJson.version) {
1020
+ throw new Error(`Package version is missing from "${packageJsonPath}"`);
1021
+ }
1022
+ return packageJson.version;
1023
+ } catch (error) {
1024
+ if (!(error instanceof Error) || !(("code" in error) && error.code === "ENOENT")) {
1025
+ throw error;
1026
+ }
1027
+ }
1028
+ const parentDirectory = dirname3(directory);
1029
+ if (parentDirectory === directory) {
1030
+ throw new Error(`Package manifest not found above "${directory}"`);
1031
+ }
1032
+ directory = parentDirectory;
1033
+ }
1034
+ }
996
1035
  // src/shared/version-bundle.ts
997
1036
  var platformSourcePackage = "@highstate/pulumi";
998
1037
  var stdlibSourcePackage = "@highstate/library";
@@ -1024,8 +1063,8 @@ function normalizeProvidedVersion(value, label) {
1024
1063
  }
1025
1064
  // src/shared/workspace.ts
1026
1065
  import { existsSync } from "fs";
1027
- import { mkdir as mkdir2, readdir as readdir2, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
1028
- import { join as join2, relative as relative3, resolve as resolve3 } from "path";
1066
+ import { mkdir as mkdir2, readdir as readdir2, readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
1067
+ import { join as join3, relative as relative3, resolve as resolve3 } from "path";
1029
1068
  import { z as z3 } from "zod";
1030
1069
  var packageJsonSchema = z3.object({
1031
1070
  name: z3.string(),
@@ -1043,10 +1082,10 @@ function generateTsconfigContent(workspaceRoot, packagePath) {
1043
1082
  async function findWorkspaceRoot(startPath = process.cwd()) {
1044
1083
  let currentPath = resolve3(startPath);
1045
1084
  while (currentPath !== "/") {
1046
- const packageJsonPath = join2(currentPath, "package.json");
1085
+ const packageJsonPath = join3(currentPath, "package.json");
1047
1086
  if (existsSync(packageJsonPath)) {
1048
1087
  try {
1049
- const content = await readFile6(packageJsonPath, "utf-8");
1088
+ const content = await readFile7(packageJsonPath, "utf-8");
1050
1089
  const packageJson = JSON.parse(content);
1051
1090
  if (packageJson.workspaces) {
1052
1091
  return currentPath;
@@ -1062,7 +1101,7 @@ async function findWorkspaceRoot(startPath = process.cwd()) {
1062
1101
  }
1063
1102
  async function scanWorkspacePackages(workspaceRoot) {
1064
1103
  const packages = [];
1065
- const packagesDir = join2(workspaceRoot, "packages");
1104
+ const packagesDir = join3(workspaceRoot, "packages");
1066
1105
  if (!existsSync(packagesDir)) {
1067
1106
  return packages;
1068
1107
  }
@@ -1075,14 +1114,14 @@ async function scanWorkspacePackages(workspaceRoot) {
1075
1114
  for (const entry of entries) {
1076
1115
  if (!entry.isDirectory())
1077
1116
  continue;
1078
- const entryPath = join2(dirPath, entry.name);
1117
+ const entryPath = join3(dirPath, entry.name);
1079
1118
  if (entry.name.startsWith(".") || entry.name === "node_modules") {
1080
1119
  continue;
1081
1120
  }
1082
- const packageJsonPath = join2(entryPath, "package.json");
1121
+ const packageJsonPath = join3(entryPath, "package.json");
1083
1122
  if (existsSync(packageJsonPath)) {
1084
1123
  try {
1085
- const content = await readFile6(packageJsonPath, "utf-8");
1124
+ const content = await readFile7(packageJsonPath, "utf-8");
1086
1125
  const packageJson = packageJsonSchema.parse(JSON.parse(content));
1087
1126
  const relativePath = relative3(workspaceRoot, entryPath);
1088
1127
  const type = packageJson.highstate?.type ?? "source";
@@ -1103,7 +1142,7 @@ async function scanWorkspacePackages(workspaceRoot) {
1103
1142
  return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
1104
1143
  }
1105
1144
  async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs = false) {
1106
- const tsconfigPath = join2(workspaceRoot, "tsconfig.json");
1145
+ const tsconfigPath = join3(workspaceRoot, "tsconfig.json");
1107
1146
  if (ensureTsconfigs) {
1108
1147
  await ensurePackageTsconfigs(workspaceRoot, packages.filter((pkg) => pkg.type !== undefined));
1109
1148
  }
@@ -1119,15 +1158,15 @@ async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs
1119
1158
  }
1120
1159
  async function ensurePackageTsconfigs(workspaceRoot, packages) {
1121
1160
  for (const pkg of packages) {
1122
- const tsconfigPath = join2(pkg.path, "tsconfig.json");
1161
+ const tsconfigPath = join3(pkg.path, "tsconfig.json");
1123
1162
  const tsconfigContent = generateTsconfigContent(workspaceRoot, pkg.path);
1124
1163
  await writeFile4(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
1125
1164
  `, "utf-8");
1126
1165
  }
1127
1166
  }
1128
1167
  async function createPackage(workspaceRoot, name, type) {
1129
- const packagePath = join2(workspaceRoot, "packages", name);
1130
- const srcPath = join2(packagePath, "src");
1168
+ const packagePath = join3(workspaceRoot, "packages", name);
1169
+ const srcPath = join3(packagePath, "src");
1131
1170
  await mkdir2(packagePath, { recursive: true });
1132
1171
  await mkdir2(srcPath, { recursive: true });
1133
1172
  const packageJson = {
@@ -1138,12 +1177,12 @@ async function createPackage(workspaceRoot, name, type) {
1138
1177
  type
1139
1178
  }
1140
1179
  };
1141
- await writeFile4(join2(packagePath, "package.json"), `${JSON.stringify(packageJson, null, 2)}
1180
+ await writeFile4(join3(packagePath, "package.json"), `${JSON.stringify(packageJson, null, 2)}
1142
1181
  `, "utf-8");
1143
1182
  const tsconfigContent = generateTsconfigContent(workspaceRoot, packagePath);
1144
- await writeFile4(join2(packagePath, "tsconfig.json"), `${JSON.stringify(tsconfigContent, null, 2)}
1183
+ await writeFile4(join3(packagePath, "tsconfig.json"), `${JSON.stringify(tsconfigContent, null, 2)}
1145
1184
  `, "utf-8");
1146
- await writeFile4(join2(srcPath, "index.ts"), `// ${name} package
1185
+ await writeFile4(join3(srcPath, "index.ts"), `// ${name} package
1147
1186
  `, "utf-8");
1148
1187
  return {
1149
1188
  path: packagePath,
@@ -1152,684 +1191,4 @@ async function createPackage(workspaceRoot, name, type) {
1152
1191
  type
1153
1192
  };
1154
1193
  }
1155
- // src/commands/backend/identity.ts
1156
- class BackendIdentityCommand extends Command {
1157
- static paths = [["backend", "identity"]];
1158
- static usage = Command.Usage({
1159
- category: "Backend",
1160
- description: "Ensures the backend identity is set up and returns the recipient."
1161
- });
1162
- async execute() {
1163
- const { getOrCreateBackendIdentity } = await import("@highstate/backend");
1164
- const config = await loadConfig();
1165
- const backendIdentity = await getOrCreateBackendIdentity(config, logger);
1166
- const recipient = await identityToRecipient(backendIdentity);
1167
- logger.info(`stored backend identity: "%s"`, recipient);
1168
- const suggestedTitle = hostname();
1169
- if (!suggestedTitle) {
1170
- logger.info(`run "highstate backend unlock-method add %s" on a trusted device`, recipient);
1171
- return;
1172
- }
1173
- logger.info(`run "highstate backend unlock-method add %s --title %s" on a trusted device`, recipient, suggestedTitle);
1174
- }
1175
- }
1176
- // src/commands/backend/unlock-method/add.ts
1177
- import { input } from "@inquirer/prompts";
1178
- import { Command as Command2, Option } from "clipanion";
1179
- class BackendUnlockMethodAddCommand extends Command2 {
1180
- static paths = [["backend", "unlock-method", "add"]];
1181
- static usage = Command2.Usage({
1182
- category: "Backend",
1183
- description: "Adds a new backend unlock method for the current workspace.",
1184
- examples: [["Add recipient", "highstate backend unlock-method add age1example --title Laptop"]]
1185
- });
1186
- recipient = Option.String();
1187
- title = Option.String("--title");
1188
- description = Option.String("--description");
1189
- async execute() {
1190
- let title = this.title;
1191
- if (!title) {
1192
- title = await input({
1193
- message: "Unlock Method Title",
1194
- default: "New Device",
1195
- validate: (value) => value.trim().length > 0 ? true : "Title is required"
1196
- });
1197
- }
1198
- let description = this.description;
1199
- if (description === undefined) {
1200
- description = await input({
1201
- message: "Description (optional)",
1202
- default: ""
1203
- });
1204
- }
1205
- const services3 = await getBackendServices();
1206
- try {
1207
- const result = await services3.backendUnlockService.addUnlockMethod({
1208
- recipient: this.recipient,
1209
- meta: description ? { title: title.trim(), description: description.trim() } : { title: title.trim() }
1210
- });
1211
- logger.info(`added backend unlock method "%s"`, result.id);
1212
- } finally {
1213
- await disposeServices();
1214
- }
1215
- process.exit(0);
1216
- }
1217
- }
1218
- // src/commands/backend/unlock-method/delete.ts
1219
- import { confirm } from "@inquirer/prompts";
1220
- import { Command as Command3, Option as Option2 } from "clipanion";
1221
- class BackendUnlockMethodDeleteCommand extends Command3 {
1222
- static paths = [["backend", "unlock-method", "delete"]];
1223
- static usage = Command3.Usage({
1224
- category: "Backend",
1225
- description: "Removes a backend unlock method by its identifier."
1226
- });
1227
- id = Option2.String();
1228
- force = Option2.Boolean("--force", false);
1229
- async execute() {
1230
- if (!this.force) {
1231
- const answer = await confirm({
1232
- message: `Delete backend unlock method ${this.id}?`,
1233
- default: false
1234
- });
1235
- if (!answer) {
1236
- logger.info("cancelled backend unlock method deletion");
1237
- return;
1238
- }
1239
- }
1240
- const services3 = await getBackendServices();
1241
- try {
1242
- await services3.backendUnlockService.deleteUnlockMethod(this.id);
1243
- logger.info(`deleted backend unlock method "%s"`, this.id);
1244
- } finally {
1245
- await disposeServices();
1246
- }
1247
- process.exit(0);
1248
- }
1249
- }
1250
- // src/commands/backend/unlock-method/list.ts
1251
- import { Command as Command4 } from "clipanion";
1252
- import { Table } from "console-table-printer";
1253
- class BackendUnlockMethodListCommand extends Command4 {
1254
- static paths = [["backend", "unlock-method", "list"]];
1255
- static usage = Command4.Usage({
1256
- category: "Backend",
1257
- description: "Lists backend unlock methods registered for the current workspace."
1258
- });
1259
- async execute() {
1260
- const services3 = await getBackendServices();
1261
- try {
1262
- const methods = await services3.backendUnlockService.listUnlockMethods();
1263
- if (methods.length === 0) {
1264
- logger.warn("no backend unlock methods configured");
1265
- return;
1266
- }
1267
- const table = new Table({
1268
- columns: [
1269
- { name: "title", title: "Title" },
1270
- { name: "id", title: "ID" },
1271
- { name: "recipient", title: "Recipient" },
1272
- { name: "description", title: "Description", maxLen: 30 }
1273
- ],
1274
- defaultColumnOptions: {
1275
- alignment: "left"
1276
- }
1277
- });
1278
- table.addRows(methods.map((method) => ({
1279
- title: method.meta.title,
1280
- id: method.id,
1281
- recipient: method.recipient,
1282
- description: method.meta.description ?? ""
1283
- })));
1284
- table.printTable();
1285
- } finally {
1286
- await disposeServices();
1287
- }
1288
- process.exit(0);
1289
- }
1290
- }
1291
- // src/commands/build.ts
1292
- import { chmod, readFile as readFile7, rm, writeFile as writeFile5 } from "fs/promises";
1293
- import { resolve as resolve4 } from "path";
1294
- import { encode } from "@msgpack/msgpack";
1295
- import { Command as Command5, Option as Option3 } from "clipanion";
1296
- import { readPackageJSON as readPackageJSON3, resolvePackageJSON as resolvePackageJSON4 } from "pkg-types";
1297
- function formatUnknownError(error) {
1298
- if (error instanceof Error) {
1299
- return error.stack ?? error.message;
1300
- }
1301
- if (typeof error === "string") {
1302
- return error;
1303
- }
1304
- try {
1305
- return JSON.stringify(error);
1306
- } catch {
1307
- return String(error);
1308
- }
1309
- }
1310
-
1311
- class BuildCommand extends Command5 {
1312
- static paths = [["build"]];
1313
- static usage = Command5.Usage({
1314
- category: "Builder",
1315
- description: "Builds the Highstate library or unit package."
1316
- });
1317
- library = Option3.Boolean("--library", false);
1318
- silent = Option3.Boolean("--silent", true);
1319
- noSourceHash = Option3.Boolean("--no-source-hash", false);
1320
- async execute() {
1321
- try {
1322
- await this.build();
1323
- } catch (error) {
1324
- if (error instanceof Error) {
1325
- throw error;
1326
- }
1327
- throw new Error(`Build failed with non-error rejection: ${formatUnknownError(error)}`);
1328
- }
1329
- }
1330
- async build() {
1331
- const packageJson = await readPackageJSON3();
1332
- const highstateConfig = highstateConfigSchema.parse(packageJson.highstate ?? {});
1333
- if (highstateConfig.type === "library") {
1334
- this.library = true;
1335
- }
1336
- if (highstateConfig.type === "worker") {
1337
- this.noSourceHash = true;
1338
- }
1339
- if (!packageJson.name) {
1340
- throw new Error("package.json must have a name field");
1341
- }
1342
- const entryPoints = extractEntryPoints(packageJson);
1343
- if (Object.keys(entryPoints).length === 0) {
1344
- return;
1345
- }
1346
- const bunPlugins = [];
1347
- const binSourceFilePaths = Object.values(entryPoints).filter((value) => value.isBin).map((value) => value.entryPoint.slice(2));
1348
- if (this.library) {
1349
- bunPlugins.push(schemaTransformerPlugin);
1350
- }
1351
- if (binSourceFilePaths.length > 0) {
1352
- bunPlugins.push(createBinTransformerPlugin(binSourceFilePaths));
1353
- }
1354
- await rm("dist", { recursive: true, force: true });
1355
- const bunEntryPoints = Object.values(entryPoints).map((value) => value.entryPoint);
1356
- const result = await Bun.build({
1357
- entrypoints: bunEntryPoints,
1358
- outdir: "dist",
1359
- root: "./src",
1360
- format: "esm",
1361
- target: "bun",
1362
- external: ["@pulumi/pulumi"],
1363
- packages: "external",
1364
- splitting: true,
1365
- plugins: bunPlugins
1366
- });
1367
- if (!result.success) {
1368
- for (const log of result.logs) {
1369
- logger.error(log.message);
1370
- }
1371
- throw new Error("build failed");
1372
- }
1373
- const binEntryPoints = Object.values(entryPoints).filter((value) => value.isBin);
1374
- for (const binEntryPoint of binEntryPoints) {
1375
- const binPath = resolve4(binEntryPoint.distPath);
1376
- const binContent = await readFile7(binPath, "utf8");
1377
- if (!binContent.startsWith(`#!/usr/bin/env bun
1378
- `)) {
1379
- await writeFile5(binPath, `#!/usr/bin/env bun
1380
- ${binContent}`, "utf8");
1381
- }
1382
- await chmod(binPath, 493);
1383
- }
1384
- const packageJsonPath = await resolvePackageJSON4();
1385
- const upToDatePackageJson = await readPackageJSON3();
1386
- if (!this.noSourceHash) {
1387
- const sourceHashCalculator = new SourceHashCalculator(packageJsonPath, upToDatePackageJson, logger);
1388
- const distPathToExportKey = new Map;
1389
- for (const value of Object.values(entryPoints)) {
1390
- distPathToExportKey.set(value.distPath, value.key);
1391
- }
1392
- await sourceHashCalculator.writeHighstateManifest("./dist", distPathToExportKey);
1393
- }
1394
- if (this.library) {
1395
- const { loadLibrary } = await import("./chunk-sxh2gdkm.js");
1396
- const fullModulePaths = Object.values(entryPoints).map((value) => resolve4(value.distPath));
1397
- logger.info("evaluating library components from modules: %s", fullModulePaths.join(", "));
1398
- const library = await loadLibrary(logger, fullModulePaths);
1399
- const libraryPath = resolve4("./dist", "highstate.library.msgpack");
1400
- await writeFile5(libraryPath, encode(library), "utf8");
1401
- }
1402
- logger.info("build completed successfully");
1403
- }
1404
- }
1405
- // src/commands/designer.ts
1406
- import { pathToFileURL as pathToFileURL2 } from "url";
1407
- import { Command as Command6, UsageError } from "clipanion";
1408
- import { consola as consola2 } from "consola";
1409
- import { colorize } from "consola/utils";
1410
- import { checkPort, getPort } from "get-port-please";
1411
- import { resolve as importMetaResolve2 } from "import-meta-resolve";
1412
- import { addDevDependency } from "nypm";
1413
- import { readPackageJSON as readPackageJSON4, resolvePackageJSON as resolvePackageJSON5 } from "pkg-types";
1414
- var shuttingDown = false;
1415
-
1416
- class DesignerCommand extends Command6 {
1417
- static paths = [["designer"]];
1418
- static usage = Command6.Usage({
1419
- category: "Designer",
1420
- description: "Starts the Highstate designer in the current project."
1421
- });
1422
- async execute() {
1423
- const packageJsonPath = await resolvePackageJSON5();
1424
- const packageJsonUrl = pathToFileURL2(packageJsonPath).toString();
1425
- const packageJson = await readPackageJSON4(packageJsonPath);
1426
- if (!packageJson.devDependencies?.["@highstate/cli"]) {
1427
- throw new UsageError(`This project is not a Highstate project.
1428
- @highstate/cli must be installed as a devDependency.`);
1429
- }
1430
- if (!packageJson.devDependencies?.["@highstate/designer"]) {
1431
- logger.info("Installing @highstate/designer...");
1432
- await addDevDependency(["@highstate/designer", "classic-level"]);
1433
- }
1434
- logger.info("starting highstate designer...");
1435
- await getBackendServices();
1436
- const oldConsoleLog = console.log;
1437
- const host = "127.0.0.1";
1438
- const configuredPort = process.env.HIGHSTATE_DESIGNER_PORT;
1439
- const port = configuredPort === undefined ? 7283 : Number(configuredPort);
1440
- if (!/^\d+$/.test(configuredPort ?? port.toString()) || port < 1 || port > 65535) {
1441
- throw new UsageError(`HIGHSTATE_DESIGNER_PORT must be an integer between "1" and "65535"`);
1442
- }
1443
- if (configuredPort !== undefined) {
1444
- logger.warn(`using custom designer port "%s"; changing the port changes the WebAuthn origin and may require registering security keys again`, port);
1445
- }
1446
- const availablePort = await checkPort(port, host);
1447
- if (!availablePort) {
1448
- throw new UsageError(`Port "${port}" is already in use`);
1449
- }
1450
- const eventsPort = await getPort({ random: true, host });
1451
- const designerPackageJsonPath = importMetaResolve2("@highstate/designer/package.json", packageJsonUrl);
1452
- const designerPackageJson = await readPackageJSON4(designerPackageJsonPath);
1453
- process.env.NITRO_PORT = port.toString();
1454
- process.env.NITRO_HOST = host;
1455
- process.env.NITRO_BUN_IDLE_TIMEOUT ??= "255";
1456
- process.env.NUXT_PUBLIC_VERSION = designerPackageJson.version;
1457
- process.env.NUXT_PUBLIC_EVENTS_PORT = eventsPort.toString();
1458
- try {
1459
- await new Promise((resolve5, reject) => {
1460
- console.log = (message) => {
1461
- if (message.startsWith("Listening on")) {
1462
- if (!message.includes(`http://${host}:${port}`)) {
1463
- reject(new Error(`Designer started on an unexpected endpoint: ${message}`));
1464
- return;
1465
- }
1466
- resolve5();
1467
- }
1468
- };
1469
- const serverPath = importMetaResolve2("@highstate/designer/server", packageJsonUrl);
1470
- import(serverPath).catch(reject);
1471
- });
1472
- } finally {
1473
- console.log = oldConsoleLog;
1474
- }
1475
- consola2.log([
1476
- `
1477
- `,
1478
- colorize("bold", colorize("cyanBright", "Highstate Designer")),
1479
- `
1480
- `,
1481
- colorize("greenBright", "\u279C Local: "),
1482
- colorize("underline", colorize("cyanBright", `http://highstate.localhost:${port}`)),
1483
- `
1484
- `
1485
- ].join(""));
1486
- process.once("SIGINT", () => {
1487
- if (shuttingDown) {
1488
- return;
1489
- }
1490
- shuttingDown = true;
1491
- process.stdout.write("\r");
1492
- consola2.info("shutting down highstate designer...");
1493
- setTimeout(() => process.exit(0), 1000);
1494
- });
1495
- }
1496
- }
1497
- // src/commands/init.ts
1498
- import { access, mkdir as mkdir3, readdir as readdir3 } from "fs/promises";
1499
- import { resolve as resolve5 } from "path";
1500
- import { fileURLToPath as fileURLToPath2 } from "url";
1501
- import { input as input2 } from "@inquirer/prompts";
1502
- import { Command as Command7, Option as Option4 } from "clipanion";
1503
- import { installDependencies } from "nypm";
1504
- class InitCommand extends Command7 {
1505
- static paths = [["init"]];
1506
- static usage = Command7.Usage({
1507
- description: "Initializes a new Highstate project."
1508
- });
1509
- pathOption = Option4.String("--path,-p", {
1510
- description: "The path where the project should be initialized."
1511
- });
1512
- name = Option4.String("--name", {
1513
- description: "The project name."
1514
- });
1515
- platformVersion = Option4.String("--platform-version", {
1516
- description: "The Highstate platform version to use."
1517
- });
1518
- stdlibVersion = Option4.String("--stdlib-version", {
1519
- description: "The Highstate standard library version to use."
1520
- });
1521
- async execute() {
1522
- const isBunAvailable = await isExecutableInPath("bun");
1523
- if (!isBunAvailable) {
1524
- throw new Error('Required package manager "bun" was not found in PATH');
1525
- }
1526
- const projectName = await resolveProjectName(this.name);
1527
- const destinationPath = await resolveDestinationPath(this.pathOption, projectName);
1528
- const templatePath = resolveTemplatePath();
1529
- const versionBundle = await resolveVersionBundle({
1530
- platformVersion: this.platformVersion,
1531
- stdlibVersion: this.stdlibVersion
1532
- });
1533
- await mkdir3(destinationPath, { recursive: true });
1534
- const isEmptyOrMissing = await isEmptyDirectory(destinationPath);
1535
- if (!isEmptyOrMissing) {
1536
- throw new Error(`Destination path is not empty: "${destinationPath}"`);
1537
- }
1538
- logger.info("initializing highstate project in %s", destinationPath);
1539
- await generateFromTemplate(templatePath, destinationPath, {
1540
- projectName,
1541
- packageName: projectName,
1542
- platformVersion: versionBundle.platformVersion,
1543
- libraryVersion: versionBundle.stdlibVersion
1544
- });
1545
- const overrides2 = buildOverrides(versionBundle);
1546
- await applyOverrides({
1547
- projectRoot: destinationPath,
1548
- overrides: overrides2
1549
- });
1550
- logger.info("installing dependencies using bun...");
1551
- await installDependencies({
1552
- cwd: destinationPath,
1553
- packageManager: "bun",
1554
- silent: false
1555
- });
1556
- logger.info("project initialized successfully");
1557
- }
1558
- }
1559
- async function resolveDestinationPath(pathOption, projectName) {
1560
- if (pathOption) {
1561
- return resolve5(pathOption);
1562
- }
1563
- const defaultPath = resolve5(process.cwd(), projectName);
1564
- const pathValue = await input2({
1565
- message: "Project path",
1566
- default: defaultPath,
1567
- validate: (value) => value.trim().length > 0 ? true : "Path is required"
1568
- });
1569
- return resolve5(pathValue);
1570
- }
1571
- async function resolveProjectName(nameOption) {
1572
- if (nameOption !== undefined) {
1573
- const trimmed = nameOption.trim();
1574
- if (trimmed.length === 0) {
1575
- throw new Error('Flag "--name" must not be empty');
1576
- }
1577
- return trimmed;
1578
- }
1579
- const value = await input2({
1580
- message: "Project name",
1581
- default: "my-project",
1582
- validate: (inputValue) => inputValue.trim().length > 0 ? true : "Name is required"
1583
- });
1584
- return value.trim();
1585
- }
1586
- async function isExecutableInPath(command) {
1587
- const pathValue = process.env.PATH;
1588
- if (!pathValue) {
1589
- return false;
1590
- }
1591
- const parts = pathValue.split(":").filter(Boolean);
1592
- for (const part of parts) {
1593
- const candidate = resolve5(part, command);
1594
- try {
1595
- await access(candidate);
1596
- return true;
1597
- } catch {}
1598
- }
1599
- return false;
1600
- }
1601
- async function isEmptyDirectory(path) {
1602
- try {
1603
- const entries = await readdir3(path);
1604
- return entries.length === 0;
1605
- } catch {
1606
- return true;
1607
- }
1608
- }
1609
- function resolveTemplatePath() {
1610
- const here = fileURLToPath2(new URL(import.meta.url));
1611
- return resolve5(here, "..", "..", "assets", "template");
1612
- }
1613
- // src/commands/package/create.ts
1614
- import { Command as Command8, Option as Option5 } from "clipanion";
1615
- class PackageCreateCommand extends Command8 {
1616
- static paths = [["package", "create"]];
1617
- static usage = Command8.Usage({
1618
- category: "Package",
1619
- description: "Creates a new package in the workspace."
1620
- });
1621
- name = Option5.String({ required: true });
1622
- type = Option5.String("--type,-t", {
1623
- description: "Package type (source, library, worker)"
1624
- });
1625
- async execute() {
1626
- const workspaceRoot = await findWorkspaceRoot();
1627
- const packageType = highstateConfigSchema.shape.type.parse(this.type);
1628
- await createPackage(workspaceRoot, this.name, packageType);
1629
- const packages = await scanWorkspacePackages(workspaceRoot);
1630
- await updateTsconfigReferences(workspaceRoot, packages);
1631
- logger.info(`created package: @highstate/${this.name} (${packageType})`);
1632
- }
1633
- }
1634
- // src/commands/package/list.ts
1635
- import { Command as Command9 } from "clipanion";
1636
- import { Table as Table2 } from "console-table-printer";
1637
- class PackageListCommand extends Command9 {
1638
- static paths = [["package", "list"]];
1639
- static usage = Command9.Usage({
1640
- category: "Package",
1641
- description: "Lists all packages in the workspace with their types."
1642
- });
1643
- async execute() {
1644
- const workspaceRoot = await findWorkspaceRoot();
1645
- const packages = await scanWorkspacePackages(workspaceRoot);
1646
- if (packages.length === 0) {
1647
- logger.info("no packages found in workspace");
1648
- return;
1649
- }
1650
- const table = new Table2({
1651
- columns: [
1652
- { name: "name", title: "Name" },
1653
- { name: "type", title: "Type" },
1654
- { name: "path", title: "Path" }
1655
- ]
1656
- });
1657
- table.addRows(packages.map((pkg) => ({
1658
- name: pkg.name,
1659
- type: pkg.type ?? "unknown",
1660
- path: pkg.relativePath
1661
- })));
1662
- table.printTable();
1663
- }
1664
- }
1665
- // src/commands/package/remove.ts
1666
- import { rm as rm2 } from "fs/promises";
1667
- import { Command as Command10, Option as Option6 } from "clipanion";
1668
- class PackageRemoveCommand extends Command10 {
1669
- static paths = [["package", "remove"]];
1670
- static usage = Command10.Usage({
1671
- category: "Package",
1672
- description: "Removes a package from the workspace."
1673
- });
1674
- name = Option6.String({ required: true });
1675
- async execute() {
1676
- const workspaceRoot = await findWorkspaceRoot();
1677
- const packages = await scanWorkspacePackages(workspaceRoot);
1678
- const targetPackage = packages.find((pkg) => pkg.name === this.name || pkg.name === `@highstate/${this.name}` || pkg.relativePath.endsWith(this.name));
1679
- if (!targetPackage) {
1680
- logger.error(`package not found: ${this.name}`);
1681
- process.exit(1);
1682
- }
1683
- await rm2(targetPackage.path, { recursive: true, force: true });
1684
- const remainingPackages = await scanWorkspacePackages(workspaceRoot);
1685
- await updateTsconfigReferences(workspaceRoot, remainingPackages);
1686
- logger.info(`removed package: ${targetPackage.name}`);
1687
- }
1688
- }
1689
- // src/commands/package/update-references.ts
1690
- import { Command as Command11 } from "clipanion";
1691
- class PackageUpdateReferencesCommand extends Command11 {
1692
- static paths = [["package", "update-references"]];
1693
- static usage = Command11.Usage({
1694
- category: "Package",
1695
- description: "Updates the root tsconfig.json with references to all packages in the workspace."
1696
- });
1697
- async execute() {
1698
- const workspaceRoot = await findWorkspaceRoot();
1699
- const packages = await scanWorkspacePackages(workspaceRoot);
1700
- await updateTsconfigReferences(workspaceRoot, packages, true);
1701
- }
1702
- }
1703
- // src/commands/update.ts
1704
- import { readFile as readFile8 } from "fs/promises";
1705
- import { Command as Command12, Option as Option7 } from "clipanion";
1706
- import { readPackageJSON as readPackageJSON5, resolvePackageJSON as resolvePackageJSON6 } from "pkg-types";
1707
- import semver from "semver";
1708
- class UpdateCommand extends Command12 {
1709
- static paths = [["update"]];
1710
- static usage = Command12.Usage({
1711
- description: "Updates version overrides in an existing Highstate project."
1712
- });
1713
- platformVersion = Option7.String("--platform-version", {
1714
- description: "The Highstate platform version to set."
1715
- });
1716
- stdlibVersion = Option7.String("--stdlib-version", {
1717
- description: "The Highstate standard library version to set."
1718
- });
1719
- platformOnly = Option7.Boolean("--platform", false, {
1720
- description: "Update only platform versions."
1721
- });
1722
- stdlibOnly = Option7.Boolean("--stdlib", false, {
1723
- description: "Update only standard library versions."
1724
- });
1725
- install = Option7.Boolean("--install", true, {
1726
- description: "Install dependencies after updating overrides."
1727
- });
1728
- async execute() {
1729
- const projectRoot = process.cwd();
1730
- await assertPackageJsonExists(projectRoot);
1731
- if (this.platformOnly && this.stdlibOnly) {
1732
- throw new Error('Flags "--platform" and "--stdlib" cannot be used together');
1733
- }
1734
- const updatePlatform = this.platformOnly || !this.stdlibOnly;
1735
- const updateStdlib = this.stdlibOnly || !this.platformOnly;
1736
- let currentPlatformVersion;
1737
- let resolvedStdlibVersion = this.stdlibVersion;
1738
- if (this.stdlibOnly) {
1739
- const projectPlatformVersion = await getProjectPlatformVersion(projectRoot);
1740
- if (!projectPlatformVersion) {
1741
- throw new Error('Current platform version is not set in overrides for "@highstate/pulumi"');
1742
- }
1743
- currentPlatformVersion = projectPlatformVersion;
1744
- resolvedStdlibVersion = await resolveCompatibleStdlibVersion({
1745
- currentPlatformVersion: projectPlatformVersion,
1746
- stdlibVersion: this.stdlibVersion
1747
- });
1748
- }
1749
- const bundle = await resolveVersionBundle({
1750
- platformVersion: updatePlatform ? this.platformVersion : currentPlatformVersion,
1751
- stdlibVersion: updateStdlib ? resolvedStdlibVersion : undefined
1752
- });
1753
- const overrides2 = buildOverrides(bundle);
1754
- await applyOverrides({
1755
- projectRoot,
1756
- overrides: overrides2
1757
- });
1758
- await syncRootPulumiDependency({
1759
- projectRoot,
1760
- pulumiVersion: bundle.pulumiVersion
1761
- });
1762
- logger.info("updated overrides: platform=%s stdlib=%s pulumi=%s", bundle.platformVersion, bundle.stdlibVersion, bundle.pulumiVersion);
1763
- if (this.install) {
1764
- const { installDependencies: installDependencies2 } = await import("nypm");
1765
- logger.info("installing dependencies using bun...");
1766
- await installDependencies2({
1767
- cwd: projectRoot,
1768
- packageManager: "bun",
1769
- silent: false
1770
- });
1771
- }
1772
- logger.info("update completed successfully");
1773
- }
1774
- }
1775
- async function resolveCompatibleStdlibVersion(args) {
1776
- const validPlatform = semver.valid(args.currentPlatformVersion);
1777
- if (!validPlatform) {
1778
- throw new Error(`Current platform version is not a valid semver "${args.currentPlatformVersion}"`);
1779
- }
1780
- const targetStdlibVersion = args.stdlibVersion?.trim();
1781
- if (targetStdlibVersion) {
1782
- await assertStdlibSupportsPlatform({
1783
- currentPlatformVersion: validPlatform,
1784
- stdlibVersion: targetStdlibVersion
1785
- });
1786
- return targetStdlibVersion;
1787
- }
1788
- const packument = await fetchNpmPackument("@highstate/library");
1789
- const sortedVersions = Object.entries(packument.versions ?? {}).filter(([version]) => semver.valid(version)).sort(([a], [b]) => semver.rcompare(a, b));
1790
- for (const [stdlibVersion, stdlibManifest] of sortedVersions) {
1791
- const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi");
1792
- if (!supportedPlatformRange) {
1793
- continue;
1794
- }
1795
- const ok = semver.satisfies(validPlatform, supportedPlatformRange, {
1796
- includePrerelease: true
1797
- });
1798
- if (ok) {
1799
- return stdlibVersion;
1800
- }
1801
- }
1802
- throw new Error(`Unable to find "@highstate/library" version compatible with platform "${validPlatform}"`);
1803
- }
1804
- async function assertStdlibSupportsPlatform(args) {
1805
- const stdlibManifest = await fetchManifest("@highstate/library", args.stdlibVersion);
1806
- const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi");
1807
- if (!supportedPlatformRange) {
1808
- throw new Error(`Unable to infer "@highstate/pulumi" version from "@highstate/library@${args.stdlibVersion}"`);
1809
- }
1810
- const ok = semver.satisfies(args.currentPlatformVersion, supportedPlatformRange, {
1811
- includePrerelease: true
1812
- });
1813
- if (!ok) {
1814
- throw new Error(`Current platform version "${args.currentPlatformVersion}" does not satisfy requirement "${supportedPlatformRange}"`);
1815
- }
1816
- }
1817
- async function assertPackageJsonExists(projectRoot) {
1818
- try {
1819
- await readFile8(`${projectRoot}/package.json`, "utf8");
1820
- } catch {
1821
- throw new Error(`File "package.json" not found in "${projectRoot}"`);
1822
- }
1823
- }
1824
- async function syncRootPulumiDependency(args) {
1825
- const packageJsonPath = await resolvePackageJSON6(args.projectRoot);
1826
- const packageJson = await readPackageJSON5(packageJsonPath);
1827
- await writeJsonFile(packageJsonPath, {
1828
- ...packageJson,
1829
- dependencies: {
1830
- ...packageJson.dependencies ?? {},
1831
- "@pulumi/pulumi": args.pulumiVersion
1832
- }
1833
- });
1834
- }
1835
- export { BackendIdentityCommand, BackendUnlockMethodAddCommand, BackendUnlockMethodDeleteCommand, BackendUnlockMethodListCommand, BuildCommand, DesignerCommand, InitCommand, PackageCreateCommand, PackageListCommand, PackageRemoveCommand, PackageUpdateReferencesCommand, UpdateCommand };
1194
+ export { logger, createBinTransformerPlugin, extractEntryPoints, generateFromTemplate, fetchNpmPackument, fetchLatestVersion, fetchManifest, getDependencyRange, writeJsonFile, PLATFORM_PACKAGES, STDLIB_PACKAGES, PULUMI_PACKAGES, buildOverrides, applyOverrides, getProjectOverrideVersion, getProjectPlatformVersion, getProjectPulumiSdkVersion, getPulumiCliVersion, schemaTransformerPlugin, applySchemaTransformations, sourceHashConfigSchema, highstateConfigSchema, highstateManifestSchema, getBackendServices, disposeServices, parseFileDependencies, SourceHashCalculator, readCurrentPackageVersion, resolveVersionBundle, findWorkspaceRoot, scanWorkspacePackages, updateTsconfigReferences, createPackage };