@akesson/figma-explorer 0.1.0 → 0.2.0

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/CHANGELOG.md CHANGED
@@ -7,8 +7,100 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2026-07-29
11
+
10
12
  ### Added
11
13
 
14
+ - **Web-search query syntax for `find`** — the syntax every agent already
15
+ knows from Google/GitHub: bare words stay fuzzy tokens with implicit AND
16
+ (unchanged); `"quoted phrases"` require the exact contiguous text
17
+ (case-insensitive) — the lane for hunting rendered copy like
18
+ `find '"Approved by you"'`; uppercase `OR` alternates adjacent terms
19
+ (`a b OR c` = a AND (b OR c)); `-term` / `-"phrase"` exclude any chain
20
+ containing them; uppercase `AND` is accepted as a no-op. Lowercase
21
+ `or`/`and` remain ordinary tokens, and mid-word hyphens (`night-shift`)
22
+ stay literal. Exact-phrase hits score above same-length fuzzy matches, so
23
+ copy searches rank the real thing first. Note the shell eats outer
24
+ quotes: write `find '"exact phrase" context'`.
25
+
26
+ - `cache status` — offline report of what the cache holds: per-file rows
27
+ (synth id, name, key, project, payload age, node count) with sidecar
28
+ presence/age for full/comments/variables, plus totals, team-catalog state,
29
+ and mark count. Ends agents introspecting the cache directory by hand (and
30
+ getting it wrong).
31
+ - `node-info` now emits a ready-made figma.com `url:` — on the `target` block
32
+ for node targets (deep link with `node-id=`) and on every `file` block —
33
+ so reports can link straight into Figma without hand-assembling URLs from
34
+ the raw `key`.
35
+ - `--only` now works on **file** targets too: `meta` (just the counts),
36
+ `pages`, `component`, `styles`, `variables`, `comments` filter the file
37
+ summary. Node-only sections on a file target (and the new `pages` section
38
+ on a node target) are rejected with a hint instead of silently emitting
39
+ nothing.
40
+
41
+ - **Marks** — a curated keyword→node database (`mark add`/`rm`/`list`, and a new
42
+ `mark:<key>` id). Once you've positively identified a node, `mark add <key>
43
+ <ID> [--alias …] [--note …]` writes the mapping down so the expensive
44
+ discovery never repeats. `find` and `library search` now fold matching marks
45
+ in **ahead of** their own hits, so a query in *your* vocabulary ("leave
46
+ tooltip") surfaces the node even when no layer name matches. `mark:<key>`
47
+ resolves like the underlying node, so `node-info mark:k`, `screenshot mark:k`,
48
+ and `--in mark:k` work transparently; a multi-node mark lists its paste-ready
49
+ ids so you can pick one. Marks live in `<cache-root>/marks.json` (beside
50
+ `synth.json`) and **survive `cache clear`**. Each mark node carries a stamp of
51
+ the node's name + ancestor path when added, so `mark list` flags drift as
52
+ `[renamed]` / `[moved]` / `[gone]` / `[uncached]` rather than silently
53
+ pointing at a node the design moved out from under.
54
+ - `find` now matches a node's **visible text**, not just its layer name. TEXT
55
+ content (`characters`) is captured into the structural cache (truncated to
56
+ 160 chars) so a query like `leave details` finds the button whose layer is
57
+ named "Button Label" but whose copy reads "Leave details". Text-lane matches
58
+ render a `text:"…"` snippet line under the hit (JSON: `text_matches`), and
59
+ unnamed TEXT nodes with copy are now searchable. This bumps
60
+ `CACHE_SCHEMA_VERSION` to 2 — existing caches silently refetch on next
61
+ access; under `--cache-only`, run `cache prefetch` once first.
62
+ - `comments <ID> --grep <PATTERN>` — case-insensitive substring filter over
63
+ thread head + reply messages. Composes with `--unresolved`/`--since`/
64
+ `--limit`; the header reports `# N of M threads match "<pattern>"` (JSON
65
+ summary gains `grep`).
66
+ - `find` now surfaces a comment-mention hint: after the search it reports
67
+ which searched files discuss the query in their comment threads
68
+ (`# N comment threads mention "tooltip" — try: comments file:15 --grep
69
+ "tooltip"`, capped at 3 files; JSON: `comment_mentions`). A name-search
70
+ miss often lands in the designers' discussion, which is written in user
71
+ vocabulary — this closes that dead end.
72
+ - `ls --comments` — restore the pre-diet inline comment thread rows. By
73
+ default `ls` now summarizes comments (see Changed).
74
+ - `comments <ID>` — list every comment thread in a file (replies inline,
75
+ sorted newest-activity-first, full message text), threads anchored under a
76
+ node subtree, or one thread by `file:N:comm:M`. Filters: `--unresolved`,
77
+ `--since <ISO8601>` (prefix-friendly, matches head or reply activity),
78
+ `--limit N`. `--refresh` re-fetches a single file's comments — no full
79
+ `cache prefetch` needed. Previously only `node-info` exposed comments,
80
+ capped at 10 recent threads.
81
+ - `node-info` file targets now sort `recent_comments` newest-first (was:
82
+ API order) and add a `comments_hint` pointing at `comments file:N` when
83
+ more threads exist than the summary shows.
84
+ - `node-info --only <sections>` — restrict output to named sections
85
+ (`fills,strokes,effects,geometry,corner,layout,text,component,prototype,meta,styles,variables,comments`)
86
+ instead of piping the full dump through grep. Identity (id/type/name) is
87
+ always emitted; the hoisted top-level `variables`/`styles_index` blocks
88
+ keep exactly the entries referenced by kept sections. `--only prototype`
89
+ and `--only meta` imply those opt-in sections.
90
+ - `ls --name <PATTERN>` — case-insensitive substring filter over node names.
91
+ Matches keep their ancestor rail for tree context; other branches are
92
+ pruned; root/project listings drop files/projects with no matches inside
93
+ (unless their own name matches). A `# name filter "…": N matches` line
94
+ (JSON: `name_filter` object) makes the filtering visible.
95
+ - `find` now prints `# searched N cached files` on unscoped runs (JSON:
96
+ `searched_files`) — cross-file search has always been the no-`--in`
97
+ default, but nothing said so; help text and docs now do, and zero-match
98
+ runs are no longer silent.
99
+ - `FIGMA_TOKEN` (and any other env) now falls back to a global
100
+ `$XDG_CONFIG_HOME`-or-`~/.config/figma-explorer/.env`, loaded after the
101
+ cwd-upward `.env` walk (lowest priority). Covers git worktrees that don't
102
+ see the canonical checkout's `.env`.
103
+
12
104
  - `library search <query>` — fuzzy text search across a team's published
