@highstate/cli 0.9.18 → 0.9.20

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/main.js CHANGED
@@ -8,22 +8,23 @@ import { colorize } from 'consola/utils';
8
8
  import { getPort } from 'get-port-please';
9
9
  import { PassThrough } from 'node:stream';
10
10
  import pino, { levels } from 'pino';
11
- import { writeFile, readFile } from 'node:fs/promises';
11
+ import { writeFile, rm, readFile, mkdir, readdir } from 'node:fs/promises';
12
12
  import { parseAsync } from 'oxc-parser';
13
13
  import { walk } from 'oxc-walker';
14
14
  import MagicString from 'magic-string';
15
- import { resolve, dirname, relative } from 'node:path';
15
+ import { resolve, dirname, relative, join } from 'node:path';
16
16
  import { pathToFileURL, fileURLToPath } from 'node:url';
17
17
  import { crc32 } from '@aws-crypto/crc32';
18
18
  import { resolve as resolve$1 } from 'import-meta-resolve';
19
19
  import { z } from 'zod';
20
+ import { existsSync } from 'node:fs';
20
21
  import { pipe, mapValues, mapKeys } from 'remeda';
21
22
  import { build } from 'tsup';
22
23
  import { encode } from '@msgpack/msgpack';
23
24
  import { identityToRecipient } from 'age-encryption';
24
25
 
25
26
  // package.json
