cmdzero 0.8.4 → 0.8.5

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/resolver.js +18 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdzero",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Tweak your UI live in the browser and write the changes straight to source. Copy and Tailwind edits cost zero tokens; everything else routes to a right-sized model via headless claude.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/resolver.js CHANGED
@@ -18,25 +18,32 @@ function walk(node, cb) {
18
18
  }
19
19
  }
20
20
 
21
- /** loc format: "<relative file>:<line 1-based>:<col 0-based>" (matches the babel stamp) */
21
+ /**
22
+ * loc format: "<file>:<line 1-based>:<col 0-based>" (matches the babel stamp).
23
+ *
24
+ * The file arrives in one of three shapes, depending on who stamped it: the
25
+ * babel plugin emits a root-relative path, and the @cmdzero/react dev runtime
26
+ * passes on whatever the bundler handed jsxDEV — absolute under webpack, but
27
+ * "[project]/components/Foo.tsx" under Turbopack. Normalize that prefix away
28
+ * here, at the boundary every caller shares: /api/nl parses locs itself and
29
+ * resolves them straight against the root, so normalizing further in (say, in
30
+ * loadTarget) leaves that lane reaching for <root>/[project]/... and dying on
31
+ * ENOENT while the copy and style lanes look fine.
32
+ */
22
33
  export function parseLoc(loc) {
23
34
  const m = /^(.*):(\d+):(\d+)$/.exec(loc);
24
35
  if (!m) throw new Error(`bad loc: ${loc}`);
25
- return { file: m[1], line: Number(m[2]), col: Number(m[3]) };
36
+ return { file: m[1].replace(/^\[project\]\//, ''), line: Number(m[2]), col: Number(m[3]) };
26
37
  }
27
38
 
28
39
  export function loadTarget(root, loc) {
29
40
  const parsed = parseLoc(loc);
30
41
  const { line, col } = parsed;
31
- // Stamps come from three sources: the babel plugin (root-relative path,
32
- // 0-based column) and the @cmdzero/react dev runtime (1-based column), which
33
- // reports whatever the bundler handed jsxDEV an absolute path under
34
- // webpack, but "[project]/..." under Turbopack. Normalize the path and match
35
- // either column convention.
36
- const raw = parsed.file.replace(/^\[project\]\//, '');
37
- // Resolve before the escape check: the guard has to see a normalized path,
38
- // or a "foo/../../.." stamp walks straight past a leading-".." test.
39
- const file = path.relative(root, path.resolve(root, raw));
42
+ // parseLoc has already normalized the path's shape; columns still come in two
43
+ // conventions (babel 0-based, the dev runtime 1-based) and are matched below.
44
+ // Resolve before the escape check: the guard has to see a normalized path, or
45
+ // a "foo/../../.." stamp walks straight past a leading-".." test.
46
+ const file = path.relative(root, path.resolve(root, parsed.file));
40
47
  if (file.startsWith('..') || path.isAbsolute(file)) {
41
48
  throw new Error('file outside root');
42
49
  }