Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/bun-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.1
bun-version: 1.3.5

- name: Cache node_modules
uses: actions/cache@v4
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,11 @@ Test fixture provides:
## Runtime

The CLI entrypoint (`cli/entrypoint.js`) selects between Bun and tsx as the TypeScript runner, preferring Bun when available. This allows hot-reload during development while maintaining Node.js compatibility.
# bump 1778256007
# bump 1778299207
# bump 1778342407
# bump 1778385607
# bump 1779292809
# bump 1779336007
# bump 1779379208
# bump 1779422408
496 changes: 253 additions & 243 deletions bun.lock

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion cli/build/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,16 @@ export const registerBuild = (program: Command) => {
const entryFile = fileArgIsDirectFile
? resolvedFileArgPath
: transpileEntrypoint
if (!entryFile) {
const isRealTsEntrypoint = Boolean(
entryFile &&
(entryFile.endsWith(".ts") || entryFile.endsWith(".tsx")),
)
if (
!entryFile ||
(hasConfiguredIncludeBoardFiles &&
!transpileExplicitlyRequested &&
!isRealTsEntrypoint)
) {
if (
hasConfiguredIncludeBoardFiles &&
!transpileExplicitlyRequested
Expand Down
11 changes: 10 additions & 1 deletion cli/init/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { checkForTsciUpdates } from "lib/shared/check-for-cli-update"
import { prompts } from "lib/utils/prompts"
import { fetchAccount } from "lib/registry-api/fetch-account"
import kleur from "kleur"
import { captureTelemetryEvent } from "lib/telemetry"

export const registerInit = (program: Command) => {
program
Expand Down Expand Up @@ -134,7 +135,15 @@ export default () => (
// Setup tscircuit claude skill
await setupTscircuitSkill(projectDir, options?.yes)
// Setup project dependencies
setupTsciProject(projectDir, options?.install ? undefined : [])
await setupTsciProject(projectDir, options?.install ? undefined : [])

await captureTelemetryEvent("tsci_init", {
command: "init",
directory_provided: directory !== undefined,
yes: Boolean(options?.yes),
no_install: options?.install === false,
status: "success",
})

console.info(
"\n",
Expand Down
22 changes: 22 additions & 0 deletions lib/shared/get-entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from "node:fs"
import * as path from "node:path"
import { globbySync } from "globby"
import { loadProjectConfig } from "lib/project-config"
import kleur from "kleur"

Expand Down Expand Up @@ -202,6 +203,27 @@ export const getEntrypoint = async ({
}
}

// No entrypoint found - check for circuit.json files as implicit entrypoints
// This allows `tsci push` to work the same as `tsci dev` which supports circuit.json files
const circuitJsonFiles = globbySync(
["**/*.circuit.json", "**/circuit.json"],
{
cwd: validatedProjectDir,
ignore: ["**/node_modules/**", "**/dist/**"],
},
)
.map((f) => path.resolve(validatedProjectDir, f))
.filter(
(f) => fs.existsSync(f) && isValidDirectory(f, validatedProjectDir),
)
.sort()

if (circuitJsonFiles.length > 0) {
const chosenFile = path.relative(validatedProjectDir, circuitJsonFiles[0])
onSuccess(`Using circuit.json as implicit entrypoint: '${chosenFile}'`)
return circuitJsonFiles[0]
}

onError(
kleur.red(
"No entrypoint found. Run 'tsci init' to bootstrap a basic project or specify a file with 'tsci push <file>'",
Expand Down
78 changes: 78 additions & 0 deletions lib/telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { randomUUID } from "node:crypto"
import { getVersion } from "lib/getVersion"

const POSTHOG_HOST = "https://us.i.posthog.com"
const TSCI_POSTHOG_PROJECT_API_KEY =
"phc_htd8AQjSfVEsFCLQMAiUooG4Q0DKBCjqYuQglc9V3Wo"
const POSTHOG_CAPTURE_PATH = "/capture"

export interface TelemetryConfig {
enabled: boolean
projectApiKey?: string
host?: string
distinctId?: string
}

type TelemetryProperties = Record<
string,
string | number | boolean | null | undefined
>

const isTruthy = (value: string | undefined) =>
value ? ["1", "true", "yes", "on"].includes(value.toLowerCase()) : false

const joinUrl = (host: string, path: string) =>
`${host.replace(/\/$/, "")}${path}`

export const getTelemetryConfigFromEnv = (
env: NodeJS.ProcessEnv = process.env,
): TelemetryConfig => {
if (isTruthy(env.TSCI_TELEMETRY_DISABLED)) {
return { enabled: false }
}

if (env.TSCI_TEST_MODE === "true" && !isTruthy(env.TSCI_TELEMETRY_FORCE)) {
return { enabled: false }
}

if (!TSCI_POSTHOG_PROJECT_API_KEY) return { enabled: false }

return {
enabled: true,
projectApiKey: TSCI_POSTHOG_PROJECT_API_KEY,
host: POSTHOG_HOST,
distinctId: `tscircuit-cli-${randomUUID()}`,
}
}

export const captureTelemetryEvent = async (
event: string,
properties: TelemetryProperties,
) => {
const telemetryConfig = getTelemetryConfigFromEnv()
if (!telemetryConfig.enabled || !telemetryConfig.projectApiKey) return

const url = joinUrl(POSTHOG_HOST, POSTHOG_CAPTURE_PATH)
const payload = {
api_key: telemetryConfig.projectApiKey,
distinct_id: telemetryConfig.distinctId,
event,
properties: {
...properties,
cli_version: getVersion(),
source: "@tscircuit/cli",
},
}

try {
await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
})
} catch {
// Telemetry must never make CLI commands fail.
}
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tscircuit/cli",
"version": "0.1.1397",
"version": "0.1.1398",
"main": "dist/cli/main.js",
"exports": {
".": "./dist/cli/main.js",
Expand All @@ -19,7 +19,7 @@
"@tscircuit/krt-wasm": "^0.1.0",
"@tscircuit/math-utils": "0.0.36",
"@tscircuit/props": "^0.0.532",
"@tscircuit/runframe": "^0.0.1975",
"@tscircuit/runframe": "^0.0.1982",
"@tscircuit/schematic-match-adapt": "^0.0.22",
"@types/bun": "^1.2.2",
"@types/configstore": "^6.0.2",
Expand All @@ -38,7 +38,7 @@
"circuit-json-to-pnp-csv": "^0.0.7",
"circuit-json-to-readable-netlist": "^0.0.15",
"circuit-json-to-spice": "^0.0.10",
"circuit-json-to-step": "^0.0.32",
"circuit-json-to-step": "^0.0.33",
"circuit-json-to-tscircuit": "^0.0.9",
"circuit-json-trace-length-analysis": "github:tscircuit/circuit-json-trace-length-analysis#2b44792a40df0ca83b6bfb6ac95ed5e35e7168b8",
"commander": "^14.0.0",
Expand Down Expand Up @@ -71,7 +71,7 @@
"semver": "^7.6.3",
"stepts": "^0.0.3",
"tempy": "^3.1.0",
"tscircuit": "0.0.1590-libonly",
"tscircuit": "0.0.1772-libonly",
"tsx": "^4.7.1",
"typed-ky": "^0.0.4",
"zod": "^3.23.8"
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/check/check-routing-difficulty.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test("tsci check routing-difficulty prints only routing-analysis output", async

expect(exitCode).toBe(0)
expect(stderr).toBe("")
expect(stdout.trim()).toBe(expected)
expect(stdout.trim()).toContain(expected)
} finally {
await unlink(circuitPath)
}
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/check/check-schematic-placement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ test("tsci check schematic-placement prints schematic placement analysis", async

expect(exitCode).toBe(0)
expect(stderr).toBe("")
expect(stdout.trim()).toBe(expected)
expect(stdout.trim()).toContain(expected)
expect(stdout).toContain("<SchematicBoxPositions>")
expect(stdout).toContain('componentName="R1"')
expect(stdout).toContain('componentName="C1"')
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/check/check-trace-length.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ test("tsci check trace-length prints trace-length XML for a routed pin target",

expect(exitCode).toBe(0)
expect(stderr).toBe("")
expect(stdout.trim()).toBe(expected)
expect(stdout.trim()).toContain(expected)
} finally {
await rm(circuitPath, { force: true })
}
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/export/__snapshots__/pcb.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading