tracer-sh 0.2.5 → 0.2.8

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/bin/tracer.mjs CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from "node:child_process";
4
+ import { existsSync, readdirSync, statSync } from "node:fs";
4
5
  import { fileURLToPath } from "node:url";
5
- import { dirname, resolve } from "node:path";
6
+ import { dirname, join, resolve } from "node:path";
6
7
 
7
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const serverPath = resolve(__dirname, "../packages/server/dist/index.js");
9
+ const repoRoot = resolve(__dirname, "..");
10
+ const serverPath = resolve(repoRoot, "packages/server/dist/index.js");
9
11
 
10
12
  // Must match RESTART_EXIT_CODE in packages/server/src/updater.ts
11
13
  const RESTART_EXIT_CODE = 75;
@@ -76,6 +78,82 @@ const banner = `
76
78
 
77
79
  console.log(banner);
78
80
 
81
+ ensureFreshBuild();
82
+
83
+ /**
84
+ * Source checkouts (git clone / npm link) serve whatever was last built into
85
+ * packages/*\/dist, which silently goes stale after a pull or local commit —
86
+ * the version number updates but the running code doesn't. Detect that here
87
+ * and rebuild before starting the server. Published npm installs ship only
88
+ * prebuilt dist (no src/), so this is a no-op for them.
89
+ */
90
+ function ensureFreshBuild() {
91
+ if (process.env.TRACER_SKIP_BUILD) return;
92
+ const isSourceCheckout = existsSync(join(repoRoot, "packages/server/src"));
93
+ if (!isSourceCheckout) return;
94
+
95
+ const distEntries = [
96
+ join(repoRoot, "packages/shared/dist"),
97
+ serverPath,
98
+ join(repoRoot, "packages/web/dist/index.html"),
99
+ ];
100
+ const missingDist = distEntries.some((p) => !existsSync(p));
101
+
102
+ // Compare the newest source/config mtime against the oldest build output:
103
+ // if anything was edited after the last full build, the dist is stale.
104
+ const sourceInputs = [
105
+ join(repoRoot, "package.json"),
106
+ join(repoRoot, "pnpm-lock.yaml"),
107
+ ...["shared", "server", "web"].flatMap((p) => [
108
+ join(repoRoot, `packages/${p}/src`),
109
+ join(repoRoot, `packages/${p}/package.json`),
110
+ ]),
111
+ join(repoRoot, "packages/web/index.html"),
112
+ join(repoRoot, "packages/web/vite.config.ts"),
113
+ ];
114
+ const stale = missingDist
115
+ || newestMtime(sourceInputs) > Math.min(...distEntries.map((p) => newestMtime([p])));
116
+ if (!stale) return;
117
+
118
+ console.log(missingDist
119
+ ? "No build found for this source checkout — building..."
120
+ : "Source has changed since the last build — rebuilding...");
121
+
122
+ const run = (args) => spawnSync("pnpm", args, {
123
+ cwd: repoRoot,
124
+ stdio: "inherit",
125
+ shell: process.platform === "win32", // pnpm is pnpm.cmd on Windows
126
+ }).status === 0;
127
+ const built = (run(["install", "--frozen-lockfile"]) || run(["install"])) && run(["build"]);
128
+
129
+ if (!built) {
130
+ if (missingDist) {
131
+ console.error("\nBuild failed and no previous build exists. Fix the build and retry, or run `pnpm build` manually.");
132
+ process.exit(1);
133
+ }
134
+ console.error("\nWARNING: rebuild failed — starting the PREVIOUS build, which does not include your latest changes.");
135
+ console.error("Run `pnpm build` manually to see the error.\n");
136
+ }
137
+ }
138
+
139
+ /** Newest mtime (ms) across files and directories (recursive, skipping build output). */
140
+ function newestMtime(paths) {
141
+ let newest = 0;
142
+ for (const p of paths) {
143
+ let st;
144
+ try { st = statSync(p); } catch { continue; }
145
+ if (st.isDirectory()) {
146
+ for (const entry of readdirSync(p, { withFileTypes: true })) {
147
+ if (entry.name === "node_modules" || entry.name === "dist") continue;
148
+ newest = Math.max(newest, newestMtime([join(p, entry.name)]));
149
+ }
150
+ } else {
151
+ newest = Math.max(newest, st.mtimeMs);
152
+ }
153
+ }
154
+ return newest;
155
+ }
156
+
79
157
  // Restart loop: if server exits with code 75, it means an update was applied
80
158
  while (true) {
81
159
  const result = spawnSync(process.execPath, [serverPath], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracer-sh",
3
- "version": "0.2.5",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "description": "Local-first debugging & analysis platform",
6
6
  "license": "SEE LICENSE IN LICENSE",