13
105
  design-system catalog (components, component sets, and styles). Each hit
14
106
  reports the component/style key and a paste-ready `file:N:x:y` id when the
@@ -22,9 +114,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
22
114
  - `FIGMA_TEAM_ID` environment variable (also `--team-id`), consumed by
23
115
  `library search` and the `cache prefetch` catalog warm.
24
116
 
117
+ ### Changed
118
+
119
+ - Root `ls` (no ID) now defaults to depth 1 — projects + files only — instead
120
+ of descending into every file's canvases/frames. A full workspace dump
121
+ measured ~237KB; the shallow default is ~2KB with a `# depth 1 …` hint on
122
+ how to descend (`ls file:N`, `ls proj:N`, or `--depth 2`). Explicit
123
+ `--depth` is unchanged; every non-root target still defaults to depth 3.
124
+ JSON root output is also depth 1 by default now — pass `--depth 3` for the
125
+ old shape.
126
+ - `ls` now summarizes comments by default instead of interleaving every
127
+ thread: a node with anchored threads shows a `[N comments]` suffix, and
128
+ file targets get a `# N comment threads (M unresolved) — use: comments
129
+ file:N …` header. Pass `--comments` for the old inline rows. Because the
130
+ filter now applies to those rows, `--resolved` requires `--comments`. JSON
131
+ output is unchanged (full comment arrays regardless).
132
+ - `library search` now distinguishes strong from weak fuzzy matches: when any
133
+ hit clears ~85% of the query's self-score, only strong hits show (with a
134
+ `# N weaker matches hidden` line); when none do, it prints `# no strong
135
+ match for "<q>"` and lists a few `(weak)`-labeled leads instead of ranking
136
+ subsequence junk as if it were relevant. JSON hits gain `strong`; the
137
+ envelope gains `no_strong_match`/`self_score`.
138
+
25
139
  ### Fixed