26
- var version = "0.9.17";
27
+ var version = "0.9.19";
27
28
  var logger = pino(
28
29
  {
29
30
  name: "highstate-cli",
@@ -93,192 +94,164 @@ var schemaTransformerPlugin = {
93
94
  }
94
95
  };
95
96
  async function applySchemaTransformations(content) {
97
+ let result = await applyZodMetaTransformations(content);
98
+ result = await applyHelperFunctionTransformations(result);
99
+ result = await applyDefineFunctionMetaTransformations(result);
100
+ return result;
101
+ }
102
+ async function applyZodMetaTransformations(content) {
96
103
  const { program, comments } = await parseAsync("file.ts", content);
97
- const transformations = [];
98
104
  const parentStack = [];
105
+ let hasTransformations = false;
106
+ const result = new MagicString(content);
99
107
  walk(program, {
100
108
  enter(node) {
101
109
  parentStack.push(node);
102
- if (node.type === "Property" && node.key.type === "Identifier" && isInsideZodObject(parentStack)) {
103
- const jsdoc2 = comments.find((comment) => isLeadingComment(content, node, comment));
104
- if (jsdoc2) {
105
- const description2 = cleanJsdoc(jsdoc2.value);
106
- const fieldName = node.key.name;
107
- const originalValue2 = content.substring(node.value.start, node.value.end);
108
- if (!originalValue2.includes(".meta(")) {
109
- transformations.push({
110
- start: node.value.start,
111
- end: node.value.end,
112
- newValue: `${originalValue2}.meta({ title: __camelCaseToHumanReadable("${fieldName}"), description: \`${description2}\` })`,
113
- type: "zod-meta"
114
- });
110
+ if (isZodObjectProperty(node, parentStack)) {
111
+ const jsdoc = findLeadingComment(content, node, comments);
112
+ if (jsdoc) {
113
+ const description = cleanJsdoc(jsdoc.value);
114
+ const fieldName = "name" in node.key && typeof node.key.name === "string" ? node.key.name : "unknown";
115
+ const originalValue = content.substring(node.value.start, node.value.end);
116
+ if (!originalValue.includes(".meta(")) {
117
+ const newValue = `${originalValue}.meta({ title: __camelCaseToHumanReadable("${fieldName}"), description: \`${description}\` })`;
118
+ result.update(node.value.start, node.value.end, newValue);
119
+ hasTransformations = true;
115
120
  }
116
121
  }
117
- return;
118
- }
119
- if (node.type !== "Property" || node.key.type !== "Identifier") {
120
- return;
121
- }
122
- const parentKey = getParentObjectKey(parentStack) || getMarkerFunctionName(parentStack);
123
- if (!parentKey || !["inputs", "outputs", "args", "secrets"].includes(parentKey)) {
124
- return;
125
- }
126
- const jsdoc = comments.find((comment) => isLeadingComment(content, node, comment));
127
- if (!jsdoc) {
128
- return;
129
- }
130
- const description = cleanJsdoc(jsdoc.value);
131
- const originalValue = content.substring(node.value.start, node.value.end);
132
- const entityField = ["inputs", "outputs"].includes(parentKey) ? "entity" : "schema";
133
- const isAlreadyStructured = isStructuredValue(originalValue, entityField);
134
- if (isAlreadyStructured) {
135
- const modifiedValue = injectDescriptionIntoObject(originalValue, description);
136
- transformations.push({
137
- start: node.value.start,
138
- end: node.value.end,
139
- newValue: modifiedValue,
140
- type: "schema-structure"
141
- });
142
- } else {
143
- transformations.push({
144
- start: node.value.start,
145
- end: node.value.end,
146
- newValue: `{
147
- ${entityField}: ${originalValue},
148
- meta: {
149
- description: \`${description}\`,
150
- },
151
- }`,
152
- type: "schema-structure"
153
- });
154
122
  }
155
123
  },
156
124
  leave() {
157
125
  parentStack.pop();
158
126
  }
159
127
  });
160
- const zodMetaTransformations = transformations.filter((t) => t.type === "zod-meta");
161
- const schemaTransformations = transformations.filter((t) => t.type === "schema-structure");
162
- const processedSchemaTransformations = schemaTransformations.map((schemaTransform) => {
163
- const containedZodMetas = zodMetaTransformations.filter((zodTransform) => {
164
- return schemaTransform.start <= zodTransform.start && schemaTransform.end >= zodTransform.end;
165
- });
166
- if (containedZodMetas.length > 0) {
167
- const originalContent = content.substring(schemaTransform.start, schemaTransform.end);
168
- const tempMagicString = new MagicString(originalContent);
169
- containedZodMetas.sort((a, b) => b.start - a.start).forEach((zodTransform) => {
170
- const relativeStart = zodTransform.start - schemaTransform.start;
171
- const relativeEnd = zodTransform.end - schemaTransform.start;
172
- tempMagicString.update(relativeStart, relativeEnd, zodTransform.newValue);
173
- });
174
- const modifiedContent = tempMagicString.toString();
175
- const entityField = schemaTransform.newValue.includes("entity:") ? "entity" : "schema";
176
- const descriptionMatch = schemaTransform.newValue.match(/description: `([^`]+)`/);
177
- if (descriptionMatch) {
178
- const description = descriptionMatch[1];
179
- const isAlreadyStructured = isStructuredValue(
180
- content.substring(schemaTransform.start, schemaTransform.end),
181
- entityField
182
- );
183
- if (isAlreadyStructured) {
184
- return {
185
- ...schemaTransform,
186
- newValue: injectDescriptionIntoObject(modifiedContent, description),
187
- containsZodMeta: true
188
- };
189
- } else {
190
- return {
191
- ...schemaTransform,
192
- newValue: `{
193
- ${entityField}: ${modifiedContent},
194
- meta: {
195
- description: \`${description}\`,
196
- },
197
- }`,
198
- containsZodMeta: true
199
- };
128
+ let finalResult = result.toString();
129
+ if (hasTransformations && !content.includes("__camelCaseToHumanReadable")) {
130
+ finalResult = 'import { camelCaseToHumanReadable as __camelCaseToHumanReadable } from "@highstate/contract"\n' + finalResult;
131
+ }
132
+ return finalResult;
133
+ }
134
+ async function applyHelperFunctionTransformations(content) {
135
+ const { program, comments } = await parseAsync("file.ts", content);
136
+ const parentStack = [];
137
+ let hasTransformations = false;
138
+ const result = new MagicString(content);
139
+ walk(program, {
140
+ enter(node) {
141
+ parentStack.push(node);
142
+ if (node.type === "Property" && "key" in node && node.key?.type === "Identifier") {
143
+ const propertyNode = node;
144
+ const parentKey = getParentObjectKey(parentStack);
145
+ if (parentKey && ["inputs", "outputs", "args", "secrets"].includes(parentKey)) {
146
+ const jsdoc = findLeadingComment(content, node, comments);
147
+ if (jsdoc) {
148
+ const description = cleanJsdoc(jsdoc.value);
149
+ const originalValue = content.substring(
150
+ propertyNode.value.start,
151
+ propertyNode.value.end
152
+ );
153
+ let helperFunction;
154
+ if (["args", "secrets"].includes(parentKey)) {
155
+ helperFunction = "$addArgumentDescription";
156
+ } else {
157
+ helperFunction = "$addInputDescription";
158
+ }
159
+ const newValue = `${helperFunction}(${originalValue}, \`${description}\`)`;
160
+ result.update(propertyNode.value.start, propertyNode.value.end, newValue);
161
+ hasTransformations = true;
162
+ }
200
163
  }
201
164
  }
165
+ },
166
+ leave() {
167
+ parentStack.pop();
202
168
  }
203
- return { ...schemaTransform, containsZodMeta: false };
204
- });
205
- const independentZodMetas = zodMetaTransformations.filter((zodTransform) => {
206
- return !schemaTransformations.some((schemaTransform) => {
207
- return schemaTransform.start <= zodTransform.start && schemaTransform.end >= zodTransform.end;
208
- });
209
- });
210
- const finalTransformations = [
211
- ...independentZodMetas,
212
- ...processedSchemaTransformations.map(({ containsZodMeta, ...rest }) => rest)
213
- // eslint-disable-line @typescript-eslint/no-unused-vars
214
- ];
215
- const hasZodMetaTransformations = zodMetaTransformations.length > 0;
216
- const needsImport = hasZodMetaTransformations && !content.includes("__camelCaseToHumanReadable");
217
- let result = content;
218
- const magicString = new MagicString(result);
219
- finalTransformations.sort((a, b) => b.start - a.start).forEach((transformation) => {
220
- magicString.update(transformation.start, transformation.end, transformation.newValue);
221
169
  });
222
- result = magicString.toString();
223
- if (needsImport) {
224
- result = 'import { camelCaseToHumanReadable as __camelCaseToHumanReadable } from "@highstate/contract"\n' + result;
170
+ let finalResult = result.toString();
171
+ if (hasTransformations && !content.includes("$addArgumentDescription")) {
172
+ finalResult = 'import { $addArgumentDescription, $addInputDescription } from "@highstate/contract"\n' + finalResult;
225
173
  }
226
- return result;
174
+ return finalResult;
227
175
  }
228
- function injectDescriptionIntoObject(objectString, description) {
229
- const trimmed = objectString.trim();
230
- const metaRegex = /meta\s*:\s*\{/;
231
- if (metaRegex.test(trimmed)) {
232
- const hasDescription = /meta\s*:\s*\{[^}]*description\s*:/.test(trimmed);
233
- if (hasDescription) {
234
- return trimmed.replace(/description\s*:\s*`[^`]*`/, `description: \`${description}\``);
235
- } else {
236
- return trimmed.replace(
237
- /meta\s*:\s*\{/,
238
- `meta: {
239
- description: \`${description}\`,`
240
- );
241
- }
242
- } else {
243
- const lastBraceIndex = trimmed.lastIndexOf("}");
244
- if (lastBraceIndex === -1) {
245
- return trimmed;
246
- }
247
- const beforeBrace = trimmed.substring(0, lastBraceIndex);
248
- const afterBrace = trimmed.substring(lastBraceIndex);
249
- const needsComma = beforeBrace.trim().length > 1 && !beforeBrace.trim().endsWith(",");
250
- const comma = needsComma ? "," : "";
251
- return `${beforeBrace}${comma}
176
+ async function applyDefineFunctionMetaTransformations(content) {
177
+ const { program, comments } = await parseAsync("file.ts", content);
178
+ const parentStack = [];
179
+ const result = new MagicString(content);
180
+ walk(program, {
181
+ enter(node) {
182
+ parentStack.push(node);
183
+ if (node.type === "CallExpression" && "callee" in node && node.callee.type === "Identifier") {
184
+ const callNode = node;
185
+ const callee = callNode.callee;
186
+ const functionName = "name" in callee && typeof callee.name === "string" ? callee.name : void 0;
187
+ if (functionName && ["defineUnit", "defineEntity", "defineComponent"].includes(functionName)) {
188
+ const jsdoc = findJsdocForDefineFunction(content, parentStack, comments);
189
+ if (jsdoc && callNode.arguments && callNode.arguments.length > 0) {
190
+ const description = cleanJsdoc(jsdoc.value);
191
+ const firstArg = callNode.arguments[0];
192
+ if (firstArg.type === "ObjectExpression" && "properties" in firstArg) {
193
+ const properties = firstArg.properties;
194
+ const metaProperty = properties?.find(
195
+ (prop) => prop.type === "Property" && "key" in prop && prop.key?.type === "Identifier" && prop.key?.name === "meta"
196
+ );
197
+ if (metaProperty && "value" in metaProperty) {
198
+ const originalMetaValue = content.substring(
199
+ metaProperty.value.start,
200
+ metaProperty.value.end
201
+ );
202
+ const newMetaValue = injectDescriptionIntoMetaObject(originalMetaValue, description);
203
+ result.update(metaProperty.value.start, metaProperty.value.end, newMetaValue);
204
+ } else if (properties && properties.length > 0) {
205
+ const lastProperty = properties[properties.length - 1];
206
+ if (lastProperty && "end" in lastProperty) {
207
+ const insertPos = lastProperty.end;
208
+ const newMetaProperty = `,
209
+
252
210
  meta: {
253
211
  description: \`${description}\`,
254
- },
255
- ${afterBrace}`;
256
- }
257
- }
258
- function isStructuredValue(value, expectedField) {
259
- const trimmed = value.trim();
260
- if (!trimmed.startsWith("{")) {
261
- return false;
262
- }
263
- const fieldPattern = new RegExp(`^\\s*{[^}]*\\b${expectedField}\\s*:`, "s");
264
- return fieldPattern.test(trimmed);
212
+ }`;
213
+ result.appendLeft(insertPos, newMetaProperty);
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ },
221
+ leave() {
222
+ parentStack.pop();
223
+ }
224
+ });
225
+ return result.toString();
265
226
  }
266
- function getMarkerFunctionName(parentStack) {
227
+ function findJsdocForDefineFunction(content, parentStack, comments) {
267
228
  for (let i = parentStack.length - 1; i >= 0; i--) {
268
229
  const node = parentStack[i];
269
- if (node.type === "CallExpression" && node.callee.type === "Identifier") {
270
- const functionName = node.callee.name;
271
- if (functionName.startsWith("$") && ["$args", "$inputs", "$outputs", "$secrets"].includes(functionName)) {
272
- return functionName.substring(1);
273
- }
230
+ if (node.type === "VariableDeclarator" && "id" in node && node.id?.type === "Identifier") {
231
+ const jsdoc = findLeadingComment(content, node, comments);
232
+ if (jsdoc) return jsdoc;
233
+ }
234
+ if (node.type === "VariableDeclaration") {
235
+ const jsdoc = findLeadingComment(content, node, comments);
236
+ if (jsdoc) return jsdoc;
237
+ }
238
+ if (node.type === "ExportNamedDeclaration" && "declaration" in node && node.declaration) {
239
+ const jsdoc = findLeadingComment(content, node, comments);
240
+ if (jsdoc) return jsdoc;
274
241
  }
275
242
  }
276
243
  return null;
277
244
  }
245
+ function isZodObjectProperty(node, parentStack) {
246
+ return node.type === "Property" && "key" in node && node.key?.type === "Identifier" && isInsideZodObject(parentStack);
247
+ }
248
+ function findLeadingComment(content, node, comments) {
249
+ return comments.find((comment) => isLeadingComment(content, node, comment)) ?? null;
250
+ }
278
251
  function getParentObjectKey(parentStack) {
279
252
  for (let i = parentStack.length - 2; i >= 0; i--) {
280
253
  const node = parentStack[i];
281
- if (node.type === "Property" && node.key.type === "Identifier") {
254
+ if (node.type === "Property" && "key" in node && node.key.type === "Identifier") {
282
255
  return node.key.name;
283
256
  }
284
257
  }
@@ -294,24 +267,41 @@ function isLeadingComment(content, node, comment) {
294
267
  function cleanJsdoc(str) {
295
268
  return str.replace(/^\s*\*/gm, "").replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\${/g, "\\${").trim();
296
269
  }
270
+ function injectDescriptionIntoMetaObject(objectString, description) {
271
+ const trimmed = objectString.trim();
272
+ const hasDescription = /description\s*:/.test(trimmed);
273
+ if (hasDescription) {
274
+ return trimmed.replace(/description\s*:\s*`[^`]*`/, `description: \`${description}\``);
275
+ } else {
276
+ const openBraceIndex = trimmed.indexOf("{");
277
+ if (openBraceIndex === -1) {
278
+ return trimmed;
279
+ }
280
+ const beforeBrace = trimmed.substring(0, openBraceIndex + 1);
281
+ const afterBrace = trimmed.substring(openBraceIndex + 1);
282
+ return `${beforeBrace}
283
+ description: \`${description}\`,${afterBrace}`;
284
+ }
285
+ }
297
286
  function isInsideZodObject(parentStack) {
298
287
  for (let i = parentStack.length - 1; i >= 0; i--) {
299
288
  const node = parentStack[i];
300
- if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && isZodObjectCall(node.callee)) {
289
+ if (node.type === "CallExpression" && "callee" in node && node.callee.type === "MemberExpression" && isZodObjectCall(node.callee)) {
301
290
  return true;
302
291
  }
303
292
  }
304
293
  return false;
305
294
  }
306
295
  function isZodObjectCall(memberExpression) {
307
- if (memberExpression.type !== "MemberExpression") {
296
+ if (memberExpression.type !== "MemberExpression" || !("object" in memberExpression) || !("property" in memberExpression)) {
308
297
  return false;
309
298
  }
310
- if (memberExpression.object.type === "Identifier" && memberExpression.object.name === "z" && memberExpression.property.type === "Identifier" && memberExpression.property.name === "object") {
299
+ const member = memberExpression;
300
+ if (member.object.type === "Identifier" && "name" in member.object && member.object.name === "z" && member.property.type === "Identifier" && member.property.name === "object") {
311
301
  return true;
312
302
  }
313
- if (memberExpression.property.type === "Identifier" && memberExpression.property.name === "object" && memberExpression.object.type === "CallExpression" && memberExpression.object.callee.type === "MemberExpression") {
314
- return startsWithZodCall(memberExpression.object);
303
+ if (member.property.type === "Identifier" && member.property.name === "object" && member.object.type === "CallExpression" && "callee" in member.object && member.object.callee.type === "MemberExpression") {
304
+ return startsWithZodCall(member.object);
315
305
  }
316
306
  return false;
317
307
  }
@@ -320,11 +310,12 @@ function startsWithZodCall(callExpression) {
320
310
  return false;
321
311
  }
322
312
  if (callExpression.callee.type === "MemberExpression") {
323
- if (callExpression.callee.object.type === "Identifier" && callExpression.callee.object.name === "z") {
313
+ const callee = callExpression.callee;
314
+ if (callee.object.type === "Identifier" && "name" in callee.object && callee.object.name === "z") {
324
315
  return true;
325
316
  }
326
- if (callExpression.callee.object.type === "CallExpression") {
327
- return startsWithZodCall(callExpression.callee.object);
317
+ if (callee.object.type === "CallExpression") {
318
+ return startsWithZodCall(callee.object);
328
319
  }
329
320
  }
330
321
  return false;
@@ -438,7 +429,6 @@ var SourceHashCalculator = class {
438
429
  })
439
430
  );
440
431
  break;
441
- case "auto":
442
432
  default:
443
433
  promises.push(
444
434
  this.getFileHash(fullPath).then((hash) => ({
@@ -594,6 +584,151 @@ ${content}`,
594
584
  }
595
585
  };
596
586
  }
587
+ var packageJsonSchema = z.object({
588
+ name: z.string(),
589
+ highstate: highstateConfigSchema.optional()
590
+ });
591
+ function generateTsconfigContent(workspaceRoot, packagePath) {
592
+ const relativePath = relative(workspaceRoot, packagePath);
593
+ const depth = relativePath.split("/").length;
594
+ const relativeNodeModules = `${"../".repeat(depth)}node_modules/@highstate/cli/assets/tsconfig.base.json`;
595
+ return {
596
+ extends: relativeNodeModules,
597
+ include: ["./src/**/*.ts", "./package.json", "./assets/**/*.json"]
598
+ };
599
+ }
600
+ async function findWorkspaceRoot(startPath = process.cwd()) {
601
+ let currentPath = resolve(startPath);
602
+ while (currentPath !== "/") {
603
+ const packageJsonPath = join(currentPath, "package.json");
604
+ if (existsSync(packageJsonPath)) {
605
+ try {
606
+ const content = await readFile(packageJsonPath, "utf-8");
607
+ const packageJson = JSON.parse(content);
608
+ if (packageJson.workspaces) {
609
+ return currentPath;
610
+ }
611
+ } catch {
612
+ }
613
+ }
614
+ const parentPath = resolve(currentPath, "..");
615
+ if (parentPath === currentPath) break;
616
+ currentPath = parentPath;
617
+ }
618
+ throw new Error("Could not find workspace root (no package.json with workspaces found)");
619
+ }
620
+ async function scanWorkspacePackages(workspaceRoot) {
621
+ const packages = [];
622
+ const packagesDir = join(workspaceRoot, "packages");
623
+ if (!existsSync(packagesDir)) {
624
+ return packages;
625
+ }
626
+ async function scanDirectory(dirPath, depth = 0) {
627
+ const dirName = relative(packagesDir, dirPath).split("/").pop();
628
+ if (dirName?.startsWith(".") || dirName === "node_modules") {
629
+ return;
630
+ }
631
+ const entries = await readdir(dirPath, { withFileTypes: true });
632
+ for (const entry of entries) {
633
+ if (!entry.isDirectory()) continue;
634
+ const entryPath = join(dirPath, entry.name);
635
+ if (entry.name.startsWith(".") || entry.name === "node_modules") {
636
+ continue;
637
+ }
638
+ const packageJsonPath = join(entryPath, "package.json");
639
+ if (existsSync(packageJsonPath)) {
640
+ try {
641
+ const content = await readFile(packageJsonPath, "utf-8");
642
+ const packageJson = packageJsonSchema.parse(JSON.parse(content));
643
+ const relativePath = relative(workspaceRoot, entryPath);
644
+ const type = packageJson.highstate?.type ?? "source";
645
+ packages.push({
646
+ path: entryPath,
647
+ relativePath,
648
+ name: packageJson.name,
649
+ type
650
+ });
651
+ } catch {
652
+ }
653
+ }
654
+ if (depth < 3) {
655
+ await scanDirectory(entryPath, depth + 1);
656
+ }
657
+ }
658
+ }
659
+ await scanDirectory(packagesDir);
660
+ return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
661
+ }
662
+ async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs = false) {
663
+ const tsconfigPath = join(workspaceRoot, "tsconfig.json");
664
+ if (ensureTsconfigs) {
665
+ await ensurePackageTsconfigs(
666
+ workspaceRoot,
667
+ // only udate for Highstate-managed packages
668
+ packages.filter((pkg) => pkg.type !== void 0)
669
+ );
670
+ }
671
+ const references = packages.map((pkg) => ({
672
+ path: `./${pkg.relativePath}/tsconfig.json`
673
+ }));
674
+ const tsconfigContent = {
675
+ files: [],
676
+ references
677
+ };
678
+ await writeFile(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
679
+ `, "utf-8");
680
+ }
681
+ async function ensurePackageTsconfigs(workspaceRoot, packages) {
682
+ for (const pkg of packages) {
683
+ const tsconfigPath = join(pkg.path, "tsconfig.json");
684
+ const tsconfigContent = generateTsconfigContent(workspaceRoot, pkg.path);
685
+ await writeFile(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
686
+ `, "utf-8");
687
+ }
688
+ }
689
+ async function createPackage(workspaceRoot, name, type) {
690
+ const packagePath = join(workspaceRoot, "packages", name);
691
+ const srcPath = join(packagePath, "src");
692
+ await mkdir(packagePath, { recursive: true });
693
+ await mkdir(srcPath, { recursive: true });
694
+ const packageJson = {
695
+ name: `@highstate/${name}`,
696
+ version: "0.0.1",
697
+ type: "module",
698
+ highstate: {
699
+ type
700
+ }
701
+ };
702
+ await writeFile(
703
+ join(packagePath, "package.json"),
704
+ `${JSON.stringify(packageJson, null, 2)}
705
+ `,
706
+ "utf-8"
707
+ );
708
+ const tsconfigContent = generateTsconfigContent(workspaceRoot, packagePath);
709
+ await writeFile(
710
+ join(packagePath, "tsconfig.json"),
711
+ `${JSON.stringify(tsconfigContent, null, 2)}
712
+ `,
713
+ "utf-8"
714
+ );
715
+ await writeFile(
716
+ join(packagePath, "CHANGELOG.md"),
717
+ `# Changelog
718
+
719
+ All notable changes to this project will be documented in this file.
720
+ `,
721
+ "utf-8"
722
+ );
723
+ await writeFile(join(srcPath, "index.ts"), `// ${name} package
724
+ `, "utf-8");
725
+ return {
726
+ path: packagePath,
727
+ relativePath: `packages/${name}`,
728
+ name: `@highstate/${name}`,
729
+ type
730
+ };
731
+ }
597
732
 
598
733
  // src/commands/designer.ts
599
734
  var DesignerCommand = class extends Command {
@@ -619,10 +754,10 @@ var DesignerCommand = class extends Command {
619
754
  const port = await getPort();
620
755
  process.env.NITRO_PORT = port.toString();
621
756
  process.env.NITRO_HOST = "0.0.0.0";
622
- await new Promise((resolve3) => {
757
+ await new Promise((resolve4) => {
623
758
  console.log = (message) => {
624
759
  if (message.startsWith("Listening on")) {
625
- resolve3();
760
+ resolve4();
626
761
  }
627
762
  };
628
763
  const path = "@highstate/designer/.output/server/index.mjs";
@@ -759,7 +894,7 @@ var BuildCommand = class extends Command {
759
894
  await sourceHashCalculator.writeHighstateManifest("./dist", distPathToExportKey);
760
895
  }
761
896
  if (this.library) {
762
- const { loadLibrary } = await import('./library-loader-ZABUULFB.js');
897
+ const { loadLibrary } = await import('./library-loader-6TJTW2HX.js');
763
898
  const fullModulePaths = Object.values(entry).map((value) => resolve(value.distPath));
764
899
  logger.info("evaluating library components from modules: %s", fullModulePaths.join(", "));
765
900
  const library = await loadLibrary(logger, fullModulePaths);
@@ -784,6 +919,88 @@ var BackendIdentityCommand = class extends Command {
784
919
  logger.info(`run "highstate backend unlock-method add ${recipient}" on other authorized device`);
785
920
  }
786
921
  };
922
+ var UpdateReferencesCommand = class extends Command {
923
+ static paths = [["package", "update-references"]];
924
+ static usage = Command.Usage({
925
+ category: "Package",
926
+ description: "Updates the root tsconfig.json with references to all packages in the workspace."
927
+ });
928
+ async execute() {
929
+ const workspaceRoot = await findWorkspaceRoot();
930
+ const packages = await scanWorkspacePackages(workspaceRoot);
931
+ await updateTsconfigReferences(workspaceRoot, packages, true);
932
+ }
933
+ };
934
+ var ListCommand = class extends Command {
935
+ static paths = [["package", "list"]];
936
+ static usage = Command.Usage({
937
+ category: "Package",
938
+ description: "Lists all packages in the workspace with their types."
939
+ });
940
+ async execute() {
941
+ const workspaceRoot = await findWorkspaceRoot();
942
+ const packages = await scanWorkspacePackages(workspaceRoot);
943
+ if (packages.length === 0) {
944
+ console.log("No packages found in workspace.");
945
+ return;
946
+ }
947
+ const nameWidth = Math.max(4, ...packages.map((pkg) => pkg.name.length));
948
+ const typeWidth = Math.max(4, ...packages.map((pkg) => pkg.type?.length ?? 0));
949
+ const pathWidth = Math.max(4, ...packages.map((pkg) => pkg.relativePath.length));
950
+ console.log(
951
+ `${"Name".padEnd(nameWidth)} ${"Type".padEnd(typeWidth)} ${"Path".padEnd(pathWidth)}`
952
+ );
953
+ console.log(`${"-".repeat(nameWidth)} ${"-".repeat(typeWidth)} ${"-".repeat(pathWidth)}`);
954
+ for (const pkg of packages) {
955
+ const type = pkg.type ?? "unknown";
956
+ console.log(
957
+ `${pkg.name.padEnd(nameWidth)} ${type.padEnd(typeWidth)} ${pkg.relativePath.padEnd(pathWidth)}`
958
+ );
959
+ }
960
+ }
961
+ };
962
+ var CreateCommand = class extends Command {
963
+ static paths = [["package", "create"]];
964
+ static usage = Command.Usage({
965
+ category: "Package",
966
+ description: "Creates a new package in the workspace."
967
+ });
968
+ name = Option.String({ required: true });
969
+ type = Option.String("--type,-t", {
970
+ description: "Package type (source, library, worker)"
971
+ });
972
+ async execute() {
973
+ const workspaceRoot = await findWorkspaceRoot();
974
+ const packageType = highstateConfigSchema.shape.type.parse(this.type);
975
+ await createPackage(workspaceRoot, this.name, packageType);
976
+ const packages = await scanWorkspacePackages(workspaceRoot);
977
+ await updateTsconfigReferences(workspaceRoot, packages);
978
+ console.log(`Created package: @highstate/${this.name} (${packageType})`);
979
+ }
980
+ };
981
+ var RemoveCommand = class extends Command {
982
+ static paths = [["package", "remove"]];
983
+ static usage = Command.Usage({
984
+ category: "Package",
985
+ description: "Removes a package from the workspace."
986
+ });
987
+ name = Option.String({ required: true });
988
+ async execute() {
989
+ const workspaceRoot = await findWorkspaceRoot();
990
+ const packages = await scanWorkspacePackages(workspaceRoot);
991
+ const targetPackage = packages.find(
992
+ (pkg) => pkg.name === this.name || pkg.name === `@highstate/${this.name}` || pkg.relativePath.endsWith(this.name)
993
+ );
994
+ if (!targetPackage) {
995
+ console.error(`Package not found: ${this.name}`);
996
+ process.exit(1);
997
+ }
998
+ await rm(targetPackage.path, { recursive: true, force: true });
999
+ const remainingPackages = await scanWorkspacePackages(workspaceRoot);
1000
+ await updateTsconfigReferences(workspaceRoot, remainingPackages);
1001
+ console.log(`Removed package: ${targetPackage.name}`);
1002
+ }
1003
+ };
787
1004
 
788
1005
  // src/main.ts
789
1006
  var cli = new Cli({
@@ -794,6 +1011,10 @@ var cli = new Cli({
794
1011
  cli.register(BuildCommand);
795
1012
  cli.register(DesignerCommand);
796
1013
  cli.register(BackendIdentityCommand);
1014
+ cli.register(UpdateReferencesCommand);
1015
+ cli.register(ListCommand);
1016
+ cli.register(CreateCommand);
1017
+ cli.register(RemoveCommand);
797
1018
  cli.register(Builtins.HelpCommand);
798
1019
  cli.register(Builtins.VersionCommand);
799
1020
  await cli.runExit(process.argv.slice(2));