@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 +147 -0
- package/README.md +13 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
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
|
|
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
|
|
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
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"hasInstallScript": true,
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"name": "@akesson/figma-explorer",
|
|
26
|
-
"version": "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.
|
|
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.
|
|
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.
|
|
102
|
+
"version": "0.2.0",
|
|
103
103
|
"volta": {
|
|
104
104
|
"node": "18.14.1",
|
|
105
105
|
"npm": "9.5.0"
|