26
140
 
141
+ - Piping any command into a reader that closes early (`figma-explorer ls … |
142
+ head`) no longer panics with `failed printing to stdout: Broken pipe (os
143
+ error 32)`. The Rust runtime ignores `SIGPIPE` at startup, which turned a
144
+ broken pipe into a `println!` panic (exit 101); both binaries now restore the
145
+ default disposition so the process ends quietly (exit 141) like a normal Unix
146
+ CLI. Matters most for agents, which pipe through `head`/`grep` constantly.
147
+ - `--cache-only` is now enforced by the live-fetch commands (`tokens`,
148
+ `screenshot`, `assets`, `context`). Previously the flag was honored only
149
+ during id resolution, then the mandatory step-2 live fetch proceeded anyway —
150
+ so `--cache-only tokens …` silently hit the network. These commands cannot be
151
+ served offline (they need fills/strokes/type styles or the `/images` API), so
152
+ they now bail up front with a clear message, matching `comments --refresh`.
153
+ - Root `ls` on a cache with no files (fresh, or just cleared) now prints a
154
+ `no cached files — run … cache prefetch …` nudge (and a `hint` key in
155
+ `--json`) instead of only the depth hint, which gave no clue the cache needed
156
+ populating.
157
+ - Instance-descendant node ids (`I880:3606;2816:36646`) are now accepted
158
+ everywhere an id is: qualified (`file:7:I880:3606;2816:36646`), bare (with
159
+ `--in`), and in figma.com URLs (`node-id=I880-3606%3B2816-36646`).
160
+ Previously `ls`/`node-info` printed these ids but the parser rejected them
161
+ ("node part is not NUM:NUM"), so the CLI's own output couldn't be pasted
162
+ back into `node-info`/`screenshot`.
163
+ - Tagged file/node targets (`file:N`, `file:N:x:y`) now cold-fetch a missing
164
+ or evicted cache entry instead of dead-ending with "nothing cached … (no
165
+ meta on disk)", matching the URL lane's behavior. Under `--cache-only` the
166
+ miss reports the standard remedy hint instead. The residual disk-only error
167
+ message now also names `cache prefetch` and the URL alternative.
27
168
  - `cache clear` (without `--file-key`) swept only the `files/` directory,
28
169
  silently leaving other cache state on disk; it now also clears the
29
170
  team-catalog sidecars under `teams/`. The command's help text overstated its
30
171
  scope and has been corrected.
172
+ - A cached payload written under an older `CACHE_SCHEMA_VERSION` now resolves as
173
+ a cache miss (→ live refetch, or a clean `--cache-only` miss) instead of a
174
+ hard "cache schema version mismatch" internal error. The version check
175
+ already promised silent refetch, but the tagged file/node resolve lane
176
+ mapped the mismatch to an internal error — so a schema bump would have
177
+ dead-ended every synth-id lookup until a manual `cache clear`.
package/README.md CHANGED
@@ -4,14 +4,16 @@ A command-line tool for navigating, inspecting, and exporting from Figma files v
4
4
 
5
5
  ## What it does
6
6
 
