@tscircuit/cli 0.0.39 → 0.0.41

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 (33) hide show
  1. package/bun.lockb +0 -0
  2. package/dev-server-api/routes/api/dev_package_examples/create.ts +3 -0
  3. package/dev-server-api/routes/api/dev_package_examples/get.ts +2 -0
  4. package/dev-server-api/routes/api/dev_package_examples/list.ts +13 -9
  5. package/dev-server-api/routes/api/dev_server/reset.ts +15 -0
  6. package/dev-server-api/src/db/create-schema.ts +1 -0
  7. package/dev-server-api/src/db/get-db.ts +5 -2
  8. package/dev-server-api/src/middlewares/with-error-response.ts +15 -2
  9. package/dev-server-frontend/bun.lockb +0 -0
  10. package/dev-server-frontend/package.json +5 -4
  11. package/dev-server-frontend/src/ExampleContentView.tsx +29 -1
  12. package/dev-server-frontend/src/components/command-k.tsx +29 -5
  13. package/dist/cli.js +243 -154
  14. package/lib/cmd-fns/config-set-runtime.ts +7 -0
  15. package/lib/cmd-fns/dev/index.ts +9 -6
  16. package/lib/cmd-fns/dev/mark-all-examples-loading.ts +18 -0
  17. package/lib/cmd-fns/dev/soupify-and-upload-example-file.ts +29 -14
  18. package/lib/cmd-fns/dev/start-watcher.ts +11 -8
  19. package/lib/cmd-fns/dev/upload-examples-from-directory.ts +23 -12
  20. package/lib/cmd-fns/dev-server-upload.ts +2 -2
  21. package/lib/cmd-fns/index.ts +1 -0
  22. package/lib/cmd-fns/package-examples-create.ts +7 -4
  23. package/lib/cmd-fns/publish/index.ts +7 -4
  24. package/lib/cmd-fns/soupify.ts +7 -4
  25. package/lib/create-config-manager.ts +1 -0
  26. package/lib/get-program.ts +7 -0
  27. package/lib/param-handlers/index.ts +2 -0
  28. package/lib/param-handlers/interact-for-runtime.ts +33 -0
  29. package/lib/soupify.ts +13 -8
  30. package/lib/util/app-context.ts +1 -0
  31. package/lib/util/create-context-and-run-program.ts +1 -0
  32. package/package.json +9 -6
  33. package/dev-server-api/index.ts +0 -1