7
- - **`ls`** / **`find`** — navigate projects, files, and node trees by name without copy-pasting node ids.
8
- - **`node-info`** — single-target view with layout, fills, strokes, effects, text, bound variables, and comments. Designed to be pasted into an agent prompt.
7
+ - **`ls`** / **`find`** — navigate projects, files, and node trees by name or visible text without copy-pasting node ids. `find` speaks web-search syntax: `"exact phrases"`, uppercase `OR`, `-exclusion`.
8
+ - **`node-info`** — single-target view with layout, fills, strokes, effects, text, bound variables, comments, and a ready-made figma.com `url:`. Designed to be pasted into an agent prompt.
9
+ - **`comments`** — list a file's comment threads (replies inline, newest first), threads under a node, or a single thread; filter with `--unresolved` / `--since` / `--grep`.
10
+ - **`mark`** — curated keyword→node bookmarks (`mark add key file:N:x:y --alias …`); `find` and `library search` surface matching marks ahead of their own hits, and `mark:key` resolves anywhere an id is accepted.
9
11
  - **`library search`** — fuzzy search across a team's published component library (components, component sets, styles).
10
12
  - **`screenshot`** — export a node as PNG / JPG / SVG / PDF.
11
13
  - **`tokens`** — extract design tokens (colors, fonts, sizes, spacing).
12
14
  - **`assets`** — bulk-export every icon/image below a node.
13
15
  - **`context`** — aggregate: tree + screenshot + tokens + assets for a node.
14
- - **`cache prefetch`** — pre-warm a local cache so subsequent commands are offline-fast.
16
+ - **`cache prefetch`** / **`cache status`** — pre-warm a local cache so subsequent commands are offline-fast, and report what it holds (per-file age, sidecars, catalog) without touching the network.
15
17
 
16
18
  All commands share a tagged-id grammar — `proj:N`, `file:N`, `file:N:x:y`, or a full `figma.com` URL — so you never paste raw node identifiers by hand.
17
19
 
@@ -61,7 +63,7 @@ Optional environment variables:
61
63
  - `FIGMA_TEAM_ID` — needed by `library search` and for the catalog warm in `cache prefetch`.
62
64
  - `FIGMA_EXPLORER_CACHE_DIR` — override the cache location (default: OS cache dir).
63
65
 
64
- A `.env` file in the current directory (or any ancestor up to root) is auto-loaded.
66
+ A `.env` file in the current directory (or any ancestor up to root) is auto-loaded, with `~/.config/figma-explorer/.env` as the global fallback — handy for git worktrees and directories with no `.env` in their ancestry. Exported environment variables always win.
65
67
 
66
68
  ## Quickstart
67
69
 
@@ -73,7 +75,13 @@ figma-explorer ls
73
75
  figma-explorer ls proj:1
74
76
  figma-explorer ls file:2
75
77
 
76
- # Find a node by name within the current scope
78
+ # Find a node by name across every cached file
79
+ figma-explorer find "Button / Primary"
80
+
81
+ # Hunt rendered copy with an exact phrase (single-quote so the shell keeps the double quotes)
82
+ figma-explorer find '"Approved by you"'
83
+
84
+ # ...or scope the search to one file
77
85
  figma-explorer --in file:2 find "Button / Primary"
78
86
 
79
87
  # Get implementation-ready info for one node
@@ -23,7 +23,7 @@
23
23
  "hasInstallScript": true,
24
24
  "license": "MIT",
25
25
  "name": "@akesson/figma-explorer",
26
- "version": "0.1.0"
26
+ "version": "0.2.0"
27
27
  },
28
28
  "node_modules/@isaacs/cliui": {
29
29
  "engines": {
@@ -542,5 +542,5 @@
542
542
  }
543
543
  },
544
544
  "requires": true,
545
- "version": "0.1.0"
545
+ "version": "0.2.0"
546
546
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "artifactDownloadUrls": [
3
- "https://github.com/akesson/figma-explorer/releases/download/v0.1.0"
3
+ "https://github.com/akesson/figma-explorer/releases/download/v0.2.0"
4
4
  ],
5
5
  "bin": {
6
6
  "figma-explorer": "run-figma-explorer.js"
@@ -99,7 +99,7 @@
99
99
  "zipExt": ".tar.xz"
100
100
  }
101
101
  },
102
- "version": "0.1.0",
102
+ "version": "0.2.0",
103
103
  "volta": {
104
104
  "node": "18.14.1",
105
105
  "npm": "9.5.0"