@@ -0,0 +1,7 @@
1
+ import { AppContext } from "../util/app-context"
2
+ import { z } from "zod"
3
+
4
+ export const configSetRuntime = async (ctx: AppContext, args: any) => {
5
+ const params = z.object({ runtime: z.enum(["bun", "node"]) }).parse(args)
6
+ ctx.global_config.set("runtime", params.runtime)
7
+ }
@@ -16,12 +16,12 @@ import { initCmd } from "../init"
16
16
  export const devCmd = async (ctx: AppContext, args: any) => {
17
17
  const params = z
18
18
  .object({
19
- cwd: z.string().optional().default(process.cwd()),
20
19
  port: z.coerce.number().optional().default(3020),
21
20
  })
22
21
  .parse(args)
23
22
 
24
- const { cwd, port } = params
23
+ const { port } = params
24
+ const { cwd } = ctx
25
25
 
26
26
  // In the future we should automatically run "tsci init" if the directory
27
27
  // isn't properly initialized, for now we're just going to do a spot check
@@ -53,8 +53,8 @@ export const devCmd = async (ctx: AppContext, args: any) => {
53
53
  // Add .tscircuit to .gitignore if it's not already there
54
54
  // TODO
55
55
 
56
- // Delete old .tscircuit/dev-server.db
57
- unlink(Path.join(cwd, ".tscircuit/dev-server.db")).catch(() => {})
56
+ // Delete old .tscircuit/dev-server.sqlite
57
+ unlink(Path.join(cwd, ".tscircuit/dev-server.sqlite")).catch(() => {})
58
58
 
59
59
  console.log(
60
60
  kleur.green(
@@ -66,12 +66,15 @@ export const devCmd = async (ctx: AppContext, args: any) => {
66
66
 
67
67
  const server = await startDevServer({ port, devServerAxios })
68
68
 
69
+ // Reset the database, allows migration to re-run
70
+ await devServerAxios.post("/api/dev_server/reset")
71
+
69
72
  // Soupify all examples
70
73
  console.log(`Loading examples...`)
71
- await uploadExamplesFromDirectory({ devServerAxios, cwd })
74
+ await uploadExamplesFromDirectory({ devServerAxios, cwd }, ctx)
72
75
 
73
76
  // Start watcher
74
- const watcher = await startWatcher({ cwd, devServerAxios })
77
+ const watcher = await startWatcher({ cwd, devServerAxios }, ctx)
75
78
 
76
79
  while (true) {
77
80
  const { action } = await prompts({
@@ -0,0 +1,18 @@
1
+ import { AxiosInstance } from "axios"
2
+
3
+ export const markAllExamplesLoading = async ({
4
+ devServerAxios,
5
+ }: {
6
+ devServerAxios: AxiosInstance
7
+ }) => {
8
+ const examples = await devServerAxios
9
+ .post("/api/dev_package_examples/list")
10
+ .then((r) => r.data.dev_package_examples)
11
+
12
+ for (const example of examples) {
13
+ await devServerAxios.post("/api/dev_package_examples/update", {
14
+ dev_package_example_id: example.dev_package_example_id,
15
+ is_loading: true,
16
+ })
17
+ }
18
+ }
@@ -5,26 +5,33 @@ import { readdirSync, readFileSync } from "fs"
5
5
  import { soupify } from "lib/soupify"
6
6
  import { inferExportNameFromSource } from "./infer-export-name-from-source"
7
7
 
8
- export const soupifyAndUploadExampleFile = async ({
9
- examplesDir,
10
- exampleFileName,
11
- devServerAxios,
12
- }: {
13
- examplesDir: string
14
- exampleFileName: string
15
- devServerAxios: AxiosInstance
16
- }) => {
8
+ export const soupifyAndUploadExampleFile = async (
9
+ {
10
+ examplesDir,
11
+ exampleFileName,
12
+ devServerAxios,
13
+ }: {
14
+ examplesDir: string
15
+ exampleFileName: string
16
+ devServerAxios: AxiosInstance
17
+ },
18
+ ctx: { runtime: "node" | "bun" }
19
+ ) => {
17
20
  try {
21
+ const startTime = Date.now()
18
22
  const examplePath = joinPath(examplesDir, exampleFileName)
19
23
  const exampleContent = readFileSync(examplePath).toString()
20
24
 
21
25
  const exportName = inferExportNameFromSource(exampleContent)
22
26
 
23
27
  console.log(kleur.gray(`[soupifying] ${exampleFileName}...`))
24
- const { soup, error } = await soupify({
25
- filePath: examplePath,
26
- exportName,
27
- })
28
+ const { soup, error } = await soupify(
29
+ {
30
+ filePath: examplePath,
31
+ exportName,
32
+ },
33
+ ctx
34
+ )
28
35
  .then((soup) => ({ soup, error: null }))
29
36
  .catch((e) => ({ error: e, soup: undefined }))
30
37
 
@@ -38,8 +45,16 @@ export const soupifyAndUploadExampleFile = async ({
38
45
  error: error?.toString() || null,
39
46
  file_path: examplePath,
40
47
  export_name: exportName,
48
+ is_loading: false,
41
49
  })
42
- console.log(kleur.gray(`[ done ] ${exampleFileName}!`))
50
+ const timeTaken = Date.now() - startTime
51
+ console.log(
52
+ kleur.gray(
53
+ `[ done ] [ ${Math.round(timeTaken)
54
+ .toString()
55
+ .padStart(5, " ")}ms ] ${exampleFileName}!`
56
+ )
57
+ )
43
58
  } catch (e: any) {
44
59
  console.log(kleur.red(`[ error ] ${e.toString()}`))
45
60
  }
@@ -3,13 +3,16 @@ import chokidar from "chokidar"
3
3
  import { uploadExamplesFromDirectory } from "./upload-examples-from-directory"
4
4
  import kleur from "kleur"
5
5
 
6
- export const startWatcher = async ({
7
- cwd,
8
- devServerAxios,
9
- }: {
10
- cwd: string
11
- devServerAxios: AxiosInstance
12
- }) => {
6
+ export const startWatcher = async (
7
+ {
8
+ cwd,
9
+ devServerAxios,
10
+ }: {
11
+ cwd: string
12
+ devServerAxios: AxiosInstance
13
+ },
14
+ ctx: { runtime: "node" | "bun" }
15
+ ) => {
13
16
  const watcher = chokidar.watch(`${cwd}/**/*.tsx`, {
14
17
  ignored: /node_modules/,
15
18
  persistent: true,
@@ -31,7 +34,7 @@ export const startWatcher = async ({
31
34
  if (upload_queue_state.dirty) {
32
35
  console.log(kleur.yellow("Changes detected, re-uploading examples..."))
33
36
  upload_queue_state.dirty = false
34
- await uploadExamplesFromDirectory({ cwd, devServerAxios })
37
+ await uploadExamplesFromDirectory({ cwd, devServerAxios }, ctx)
35
38
  }
36
39
  await new Promise((resolve) => setTimeout(resolve, 100))
37
40
  }
@@ -4,23 +4,34 @@ import { AxiosInstance } from "axios"
4
4
  import { readdirSync, readFileSync } from "fs"
5
5
  import { soupify } from "lib/soupify"
6
6
  import { soupifyAndUploadExampleFile } from "./soupify-and-upload-example-file"
7
+ import { markAllExamplesLoading } from "./mark-all-examples-loading"
7
8
 
8
- export const uploadExamplesFromDirectory = async ({
9
- cwd,
10
- devServerAxios,
11
- }: {
12
- cwd: string
13
- devServerAxios: AxiosInstance
14
- }) => {
9
+ export const uploadExamplesFromDirectory = async (
10
+ {
11
+ cwd,
12
+ devServerAxios,
13
+ }: {
14
+ cwd: string
15
+ devServerAxios: AxiosInstance
16
+ },
17
+ ctx: { runtime: "node" | "bun" }
18
+ ) => {
15
19
  const examplesDir = joinPath(cwd, "examples")
16
20
  const exampleFileNames = readdirSync(examplesDir)
21
+
22
+ // Mark all examples as being "reloaded" in the database
23
+ await markAllExamplesLoading({ devServerAxios })
24
+
17
25
  for (const exampleFileName of exampleFileNames) {
18
26
  if (exampleFileName.endsWith(".__tmp_entrypoint.tsx")) continue
19
27
  if (!exampleFileName.endsWith(".tsx")) continue
20
- await soupifyAndUploadExampleFile({
21
- devServerAxios,
22
- examplesDir,
23
- exampleFileName,
24
- })
28
+ await soupifyAndUploadExampleFile(
29
+ {
30
+ devServerAxios,
31
+ examplesDir,
32
+ exampleFileName,
33
+ },
34
+ ctx
35
+ )
25
36
  }
26
37
  }
@@ -17,10 +17,10 @@ export const devServerUpload = async (ctx: AppContext, args: any) => {
17
17
  const devServerAxios = getDevServerAxios({ serverUrl })
18
18
 
19
19
  console.log(`Loading examples...`)
20
- await uploadExamplesFromDirectory({ devServerAxios, cwd: params.dir })
20
+ await uploadExamplesFromDirectory({ devServerAxios, cwd: params.dir }, ctx)
21
21
 
22
22
  if (params.watch) {
23
23
  // Start watcher
24
- const watcher = await startWatcher({ cwd: params.dir, devServerAxios })
24
+ const watcher = await startWatcher({ cwd: params.dir, devServerAxios }, ctx)
25
25
  }
26
26
  }
@@ -1,6 +1,7 @@
1
1
  export { configRevealLocation } from "./config-reveal-location"
2
2
  export { configSetRegistry } from "./config-set-registry"
3
3
  export { configSetSession } from "./config-set-session"
4
+ export { configSetRuntime } from "./config-set-runtime"
4
5
  export { configSetLogRequests } from "./config-set-log-requests"
5
6
  export { configPrintConfig } from "./config-print-config"
6
7
  export { authLogin } from "./auth-login"
@@ -12,10 +12,13 @@ export const packageExamplesCreate = async (ctx: AppContext, args: any) => {
12
12
  })
13
13
  .parse(args)
14
14
 
15
- const tscircuit_soup = await soupify({
16
- filePath: params.file,
17
- exportName: params.export,
18
- })
15
+ const tscircuit_soup = await soupify(
16
+ {
17
+ filePath: params.file,
18
+ exportName: params.export,
19
+ },
20
+ ctx
21
+ )
19
22
 
20
23
  const fileContent = await fs.promises.readFile(params.file, "utf8")
21
24
 
@@ -218,10 +218,13 @@ export const publish = async (ctx: AppContext, args: any) => {
218
218
 
219
219
  const exportName = inferExportNameFromSource(fileContent)
220
220
 
221
- const tscircuit_soup = await soupify({
222
- filePath,
223
- exportName,
224
- }).catch((e) => e)
221
+ const tscircuit_soup = await soupify(
222
+ {
223
+ filePath,
224
+ exportName,
225
+ },
226
+ ctx
227
+ ).catch((e) => e)
225
228
 
226
229
  if (tscircuit_soup instanceof Error) {
227
230
  console.log(
@@ -14,10 +14,13 @@ export const soupifyCmd = async (ctx: AppContext, args: any) => {
14
14
  })
15
15
  .parse(args)
16
16
 
17
- const soup = await soupify({
18
- filePath: params.file,
19
- exportName: params.export,
20
- })
17
+ const soup = await soupify(
18
+ {
19
+ filePath: params.file,
20
+ exportName: params.export,
21
+ },
22
+ ctx
23
+ )
21
24
 
22
25
  if (params.output) {
23
26
  await writeFileSync(params.output, JSON.stringify(soup, null, 2))
@@ -8,6 +8,7 @@ interface ProfileConfigProps {
8
8
  interface GlobalConfigProps {
9
9
  current_profile?: string
10
10
  log_requests?: boolean
11
+ runtime?: "bun" | "node"
11
12
  }
12
13
 
13
14
  interface TypedConfigstore<T extends Record<string, any>> {
@@ -40,6 +40,13 @@ export const getProgram = (ctx: AppContext) => {
40
40
  .command("set-session")
41
41
  .requiredOption("--session-token <session_token>", "Session Token")
42
42
  .action((args) => CMDFN.configSetSession(ctx, args))
43
+ configCmd
44
+ .command("set-runtime")
45
+ .requiredOption(
46
+ "--runtime <runtime>",
47
+ "Bun or node. Setting to bun generally doubles soupification speed."
48
+ )
49
+ .action((args) => CMDFN.configSetRuntime(ctx, args))
43
50
  configCmd
44
51
  .command("set-log-requests")
45
52
  .requiredOption("--log-requests", "Should log requests to registry")
@@ -5,6 +5,7 @@ import { interactForPackageName } from "./interact-for-package-name"
5
5
  import { interactForPackageNameWithVersion } from "./interact-for-package-name-with-version"
6
6
  import { interactForPackageReleaseId } from "./interact-for-package-release-id"
7
7
  import { interactForRegistryUrl } from "./interact-for-registry-url"
8
+ import { interactForRuntime } from "./interact-for-runtime"
8
9
  import { ParamHandler } from "./param-handler-type"
9
10
 
10
11
  export const PARAM_HANDLERS_BY_PARAM_NAME: Record<string, ParamHandler> = {
@@ -12,6 +13,7 @@ export const PARAM_HANDLERS_BY_PARAM_NAME: Record<string, ParamHandler> = {
12
13
  cwd: interactForLocalDirectory,
13
14
  dir: interactForLocalDirectory,
14
15
  registry_url: interactForRegistryUrl,
16
+ runtime: interactForRuntime,
15
17
  package_release_id: interactForPackageReleaseId,
16
18
  package_name: interactForPackageName,
17
19
  package_name_with_version: interactForPackageNameWithVersion,
@@ -0,0 +1,33 @@
1
+ import kleur from "kleur"
2
+ import { ParamHandler } from "./param-handler-type"
3
+ import $ from "dax-sh"
4
+
5
+ export const interactForRuntime: ParamHandler = async (params) => {
6
+ const { prompts, ctx } = params
7
+
8
+ const bunVersion = await $`bun --version`.text().catch((e) => null)
9
+
10
+ if (!bunVersion) {
11
+ console.log(
12
+ kleur.red(`BUN IS NOT INSTALLED! Install bun first https://bun.sh/`)
13
+ )
14
+ }
15
+
16
+ const { runtime } = await prompts({
17
+ type: "select",
18
+ name: "runtime",
19
+ message: "Select a runtime",
20
+ choices: [
21
+ {
22
+ title: "bun",
23
+ value: "bun",
24
+ description: bunVersion
25
+ ? `bun version: ${bunVersion}`
26
+ : "NOTE: bun not installed, install bun first!",
27
+ },
28
+ { title: "node", value: "node" },
29
+ ],
30
+ })
31
+
32
+ return runtime
33
+ }
package/lib/soupify.ts CHANGED
@@ -6,13 +6,16 @@ import { unlink } from "node:fs/promises"
6
6
  import kleur from "kleur"
7
7
  import { writeFileSync } from "fs"
8
8
 
9
- export const soupify = async ({
10
- filePath,
11
- exportName,
12
- }: {
13
- filePath: string
14
- exportName?: string
15
- }) => {
9
+ export const soupify = async (
10
+ {
11
+ filePath,
12
+ exportName,
13
+ }: {
14
+ filePath: string
15
+ exportName?: string
16
+ },
17
+ ctx: { runtime: "node" | "bun" }
18
+ ) => {
16
19
  const tmpFilePath = Path.join(
17
20
  Path.dirname(filePath),
18
21
  Path.basename(filePath).replace(/\.[^\.]+$/, "") + ".__tmp_entrypoint.tsx"
@@ -44,7 +47,9 @@ console.log(JSON.stringify(elements))
44
47
  `.trim()
45
48
  )
46
49
 
47
- const processResult = await $`npx tsx ${tmpFilePath}`
50
+ const runtime = ctx.runtime === "node" ? "npx tsx" : "bun"
51
+
52
+ const processResult = await $`${runtime} ${tmpFilePath}`
48
53
  .stdout("piped")
49
54
  .stderr("piped")
50
55
  .noThrow()
@@ -10,4 +10,5 @@ export type AppContext = {
10
10
  registry_url: string
11
11
  axios: AxiosInstance
12
12
  current_profile: string
13
+ runtime: "node" | "bun"
13
14
  } & ContextConfigProps
@@ -103,6 +103,7 @@ export const createContextAndRunProgram = async (process_args: any) => {
103
103
  axios,
104
104
  global_config,
105
105
  profile_config,
106
+ runtime: global_config.get("runtime") ?? "node",
106
107
  args: {
107
108
  cmd: args._,
108
109
  yes: args.y ?? args.yes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Command line tool for developing, publishing and installing tscircuit circuits",
@@ -9,12 +9,15 @@
9
9
  "bootstrap": "bun i && cd dev-server-api && bun i && cd ../dev-server-frontend && bun i",
10
10
  "bootstrap:ci": "bun i --frozen-lockfile && cd dev-server-api && bun i --frozen-lockfile && cd ../dev-server-frontend && bun i --frozen-lockfile",
11
11
  "start": "bun cli.ts",
12
- "start:dev-server:dev": "TSCI_DEV_SERVER_DB=$(pwd)/.tscircuit/dev-server.db concurrently 'cd dev-server-api && bun start' 'cd dev-server-frontend && bun start'",
12
+ "start:dev-server:dev": "TSCI_DEV_SERVER_DB=$(pwd)/.tscircuit/dev-server.sqlite concurrently 'cd dev-server-api && bun start' 'cd dev-server-frontend && bun start'",
13
13
  "start:dev-server": "bun build:dev-server && bun cli.ts dev -y --cwd ./tests/assets/example-project",
14
14
  "build:dev-server": "cd dev-server-api && bun run build && cd ../dev-server-frontend && bun run build",
15
+ "build:dev-server:api": "cd dev-server-api && bun run build",
15
16
  "build:cli": "bun build-cli.ts",
16
17
  "build": "bun build:dev-server && npm run build:cli",
17
- "test:init": "bun cli.ts init --dir ./tmp/test --name test"
18
+ "dev-with-test-project": "bun cli.ts dev --cwd ./tests/assets/example-project",
19
+ "test:init": "bun cli.ts init --dir ./tmp/test --name test",
20
+ "update-deps": "bun add @tscircuit/builder@latest @tscircuit/react-fiber@latest && cd dev-server-frontend && bun run update-deps"
18
21
  },
19
22
  "bin": {
20
23
  "tscircuit": "./dist/cli.js",
@@ -32,8 +35,8 @@
32
35
  "dependencies": {
33
36
  "@edge-runtime/primitives": "^4.1.0",
34
37
  "@hono/node-server": "^1.8.2",
35
- "@tscircuit/builder": "^1.5.10",
36
- "@tscircuit/react-fiber": "^1.0.10",
38
+ "@tscircuit/builder": "latest",
39
+ "@tscircuit/react-fiber": "latest",
37
40
  "axios": "^1.6.7",
38
41
  "better-sqlite3": "^9.4.3",
39
42
  "chokidar": "^3.6.0",
@@ -54,7 +57,7 @@
54
57
  "minimist": "^1.2.8",
55
58
  "node-persist": "^4.0.1",
56
59
  "open": "^10.1.0",
57
- "perfect-cli": "^1.0.16",
60
+ "perfect-cli": "^1.0.19",
58
61
  "prompts": "^2.4.2",
59
62
  "react": "^18.2.0",
60
63
  "semver": "^7.6.0",
@@ -1 +0,0 @@
1
- console.log("Hello via Bun!");