@smallpen/cli 0.1.0-alpha.5 → 0.1.0-alpha.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/command-contract.mjs +1416 -0
- package/bin/command-tree.mjs +512 -0
- package/bin/design-output.mjs +1039 -0
- package/bin/help-topics.mjs +241 -0
- package/bin/help.mjs +379 -478
- package/bin/read-output.mjs +219 -0
- package/bin/result-files.mjs +232 -0
- package/bin/reuse-advice.mjs +73 -0
- package/bin/schema.mjs +607 -152
- package/bin/smallpen.mjs +4185 -1330
- package/bin/warning-output.mjs +2 -2
- package/bin/windows-artifacts.mjs +72 -0
- package/bin/workflow.mjs +55 -0
- package/package.json +3 -3
package/bin/help.mjs
CHANGED
|
@@ -1,69 +1,124 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
[
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
["
|
|
19
|
-
["effective-token", "Resolve one Effective Token"],
|
|
20
|
-
["explain-token", "Explain one Effective Token resolution decision"],
|
|
21
|
-
["render", "Render the selected Design View to deterministic PNG"],
|
|
22
|
-
["inspect-view", "Return wireframe, semanticTree, optional image, and supporting context"],
|
|
23
|
-
["render-matrix", "Render multiple design contexts for AI comparison"],
|
|
24
|
-
["evidence", "Return PNG plus deterministic review evidence; --output exports files"],
|
|
25
|
-
["import-draft", "Import Figma clipboard, SVG, or PNG as a separate Draft file"],
|
|
26
|
-
["import-media", "Import binary Media (PNG/JPEG/GIF/WebP/SVG) into a Product Asset Library"],
|
|
27
|
-
["remove-media", "Remove an imported Media descriptor from the Asset Library"],
|
|
28
|
-
["import-font", "Import a TTF/OTF/WOFF font and convert SFNT to WOFF"],
|
|
29
|
-
["import-tokens", "Review and import a DTCG / Tokens Studio token file into the Token Library"],
|
|
30
|
-
["library-refresh", "Re-fetch a declared URL Library into its verified cache"],
|
|
31
|
-
["draft-diff", "Compare two independent Draft files without changing Canonical"],
|
|
32
|
-
["draft-compile", "Compile selected Draft fields into a current-revision batch"],
|
|
33
|
-
["flow", "Create flowchart nodes from a declarative intent"],
|
|
34
|
-
["page", "Create page nodes from a declarative intent"],
|
|
35
|
-
["token", "Apply declarative Token operations atomically"],
|
|
36
|
-
["impact", "Find every node and component using a Token"],
|
|
37
|
-
["apply", "Atomically apply one typed Operation Batch"],
|
|
38
|
-
["watch", "Emit NDJSON revision events for local external changes"],
|
|
39
|
-
["repair", "Inspect or execute one explicit Repair choice"],
|
|
1
|
+
import {
|
|
2
|
+
COMMAND_CONTRACTS,
|
|
3
|
+
commandContract,
|
|
4
|
+
commandHelp,
|
|
5
|
+
} from "./command-contract.mjs";
|
|
6
|
+
import { commandOverview, printBriefHelp } from "./help-topics.mjs";
|
|
7
|
+
import { printText } from "./result-files.mjs";
|
|
8
|
+
import { COMMAND_GROUPS, publicArgv } from "./command-tree.mjs";
|
|
9
|
+
|
|
10
|
+
const COMMANDS = Object.entries(COMMAND_CONTRACTS).map(
|
|
11
|
+
([name, { purpose }]) => [name, purpose],
|
|
12
|
+
);
|
|
13
|
+
// What help lists: every grouped action and the shared commands.
|
|
14
|
+
const PUBLIC_PATHS = [
|
|
15
|
+
...Object.entries(COMMAND_GROUPS).flatMap(([group, { actions }]) =>
|
|
16
|
+
Object.entries(actions).map(([action, { purpose }]) => [`${group} ${action}`, purpose]),
|
|
17
|
+
),
|
|
18
|
+
...["view", "changes", "export", "validate", "help", "schema", "version"].map((name) => [name, COMMAND_CONTRACTS[name].purpose]),
|
|
40
19
|
];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
--context AXIS=VALUE Repeatable finite Context selection`;
|
|
20
|
+
// Help texts are kept per engine; they print with the grouped path a caller
|
|
21
|
+
// types ("smallpen apply" reads "smallpen advanced apply").
|
|
22
|
+
const publicName = (name) => publicArgv([name]).join(" ");
|
|
23
|
+
const publicText = (text) =>
|
|
24
|
+
text.replace(/\b(smallpen|SmallPen) ([a-z][a-z-]*)/g, (match, word, name) =>
|
|
25
|
+
Object.hasOwn(COMMAND_CONTRACTS, name) ? `${word} ${publicName(name)}` : match);
|
|
48
26
|
|
|
49
27
|
const WRITE_REPLY = `Reply size:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
28
|
+
Default: batchId, revision, changed/alreadyApplied/dryRun, counts, warnings,
|
|
29
|
+
and summary. changeReportPath records exact before/after values. reverseEdit
|
|
30
|
+
describes an explicit new write at the confirmed revision; inverseBatchPath
|
|
31
|
+
locates its JSON. This does not rewind history. --inverse-out FILE chooses a
|
|
32
|
+
durable caller-owned file (only when the batch commits). --compact is default.
|
|
33
|
+
--full includes inverseBatch, guidance, and exact before/after diff values.
|
|
34
|
+
After later edits, read current values and restore intended fields in a new
|
|
35
|
+
scoped edit. Never force an old snapshot by replacing its baseRevision.
|
|
36
|
+
For safe retries choose batchId before the first call and reuse it with the
|
|
37
|
+
same input. The local ledger retains at most 500 batch identities.
|
|
38
|
+
smallpen apply PACKAGE --batch FILE --inverse-out FILE.reverse.json`;
|
|
59
39
|
|
|
60
40
|
const HELP = {
|
|
41
|
+
assets: `Usage:
|
|
42
|
+
smallpen advanced style list PACKAGE [--kind colors|typographies]
|
|
43
|
+
[--limit N] [--offset N] [--json]
|
|
44
|
+
|
|
45
|
+
Read the App's stored color and typography assets. Use token for design values
|
|
46
|
+
and token theme for their options and defaults. File assets are managed through
|
|
47
|
+
asset media and asset font. Write styles in their owning package.`,
|
|
48
|
+
help: `Usage:
|
|
49
|
+
smallpen help [OBJECT [GROUP] [ACTION]|rules [TOPIC]] [--json]
|
|
50
|
+
|
|
51
|
+
Use COMMAND --help for options, or schema for JSON input shapes. Use help rules for shared operation rules; schema command OBJECT ACTION
|
|
52
|
+
describes one command at a time.`,
|
|
53
|
+
themes: `Usage:
|
|
54
|
+
smallpen token theme list PACKAGE [--theme GROUP/NAME]... [--json]
|
|
55
|
+
|
|
56
|
+
Read project-defined groups, options (named Group/Option), defaults and this
|
|
57
|
+
call's selection. This is a lightweight settings query, with no Token inventory.
|
|
58
|
+
selection and option active flags mean this command's parameters and defaults,
|
|
59
|
+
never a previous CLI call. The stored App selection is unrelated to this query
|
|
60
|
+
and omitted by default; --full includes appSelection for explicit inspection.
|
|
61
|
+
It never supplies the CLI defaults.
|
|
62
|
+
No --theme uses project defaults; App current selection is independent.
|
|
63
|
+
--theme overrides only named groups. No data or App state is written.
|
|
64
|
+
Write: token theme add|rename|default|delete --theme Group/Option.`,
|
|
65
|
+
view: `Usage:
|
|
66
|
+
smallpen view PACKAGE [what] [--as text|wireframe|png|issues] [--theme G/O]...
|
|
67
|
+
|
|
68
|
+
Look at anything by name; no IDs. What:
|
|
69
|
+
(nothing) the whole package: themes, Tokens, components, pages
|
|
70
|
+
--tokens | --token color every Token, or those under a name
|
|
71
|
+
--components every component
|
|
72
|
+
--component Button one component: every variant
|
|
73
|
+
[--variant "Style=secondary"] [--element Label] one variant, one part of it
|
|
74
|
+
--pages [--platform mobile] every page
|
|
75
|
+
--page Board one page ("Board" or "Tasks / Board")
|
|
76
|
+
[--platform mobile] [--element "Top bar"] one version, one part of it
|
|
77
|
+
--as text (default) is a compact outline; wireframe is a text drawing of regions;
|
|
78
|
+
png writes an image (inspect it only if you can see images); issues lists layout,
|
|
79
|
+
text and contrast problems by element. Tokens have text, wireframe and png.
|
|
80
|
+
--theme Group/Option shows values under that option for this call only.
|
|
81
|
+
Large results go to a file. Unknown names fail with the names that exist;
|
|
82
|
+
"Name [2]" picks one of a name stored twice.
|
|
83
|
+
Next: changes PACKAGE --since REVISION after someone edits the design.`,
|
|
84
|
+
"token-export": `Usage:
|
|
85
|
+
smallpen token export PACKAGE [--type TYPE] [--token PREFIX] [--by GROUP]
|
|
86
|
+
[--format json|flat] [--theme G/O]... [--output DIR] [--json]
|
|
87
|
+
|
|
88
|
+
Export resolved Token values as JSON. --by GROUP writes one file
|
|
89
|
+
per option of that theme group, named after the option (--type string
|
|
90
|
+
--by Language with options English and Chinese -> English.json, Chinese.json);
|
|
91
|
+
without it one file, tokens.json, holds the values of the selected themes
|
|
92
|
+
(project defaults, or --theme). json nests by name
|
|
93
|
+
(text.task.new -> {"text":{"task":{"new":...}}}); flat keeps one key per name.
|
|
94
|
+
Other groups use the project defaults or --theme.`,
|
|
95
|
+
changes: `Usage:
|
|
96
|
+
smallpen changes PACKAGE [--since REVISION] [--limit N] [--full] [--json]
|
|
97
|
+
|
|
98
|
+
What changed since a revision you saw, by name: themes, Tokens (with values),
|
|
99
|
+
components (per variant and element) and pages (per platform and element),
|
|
100
|
+
including edits a person made in the App. Every read and write reports a
|
|
101
|
+
revision; keep the latest one and pass it as --since to align code with the
|
|
102
|
+
design. Without --since: the most recent edits, who made them (app or cli) and
|
|
103
|
+
the revision before each. --full adds the structured list. Nothing is stored
|
|
104
|
+
for the caller.`,
|
|
105
|
+
export: `Usage:
|
|
106
|
+
smallpen export PACKAGE [--page P [--platform X] [--element E]]
|
|
107
|
+
[--component C [--variant V] [--element E]] [--design-system]
|
|
108
|
+
[--format text|wireframe|png] [--output FILE] [--scale N] [--json]
|
|
109
|
+
|
|
110
|
+
Save a page, component or region as a text wireframe (default) or a PNG file,
|
|
111
|
+
named the way view names it. Nothing named is the main page. Request PNG with
|
|
112
|
+
--format png; read text and wireframes first, and inspect PNG only when the
|
|
113
|
+
caller can see images. Text files contain LF newlines and alignment spaces.
|
|
114
|
+
Missing --output uses a temporary file. Returns path, hash, bytes, target,
|
|
115
|
+
themes and revisions. --design-system exports the generated Token/component
|
|
116
|
+
page; do not draw a copy. --evidence adds review evidence to a page PNG.`,
|
|
61
117
|
version: `Usage:
|
|
62
|
-
smallpen --version
|
|
63
118
|
smallpen version [--json]
|
|
64
119
|
|
|
65
120
|
Output:
|
|
66
|
-
|
|
121
|
+
JSON {name,version} for the installed CLI package.
|
|
67
122
|
No package path is required; design files are unchanged and no services start.`,
|
|
68
123
|
schema: `Usage:
|
|
69
124
|
smallpen schema [TOPIC] [--json]
|
|
@@ -76,209 +131,137 @@ Purpose:
|
|
|
76
131
|
example is tested against a workspace made by smallpen init.
|
|
77
132
|
|
|
78
133
|
Topics:
|
|
134
|
+
command NAME one command: parameters, types, defaults and constraints
|
|
135
|
+
commands command names and purposes
|
|
79
136
|
operations every operation type, its purpose, Package, required fields
|
|
80
|
-
operation TYPE one operation in full
|
|
137
|
+
operation TYPE one operation in full
|
|
81
138
|
batch batch contract, Foundation vs Product, worked example
|
|
82
139
|
node node fields, textStyle, tokenBindings
|
|
83
140
|
node-types what each node type requires
|
|
84
|
-
token
|
|
141
|
+
token Tokens in token sets, DTCG files, bindings
|
|
142
|
+
theme token sets and themes, --theme, Foundation + Product themes
|
|
85
143
|
token-types the value each Token type accepts
|
|
86
144
|
component-set Component Set, Axis roles (configuration, state), variants
|
|
87
145
|
instance INSTANCE nodes and overrides
|
|
88
146
|
presentation Presentation fields, size, and resizing
|
|
89
147
|
screen Screen fields
|
|
90
148
|
scenario Scenario fields and viewport
|
|
91
|
-
context Context Axes
|
|
92
|
-
init
|
|
149
|
+
context Context Axes (viewport, density, locale, ...)
|
|
150
|
+
init blank package paths, layouts and creation behavior
|
|
93
151
|
|
|
94
152
|
Examples:
|
|
95
153
|
smallpen schema operations
|
|
96
154
|
smallpen schema operation update-component-node
|
|
97
155
|
smallpen schema component-set`,
|
|
98
156
|
init: `Usage:
|
|
99
|
-
smallpen init
|
|
100
|
-
[--answer QUESTION_ID=JSON]... [--confirm] [--locale LOCALE] [--json]
|
|
157
|
+
smallpen project init PATH [--name NAME] [--layout single|foundation-product] [--json]
|
|
101
158
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
--state defaults to <workspace-directory>.smallpen-init.json. Answers build up
|
|
109
|
-
only when every call passes the same --state; a call without --state starts
|
|
110
|
-
from no answers (the reply then carries stateNotice).
|
|
111
|
-
--answers FILE answers every question at once: smallpen schema init prints all
|
|
112
|
-
questions and a complete file.
|
|
113
|
-
--locale defaults to the environment (LC_ALL, LC_MESSAGES, LANG): zh* selects
|
|
114
|
-
Chinese labels, anything else English.
|
|
115
|
-
Project kinds: application|motion|custom. Foundation choice: create-new.
|
|
116
|
-
--answer values are JSON (for example projectKind=\"application\").
|
|
159
|
+
Create a blank package immediately. PATH ending in .smallpen creates that
|
|
160
|
+
package; a directory creates a new workspace containing a package. The default
|
|
161
|
+
is one self-contained package with one canvas and Theme/Default, no Tokens,
|
|
162
|
+
components, business flows or platform copies. Existing targets are rejected.
|
|
163
|
+
--layout foundation-product creates two blank packages with a local dependency.
|
|
164
|
+
No business questionnaire, saved selection or initialization state is required.
|
|
117
165
|
|
|
118
166
|
Examples:
|
|
119
|
-
smallpen init ./
|
|
120
|
-
smallpen init ./
|
|
121
|
-
|
|
167
|
+
smallpen project init ./acme.smallpen --name Acme --json
|
|
168
|
+
smallpen project init ./acme --layout foundation-product --json
|
|
169
|
+
|
|
170
|
+
Next: smallpen schema command project init --json`,
|
|
122
171
|
|
|
123
|
-
Output:
|
|
124
|
-
status needs_input returns a stable question id, localized label, schema,
|
|
125
|
-
optional recommendation, and continuation args with an answer placeholder. Replace
|
|
126
|
-
<JSON> with your schema-valid answer; if no recommendation is present, supply the
|
|
127
|
-
project's own purpose, audience, or deliverable. status proposal returns the
|
|
128
|
-
persisted Proposal and confirmation args. Only --confirm creates the packages;
|
|
129
|
-
status initialized returns both package paths plus every id the first writes
|
|
130
|
-
need: packages.{foundation,product}.{packageId,path,revision},
|
|
131
|
-
start.{screenId,presentationId,rootNode,scenarioIds,contextAxes}, and seeded
|
|
132
|
-
(the starter Tokens and Component Sets with ids and paths).
|
|
133
|
-
|
|
134
|
-
Seeded content (from the answers):
|
|
135
|
-
Foundation: each initialTokens name becomes a Token tok_<path with _>, for
|
|
136
|
-
example color.brand -> tok_color_brand (#6750a4), spacing.md -> tok_spacing_md
|
|
137
|
-
(8), radius.md -> tok_radius_md (8). Each initialComponents name becomes a
|
|
138
|
-
Component Set cmp_<name> with one plain variant var_<name>_default, no axes
|
|
139
|
-
(Button -> cmp_button). platforms become Context Axis axis_platform, next to
|
|
140
|
-
your contextAxes. Product: Screen scr_<firstScreen> with Presentation
|
|
141
|
-
pres_<firstScreen>_<platform>, root FRAME node_<firstScreen>_root, and one
|
|
142
|
-
Scenario. put-token or put-component-set with a seeded id replaces it whole.
|
|
143
|
-
|
|
144
|
-
Errors and next commands:
|
|
145
|
-
Malformed --answer JSON identifies the question; schema-invalid values also return
|
|
146
|
-
its schema. Correct the answer and retry with the same --state. After confirming:
|
|
147
|
-
smallpen validate <product.smallpen> --json`,
|
|
148
172
|
validate: `Usage:
|
|
149
|
-
smallpen validate
|
|
173
|
+
smallpen validate PACKAGE [--page P [--platform X] [--element E]]
|
|
174
|
+
[--component C [--variant V] [--element E]] [--design-system]
|
|
175
|
+
[--theme G/O]... [--limit N] [--offset N] [--json]
|
|
150
176
|
|
|
151
177
|
Purpose:
|
|
152
|
-
Validate
|
|
153
|
-
|
|
178
|
+
Validate the stored data, references and the Product/Foundation dependency,
|
|
179
|
+
and check text fit, bounds, overlaps and contrast for the target. A page
|
|
180
|
+
checks every version unless --platform names one; a component every variant
|
|
181
|
+
unless --variant names one. Nothing named checks the main page and lists
|
|
182
|
+
names stored twice.
|
|
154
183
|
|
|
155
184
|
Output:
|
|
156
|
-
status valid
|
|
157
|
-
|
|
185
|
+
status/dataStatus valid means the data and references are valid. Visual
|
|
186
|
+
issues are separate: read visualStatus, issueCount, issues and
|
|
187
|
+
coverage.skipped. Valid data is not visual approval. Issue pagination does
|
|
188
|
+
not shrink coverage. Dependency conflicts return repair_required with exact
|
|
189
|
+
choices. view --as issues gives the same issues by element name.
|
|
158
190
|
|
|
159
191
|
Next:
|
|
160
|
-
smallpen
|
|
161
|
-
smallpen repair <product> --json`,
|
|
192
|
+
smallpen view <package> --as issues --json
|
|
193
|
+
smallpen project repair <product> --json`,
|
|
162
194
|
inspect: `Usage:
|
|
163
195
|
smallpen inspect <package.smallpen> [--json]
|
|
164
196
|
|
|
165
197
|
Purpose:
|
|
166
|
-
Return
|
|
167
|
-
|
|
168
|
-
machine-readable Design System preflight operations.
|
|
198
|
+
Return Package identity, revision, and domain counts. --full includes all
|
|
199
|
+
domain summaries and format capabilities.
|
|
169
200
|
|
|
170
201
|
Next:
|
|
171
|
-
smallpen
|
|
172
|
-
smallpen read-view <package> --json`,
|
|
202
|
+
smallpen view <package> --json`,
|
|
173
203
|
list: `Usage:
|
|
174
204
|
smallpen list <package.smallpen> [--kind KIND] [--offset N] [--limit N] [--json]
|
|
175
205
|
|
|
176
206
|
Values:
|
|
177
207
|
KIND: all|screens|presentations|contexts|tokens|components|scenarios|requirements|flows
|
|
178
|
-
Defaults: kind=all, offset=0, limit=
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
Purpose:
|
|
186
|
-
Return the complete validated Canonical Snapshot used by adapters. Binary blobs are
|
|
187
|
-
not embedded in JSON. Prefer inspect/list/read-view for bounded Agent reads.
|
|
188
|
-
|
|
189
|
-
Next:
|
|
190
|
-
smallpen inspect <package> --json`,
|
|
191
|
-
"read-view": `Usage:
|
|
192
|
-
smallpen read-view <product.smallpen> [selectors] [--offset N] [--limit N]
|
|
193
|
-
[--locale LOCALE] [--json]
|
|
194
|
-
|
|
195
|
-
${VIEW_SELECTORS}
|
|
196
|
-
|
|
197
|
-
Defaults:
|
|
198
|
-
Base Presentation + default Context values + canonical initial state + structure.
|
|
199
|
-
All formats resolve the same selection. --locale defaults to the environment
|
|
200
|
-
(zh* selects Chinese labels, anything else English).
|
|
201
|
-
|
|
202
|
-
Choose a format:
|
|
203
|
-
wireframe A scaled 2D ASCII canvas for fast spatial reasoning, followed by a
|
|
204
|
-
compact marker key with hierarchy, layer type, name, and stable ID.
|
|
205
|
-
semantic Exact machine-readable hierarchy, bounds, text, alignment, resolved
|
|
206
|
-
typography, component references, variants, and Token bindings.
|
|
207
|
-
screenshot Rendered PNG metadata only; use render/evidence for inline pixels,
|
|
208
|
-
or add --output to explicitly write PNG files.
|
|
209
|
-
The PNG image itself is raster pixels only: it has no layer IDs,
|
|
210
|
-
hierarchy, bounds, component references, or Token bindings.
|
|
211
|
-
|
|
212
|
-
Agent guidance:
|
|
213
|
-
Use wireframe or semantic to understand and edit the design. Use PNG to inspect
|
|
214
|
-
high-fidelity color, typography, spacing, effects, and rendering. Use inspect-view
|
|
215
|
-
--include-image when both structural reasoning and visual QA are required.
|
|
208
|
+
Defaults: kind=all, offset=0, limit=20. Return identities and counts, without
|
|
209
|
+
node trees or variants. page includes total/hasMore; --full includes definitions.
|
|
210
|
+
Default item fields follow the public allowlist in schema command list.
|
|
211
|
+
Descriptions and editor root IDs belong to target reads, not this directory.
|
|
212
|
+
Omit visibility=public and deprecated=false. Only report private visibility,
|
|
213
|
+
actual deprecation and a configured replacement when they affect reuse.
|
|
214
|
+
JSON is compact in all modes; --full adds data, not pretty-printing.
|
|
216
215
|
|
|
217
216
|
Next:
|
|
218
|
-
|
|
219
|
-
discover: `Usage:
|
|
220
|
-
smallpen discover <product.smallpen> [selectors] [--offset N] [--limit N]
|
|
221
|
-
[--locale LOCALE] [--json]
|
|
222
|
-
|
|
223
|
-
${VIEW_SELECTORS}
|
|
224
|
-
|
|
225
|
-
Output:
|
|
226
|
-
Exact selector parameters, defaults, finite valid values, localized summaries,
|
|
227
|
-
machine operation/args, copyable commands, and pagination metadata.`,
|
|
217
|
+
Look at one by name: smallpen view <package> --page NAME | --component NAME.`,
|
|
228
218
|
catalog: `Usage:
|
|
229
|
-
smallpen catalog <product.smallpen> [--context AXIS=VALUE]... [--
|
|
219
|
+
smallpen catalog <product.smallpen> [--context AXIS=VALUE]... [--theme GROUP/NAME]...
|
|
220
|
+
[--offset N] [--limit N] [--full] [--json]
|
|
230
221
|
|
|
231
222
|
Purpose:
|
|
232
|
-
|
|
233
|
-
|
|
223
|
+
Return Component identities (limit=20) and domain counts. Use component for one
|
|
224
|
+
candidate's legal selections, tokens/search-tokens for values, or --full for
|
|
225
|
+
the complete Catalog. Token definitions, effective values and inventory are
|
|
226
|
+
not repeated in the default response. Default items use the same public
|
|
227
|
+
discovery fields as list; descriptions require a target read.`,
|
|
234
228
|
"search-components": `Usage:
|
|
235
229
|
smallpen search-components <product.smallpen> --query TEXT [--limit N] [--json]
|
|
236
230
|
|
|
237
231
|
Purpose:
|
|
238
232
|
Find reusable Product, public Foundation, and linked Library components before
|
|
239
233
|
drawing a custom replacement. Matches stable ID, name, category, and description and returns the
|
|
240
|
-
owning Package, source layer,
|
|
234
|
+
owning Package, source layer, variant count, and an executable
|
|
241
235
|
owner-scoped component command (argv plus a POSIX-shell command).
|
|
236
|
+
Default candidates use the public discovery fields; read component for
|
|
237
|
+
descriptions and legal choices. Private reuse restrictions remain explicit.
|
|
242
238
|
|
|
243
239
|
State:
|
|
244
240
|
Every query is explicit and self-contained. It never creates a current component
|
|
245
241
|
or affects a later command.`,
|
|
246
|
-
component: `Usage:
|
|
247
|
-
smallpen component <package.smallpen> --component-id CMP [--json]
|
|
248
|
-
|
|
249
|
-
Purpose:
|
|
250
|
-
Return one exact Component Set, its legal variant selections, replacement metadata,
|
|
251
|
-
and component-targeted Scenarios. This is read-only and uses stable Canonical IDs.
|
|
252
|
-
The package path must identify the owning Package. For inherited components,
|
|
253
|
-
execute the owner-scoped command returned by search-components.
|
|
254
|
-
An HTTP(S) Library URL is also accepted and uses the normal Library cache.
|
|
255
|
-
|
|
256
|
-
Shapes:
|
|
257
|
-
smallpen schema component-set axes (role configuration|state) and variants
|
|
258
|
-
smallpen schema instance place a variant on a Screen and override it
|
|
259
|
-
Edit a variant: {"type":"update-component-node","componentSetId":"cmp_button",
|
|
260
|
-
"variantId":"var_button_primary","nodeId":"node_button_label",
|
|
261
|
-
"changes":{"textStyle":{"textAlign":"center"}}}
|
|
262
|
-
|
|
263
|
-
Next:
|
|
264
|
-
Use a returned selection with read-view or inspect-view to review the design.`,
|
|
265
|
-
compare: `Usage:
|
|
266
|
-
smallpen compare <product.smallpen> --selector JSON --selector JSON
|
|
267
|
-
[--selector JSON] [--selector JSON] [--json]
|
|
268
|
-
|
|
269
|
-
Values:
|
|
270
|
-
Exactly two to four selector objects. Example:
|
|
271
|
-
smallpen compare product.smallpen --selector '{"presentationId":"pres_desktop"}' \\
|
|
272
|
-
--selector '{"presentationId":"pres_mobile"}' --json`,
|
|
273
242
|
tokens: `Usage:
|
|
274
|
-
smallpen tokens <
|
|
243
|
+
smallpen tokens <package.smallpen> [--theme GROUP/NAME]... [--context AXIS=VALUE]...
|
|
244
|
+
[--offset N] [--limit N] [--locale LOCALE] [--full] [--json]
|
|
245
|
+
smallpen tokens <package.smallpen> --definitions [--group GROUP]
|
|
246
|
+
[--offset N] [--limit N] [--full] [--json]
|
|
275
247
|
|
|
276
248
|
Purpose:
|
|
277
|
-
List Effective Tokens
|
|
278
|
-
|
|
249
|
+
List Effective Tokens: the active token sets of the selected themes (a later
|
|
250
|
+
set overrides an earlier one by name; a Product's own sets sit on top of its
|
|
251
|
+
Foundation's), then Context specificity for legacy contextValues. themes[]
|
|
252
|
+
lists every theme with active, owner (package|foundation) and its sets.
|
|
253
|
+
--theme selects themes for this read only (one per group); unknown groups or
|
|
254
|
+
names exit unknown_token_theme with validThemes. labels follow --locale or the
|
|
255
|
+
environment. Default: 20 items with target, Token id/path/type and resolved
|
|
256
|
+
value, plus page.total/hasMore. --full includes every definition and source chain.
|
|
257
|
+
--definitions reads exact stored Tokens in every option Set, with owning
|
|
258
|
+
packageId, setId, group and option. Optional --group filters the App Set group.
|
|
259
|
+
Missing cells have no item; they do not inherit Default. This mode cannot take
|
|
260
|
+
--theme or --context. Use the ordinary tokens read to resolve a combination.`,
|
|
279
261
|
"search-tokens": `Usage:
|
|
280
262
|
smallpen search-tokens <product.smallpen> (--color COLOR | --value JSON | --query TEXT | --type TYPE)
|
|
281
|
-
[--context AXIS=VALUE]... [--
|
|
263
|
+
[--context AXIS=VALUE]... [--theme GROUP/NAME]... [--all-themes]
|
|
264
|
+
[--limit N] [--json]
|
|
282
265
|
|
|
283
266
|
Purpose:
|
|
284
267
|
Find reusable Product and Foundation Design Tokens before writing a hard-coded
|
|
@@ -286,6 +269,11 @@ Purpose:
|
|
|
286
269
|
values. Without --context, every finite Web/Desktop/theme/etc. Context is searched
|
|
287
270
|
and each resolved value reports its matching Contexts. Repeating --context restricts
|
|
288
271
|
the search explicitly. Name queries match Token path, description, and type.
|
|
272
|
+
Token themes: by default project defaults are searched; --theme overrides only
|
|
273
|
+
named groups, as every resolved read does. --all-themes searches every
|
|
274
|
+
selection of one theme per group (at most 64) and gives each item themes[],
|
|
275
|
+
the selections where it has that value. themeScope {mode active|explicit|all,
|
|
276
|
+
selections} says which themes were searched.
|
|
289
277
|
|
|
290
278
|
Examples:
|
|
291
279
|
smallpen search-tokens product.smallpen --color '#6750a4' --json
|
|
@@ -296,146 +284,38 @@ State:
|
|
|
296
284
|
Every search is self-contained. It never reads or writes a current selection,
|
|
297
285
|
previous result, session, or Web UI state.`,
|
|
298
286
|
"effective-token": `Usage:
|
|
299
|
-
smallpen
|
|
300
|
-
|
|
287
|
+
smallpen token show <package.smallpen> --path TOKEN.NAME
|
|
288
|
+
[--theme GROUP/NAME]... [--json]
|
|
301
289
|
|
|
302
290
|
Defaults:
|
|
303
|
-
|
|
291
|
+
Themes use project defaults, independently of the App's active selection.
|
|
292
|
+
--theme overrides only named groups.`,
|
|
304
293
|
"explain-token": `Usage:
|
|
305
|
-
smallpen
|
|
306
|
-
[--
|
|
294
|
+
smallpen token explain <package.smallpen> --path TOKEN.NAME
|
|
295
|
+
[--theme GROUP/NAME]... [--json]
|
|
307
296
|
|
|
308
297
|
Output:
|
|
309
298
|
Chosen source/value plus all candidates, specificity, rejection reasons, and layer.`,
|
|
310
|
-
render: `Usage:
|
|
311
|
-
smallpen render <product.smallpen> [selectors] [--scale N] [--output FILE] [--json]
|
|
312
|
-
|
|
313
|
-
${DESIGN_SELECTORS}
|
|
314
|
-
|
|
315
|
-
Defaults and limits:
|
|
316
|
-
No --output: return a PNG as bare base64 in one JSON result; no image file or
|
|
317
|
-
temporary image is created. This also applies without --json.
|
|
318
|
-
Explicit --output FILE: write that PNG and return its absolute output path
|
|
319
|
-
instead of base64. Existing FILE is replaced only after a successful write.
|
|
320
|
-
scale=1, scale range (0,8], maximum dimension 8192,
|
|
321
|
-
maximum 32M pixels. Output is deterministic PNG with revision/render hash. The
|
|
322
|
-
PNG image itself is raster pixels only and contains no layer IDs, hierarchy,
|
|
323
|
-
bounds, component references, or Token bindings. Use it for high-fidelity visual
|
|
324
|
-
QA of color, typography, spacing, effects, alignment, and rendering.
|
|
325
|
-
Decode the current response in an image-capable client; base64 text alone is
|
|
326
|
-
not visual QA. Verify decoded bytes against renderHash (SHA-256), and use the
|
|
327
|
-
accompanying revision and selection. On failure, never open a previous file.
|
|
328
|
-
|
|
329
|
-
Fonts:
|
|
330
|
-
The renderer bundles Source Sans Pro and draws fonts imported with import-font.
|
|
331
|
-
Any other family renders in Source Sans Pro: diagnostics then carries one
|
|
332
|
-
font_render_fallback per missing family with its nodeIds, availableFonts, and
|
|
333
|
-
the import-font command in nextOperations.
|
|
334
|
-
|
|
335
|
-
Wireframe:
|
|
336
|
-
Use smallpen read-view <product.smallpen> --format wireframe --json.
|
|
337
|
-
It returns a scaled 2D ASCII canvas and compact marker key. Use semanticTree
|
|
338
|
-
from inspect-view when exact bounds, text, component, and Token data is needed.`,
|
|
339
|
-
"inspect-view": `Usage:
|
|
340
|
-
smallpen inspect-view <product.smallpen> [selectors] [--include-image]
|
|
341
|
-
[--output FILE] [--base64] [--json]
|
|
342
|
-
|
|
343
|
-
${DESIGN_SELECTORS}
|
|
344
|
-
--scale N Image scale; default: 1 (requires --include-image to render)
|
|
345
|
-
--locale LOCALE Localized view labels; default: from the environment
|
|
346
|
-
|
|
347
|
-
Purpose:
|
|
348
|
-
Return one AI-readable view bundle.
|
|
349
|
-
|
|
350
|
-
Three complementary view parts:
|
|
351
|
-
wireframe Scaled 2D ASCII canvas plus a compact layer marker key.
|
|
352
|
-
semanticTree Exact hierarchy, bounds, text, alignment, typography, component,
|
|
353
|
-
variant, and Token data.
|
|
354
|
-
image Optional high-fidelity PNG and metadata; add --include-image to render it.
|
|
355
|
-
|
|
356
|
-
Supporting context:
|
|
357
|
-
Effective Tokens, component catalog, selected Context, and revision metadata.
|
|
358
|
-
Without --output, image.base64 contains bare PNG base64 in this one JSON result
|
|
359
|
-
(also without --json). No image file or temporary image is created.
|
|
360
|
-
Explicit --output FILE writes the image and returns image.output instead of
|
|
361
|
-
base64; add --base64 only when both file and inline bytes are wanted.
|
|
362
|
-
--output and --base64 require --include-image.
|
|
363
|
-
|
|
364
|
-
Agent guidance:
|
|
365
|
-
Use this when the Agent needs both structure and visual QA. Start with wireframe
|
|
366
|
-
for spatial relationships, query semanticTree for exact data, and inspect image
|
|
367
|
-
only when pixel-level visual QA is needed. The PNG itself contains no layer or
|
|
368
|
-
Token metadata. Decode this response in an image-capable client; base64 text
|
|
369
|
-
alone is not visual QA. image.revision/selection identify the rendered snapshot;
|
|
370
|
-
image.renderHash is the SHA-256 of the decoded PNG. Never reuse an old image
|
|
371
|
-
after an error, or infer freshness from a filename.`,
|
|
372
|
-
"render-matrix": `Usage:
|
|
373
|
-
smallpen render-matrix <product.smallpen> --contexts CONTEXTS.json
|
|
374
|
-
[--output DIRECTORY] [--scale N] [--json]
|
|
375
|
-
|
|
376
|
-
Purpose:
|
|
377
|
-
Render a deterministic PNG for every explicit design selector in CONTEXTS.json.
|
|
378
|
-
Each selector may choose context axes, screen, presentation, and scenario.
|
|
379
|
-
Without --output, one JSON result contains ordered images with bare base64,
|
|
380
|
-
dimensions, exact selectors, per-image revisions, and PNG SHA-256 renderHash.
|
|
381
|
-
No image files or temporary images are created, including if a later selector
|
|
382
|
-
fails. This also applies without --json.
|
|
383
|
-
Explicit --output DIRECTORY writes PNG files and returns each image.output
|
|
384
|
-
instead of base64. Different render hashes retain separate files; there is no
|
|
385
|
-
automatic cleanup or all-or-nothing multi-file export. Only consume images
|
|
386
|
-
from a successful current response; never fall back to earlier matrix files.`,
|
|
387
|
-
evidence: `Usage:
|
|
388
|
-
smallpen evidence <product.smallpen> [selectors] [--scale N] [--output PREFIX] [--json]
|
|
389
|
-
|
|
390
|
-
${DESIGN_SELECTORS}
|
|
391
|
-
|
|
392
|
-
Output:
|
|
393
|
-
Without --output, return one JSON evidence bundle with image.base64 (bare PNG
|
|
394
|
-
base64); no PNG, evidence JSON file, or temporary image is created. This also
|
|
395
|
-
applies without --json. image includes the current revision/selection and
|
|
396
|
-
renderHash (SHA-256 of decoded PNG bytes), not a cache locator.
|
|
397
|
-
Explicit --output PREFIX writes PREFIX.png and PREFIX.json instead of base64.
|
|
398
|
-
Evidence contains revision/package hash, resolved selectors,
|
|
399
|
-
render hash, node-to-image regions, Semantic Tree, viewport, and diagnostics.
|
|
400
|
-
PREFIX.png is an unannotated high-fidelity raster image. Semantic details live in
|
|
401
|
-
PREFIX.json and are not embedded visibly in the PNG.
|
|
402
|
-
Decode the current inline response in an image-capable client for visual QA.
|
|
403
|
-
Failed exports do not authorize reading an old file; multi-file export is not
|
|
404
|
-
an all-or-nothing transaction and existing files are not automatically cleaned.
|
|
405
|
-
|
|
406
|
-
Wireframe:
|
|
407
|
-
Use smallpen read-view <product.smallpen> --format wireframe --json.
|
|
408
|
-
It returns a scaled 2D ASCII canvas with one [NN] marker per layer.`,
|
|
409
299
|
"import-media": `Usage:
|
|
410
|
-
smallpen
|
|
300
|
+
smallpen asset media import <package.smallpen> --file MEDIA_FILE
|
|
411
301
|
[--media-path PATH] [--name NAME] [--json]
|
|
412
302
|
|
|
413
303
|
Import is the public binary Media entry for an existing Product: PNG, JPEG, GIF,
|
|
414
304
|
WebP, and SVG are detected from bytes, dimensions are validated, and the blob is
|
|
415
305
|
content-addressed (identical bytes in one package share one blob). JSON apply
|
|
416
|
-
still forbids blob writes; media import is a file entry, not a batch operation.
|
|
417
|
-
|
|
418
|
-
|
|
306
|
+
still forbids blob writes; asset media import is a file entry, not a batch operation.
|
|
307
|
+
asset media delete --media NAME deletes the descriptor; the content-addressed blob
|
|
308
|
+
itself is immutable and shared.
|
|
419
309
|
|
|
420
310
|
Errors and recovery:
|
|
421
311
|
Corrupt or unsupported bytes exit 1 invalid_media_file and write nothing.
|
|
422
|
-
Reusing --media-id exits duplicate_media_id with the existing descriptor.
|
|
423
312
|
|
|
424
313
|
Output:
|
|
425
|
-
descriptor and revision, plus batchId and the
|
|
426
|
-
|
|
427
|
-
`,
|
|
428
|
-
"remove-media": `Usage:
|
|
429
|
-
smallpen remove-media <package.smallpen> --media-id MEDIA [--json]
|
|
430
|
-
|
|
431
|
-
Removes one Media descriptor from the Asset Library atomically. The result
|
|
432
|
-
carries batchId and inverseBatch; smallpen apply with that inverseBatch restores
|
|
433
|
-
the descriptor (the blob is retained). Unknown ids exit missing_media.
|
|
314
|
+
descriptor and revision, plus batchId and the revision-guarded reverse edit (inverseBatch).
|
|
434
315
|
|
|
435
316
|
`,
|
|
436
317
|
"import-font": `Usage:
|
|
437
|
-
smallpen
|
|
438
|
-
[--font-id font_...] [--variant-id fvar_...]
|
|
318
|
+
smallpen asset font import <package.smallpen> --file FONT_FILE --family NAME
|
|
439
319
|
[--weight 400] [--style normal] [--name NAME] [--json]
|
|
440
320
|
|
|
441
321
|
Public Font entry for an existing Product. TTF and OTF are validated by SFNT
|
|
@@ -443,7 +323,8 @@ signature and converted to WOFF (the renderer loads ttf/otf/woff). WOFF imports
|
|
|
443
323
|
as-is after table validation. A valid WOFF2 reaches an explicit
|
|
444
324
|
unsupported_font_conversion boundary (no WOFF2 decoder is bundled); corrupt
|
|
445
325
|
fonts fail invalid_font_blob. Either way nothing is written. Success returns
|
|
446
|
-
|
|
326
|
+
the family, files, revision, batchId, and the exact inverseBatch. Use the
|
|
327
|
+
family by name: "fontFamily": "Inter", or a font-family Token.
|
|
447
328
|
|
|
448
329
|
`,
|
|
449
330
|
"library-refresh": `Usage:
|
|
@@ -488,7 +369,9 @@ Purpose:
|
|
|
488
369
|
Import a DTCG token file (Penpot or Tokens Studio export, single-set, multi-set
|
|
489
370
|
with $themes/$metadata, or legacy value/type) into the package's Penpot-shaped
|
|
490
371
|
Token Library. Without --apply the command only reviews: it prints the diff of
|
|
491
|
-
tokens, sets, and themes that would be added, changed, or removed
|
|
372
|
+
tokens, sets, and themes that would be added, changed, or removed (counts and
|
|
373
|
+
up to 20 identities per action). --full includes the replacement library and
|
|
374
|
+
exact before/after values.
|
|
492
375
|
--dry-run keeps the operation in no-write review mode even with --apply;
|
|
493
376
|
that combination also validates the prepared Operation Batch without committing.
|
|
494
377
|
|
|
@@ -525,117 +408,13 @@ Selections:
|
|
|
525
408
|
Output:
|
|
526
409
|
A typed Operation Batch whose baseRevision is the current Canonical revision.
|
|
527
410
|
This command does not apply the batch. Review it, then use smallpen apply.`,
|
|
528
|
-
flow: `Usage:
|
|
529
|
-
smallpen flow <product.smallpen> --intent INTENT.json [--batch-id ID] [--dry-run]
|
|
530
|
-
[--explain] [--diff] [--warning-detail compact|full]
|
|
531
|
-
[--confirm-unmatched] [--compact] [--inverse-out FILE] [--json]
|
|
532
|
-
|
|
533
|
-
Purpose:
|
|
534
|
-
Compile and atomically apply a declarative flowchart intent. The intent contains
|
|
535
|
-
screenId, optional presentationId/parentId, and nodes. Each node becomes a
|
|
536
|
-
canonical add-presentation-node operation and receives an exact inverse batch.
|
|
537
|
-
|
|
538
|
-
Intent example:
|
|
539
|
-
{"screenId":"scr_home","nodes":[{"id":"node_start","type":"ELLIPSE",
|
|
540
|
-
"name":"Start","x":80,"y":80,"width":120,"height":56,"children":[]}]}
|
|
541
|
-
|
|
542
|
-
Node types:
|
|
543
|
-
FRAME|ELLIPSE|GROUP|PATH|RECTANGLE|TEXT. PATH nodes may carry pathData, points,
|
|
544
|
-
strokes, and tokenBindings; arrowheads use stroke cap fields.
|
|
545
|
-
Node fields: smallpen schema node. Every intent node is added as a sibling
|
|
546
|
-
under parentId (default: the Presentation root); nest with a later intent.
|
|
547
|
-
INSTANCE nodes may carry overrides, as in smallpen page --help.
|
|
548
|
-
|
|
549
|
-
Output:
|
|
550
|
-
The normal atomic apply result. Follow with read-view or render to inspect it.
|
|
551
|
-
|
|
552
|
-
${WRITE_REPLY}`,
|
|
553
|
-
page: `Usage:
|
|
554
|
-
smallpen page <product.smallpen> --intent INTENT.json [--batch-id ID] [--dry-run]
|
|
555
|
-
[--explain] [--diff] [--warning-detail compact|full]
|
|
556
|
-
[--confirm-unmatched] [--compact] [--inverse-out FILE] [--json]
|
|
557
|
-
|
|
558
|
-
Purpose:
|
|
559
|
-
Compile and atomically apply declarative page nodes. The intent uses the same
|
|
560
|
-
screenId, optional presentationId/parentId, and nodes schema as flow. Use page
|
|
561
|
-
for general UI nodes and flow for flowchart-oriented PATH/ELLIPSE nodes.
|
|
562
|
-
Warning output follows apply; see smallpen apply --help for the compact schema.
|
|
563
|
-
Pass the Product. Each node becomes one add-presentation-node, all siblings
|
|
564
|
-
under parentId (default: the Presentation root); x/y are relative to it.
|
|
565
|
-
|
|
566
|
-
Instance overrides:
|
|
567
|
-
An INSTANCE intent node may carry overrides {"<sourceNodeId>:<field>": value}
|
|
568
|
-
(fields: fills, name, opacity, text, visible). Each becomes a
|
|
569
|
-
set-instance-override after the node in the same atomic batch, so a label
|
|
570
|
-
needs no second write; a wrong path or type rejects the whole intent.
|
|
571
|
-
|
|
572
|
-
Intent example (a title and a Button Instance with its label):
|
|
573
|
-
{"screenId":"scr_home","nodes":[
|
|
574
|
-
{"id":"node_title","type":"TEXT","name":"Title","x":24,"y":48,"width":312,
|
|
575
|
-
"height":32,"children":[],"text":"Tasks","textStyle":{"fontSize":24}},
|
|
576
|
-
{"id":"node_add_button","type":"INSTANCE","name":"Add button","x":16,"y":576,
|
|
577
|
-
"width":328,"height":48,"children":[],"instance":{"component":
|
|
578
|
-
{"packageId":"pkg_acme_foundation","assetId":"cmp_button"},
|
|
579
|
-
"variant":{"axis_style":"primary"}},
|
|
580
|
-
"overrides":{"node_button_label:text":"Add task"}}]}
|
|
581
|
-
|
|
582
|
-
Shapes:
|
|
583
|
-
smallpen schema node fields, textStyle, tokenBindings
|
|
584
|
-
smallpen schema instance INSTANCE nodes; search-components prints a ready intent
|
|
585
|
-
|
|
586
|
-
${WRITE_REPLY}`,
|
|
587
|
-
token: `Usage:
|
|
588
|
-
smallpen token <package.smallpen> --intent INTENT.json [--batch-id ID] [--dry-run]
|
|
589
|
-
[--explain] [--diff] [--warning-detail compact|full]
|
|
590
|
-
[--confirm-unmatched] [--compact] [--inverse-out FILE] [--json]
|
|
591
|
-
|
|
592
|
-
Which Package:
|
|
593
|
-
Pass the Foundation (<name>-foundation.smallpen) for put-token, set-token-value,
|
|
594
|
-
remove-token, and deprecate-token: shared Tokens live there. Pass the Product
|
|
595
|
-
(<name>.smallpen) for set-token-binding, clear-token-binding, and
|
|
596
|
-
set-active-token-themes, which change Product nodes and its Token Library.
|
|
597
|
-
smallpen schema operations lists the Package of every operation.
|
|
598
|
-
|
|
599
|
-
Purpose:
|
|
600
|
-
Apply declarative Token operations through the canonical atomic batch contract.
|
|
601
|
-
Intent JSON contains an operations array using put-token, set-token-value,
|
|
602
|
-
set-active-token-themes, set-token-binding, clear-token-binding, remove-token,
|
|
603
|
-
or deprecate-token. Theme selection uses themePaths such as Product/Dark.
|
|
604
|
-
The current package revision is read immediately before applying the intent.
|
|
605
|
-
Write shared Tokens to the Foundation package; bind them from the Product.
|
|
606
|
-
put-token with an existing tokenId replaces that Token whole (no merge). init
|
|
607
|
-
seeds one Token per initialTokens answer (the recommended answers give
|
|
608
|
-
tok_color_brand, tok_spacing_md, tok_radius_md; the init reply lists them in
|
|
609
|
-
seeded.tokens); put-token with one of those ids redefines it.
|
|
610
|
-
Rerunning with the same --batch-id and intent after success returns
|
|
611
|
-
alreadyApplied:true; see smallpen apply --help for replay rules.
|
|
612
|
-
|
|
613
|
-
Intent example (a color with a dark value, and a typography Token):
|
|
614
|
-
{"operations":[
|
|
615
|
-
{"type":"put-token","filePath":"tokens/foundation.json","path":"color.surface",
|
|
616
|
-
"tokenId":"tok_color_surface","definition":{"$type":"color","$value":"#ffffff",
|
|
617
|
-
"$extensions":{"smallpen":{"id":"tok_color_surface","contextValues":
|
|
618
|
-
[{"when":{"axis_theme":"dark"},"value":"#1c1b1f"}]}}}},
|
|
619
|
-
{"type":"put-token","filePath":"tokens/foundation.json","path":"type.heading",
|
|
620
|
-
"tokenId":"tok_type_heading","definition":{"$type":"typography","$value":
|
|
621
|
-
{"fontFamily":"Inter","fontSize":24,"fontWeight":700},
|
|
622
|
-
"$extensions":{"smallpen":{"id":"tok_type_heading"}}}}]}
|
|
623
|
-
|
|
624
|
-
Shapes:
|
|
625
|
-
smallpen schema token definition, contextValues, bindable fields
|
|
626
|
-
smallpen schema token-types the value each type accepts
|
|
627
|
-
smallpen schema operation set-token-value
|
|
628
|
-
|
|
629
|
-
${WRITE_REPLY}`,
|
|
630
411
|
impact: `Usage:
|
|
631
|
-
smallpen impact <
|
|
412
|
+
smallpen token impact <package.smallpen> --path TOKEN.NAME [--json]
|
|
632
413
|
|
|
633
414
|
Purpose:
|
|
634
|
-
Find
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
Tokens are resolved through the Product dependency; use --package-id to
|
|
638
|
-
disambiguate a Token ID or path that exists in both Packages.`,
|
|
415
|
+
Find every element whose bindings use the Token, by page, component and
|
|
416
|
+
element, so an Agent can see what a change touches before making it.
|
|
417
|
+
Foundation Tokens are resolved through the Product dependency.`,
|
|
639
418
|
apply: `Usage:
|
|
640
419
|
smallpen apply <package.smallpen> --batch BATCH.json [--dry-run] [--explain] [--diff]
|
|
641
420
|
[--warning-detail compact|full] [--confirm-unmatched]
|
|
@@ -645,7 +424,7 @@ Batch contract:
|
|
|
645
424
|
{"baseRevision":"...","batchId":"unique-id","operations":[...]}
|
|
646
425
|
baseRevision is package.revision from smallpen inspect PACKAGE --json.
|
|
647
426
|
The whole candidate validates and commits atomically. Success returns revision,
|
|
648
|
-
affected stable IDs/files,
|
|
427
|
+
affected stable IDs/files, a revision-guarded reverse edit, and changed
|
|
649
428
|
(false, with noChange, when the batch leaves the Package as it was).
|
|
650
429
|
Revisions are content hashes, not increasing counters: restoring the exact
|
|
651
430
|
Canonical content restores its previous revision.
|
|
@@ -654,8 +433,10 @@ Operations:
|
|
|
654
433
|
smallpen schema operations every type, purpose, Package, required fields
|
|
655
434
|
smallpen schema operation TYPE fields, allowed values, example, inverse
|
|
656
435
|
Unknown operation types and unknown fields are rejected, with a suggestion.
|
|
657
|
-
|
|
658
|
-
|
|
436
|
+
In the default layout everything goes to the one Package. In the
|
|
437
|
+
foundation-product layout Tokens, themes, Context Axes, and shared Component
|
|
438
|
+
Sets go to the Foundation; Screens, nodes, Instances, and Scenarios go to the
|
|
439
|
+
Product.
|
|
659
440
|
Example: {"baseRevision":"<revision>","batchId":"resize-home-1","operations":[
|
|
660
441
|
{"type":"update-presentation-node","screenId":"scr_home",
|
|
661
442
|
"presentationId":"pres_home_mobile","nodeId":"node_home_root",
|
|
@@ -705,7 +486,8 @@ Errors and recovery:
|
|
|
705
486
|
write. If later writes moved the Package elsewhere the retry exits
|
|
706
487
|
batch_superseded with committedRevision and currentRevision. The same batchId
|
|
707
488
|
with a different baseRevision or operations exits batch_id_conflict.
|
|
708
|
-
|
|
489
|
+
The name-based writes (page, component, flow, token, theme, asset, canvas)
|
|
490
|
+
and import-tokens rebuild the batch from the current
|
|
709
491
|
revision; rerunning one with the same --batch-id and input after success
|
|
710
492
|
returns alreadyApplied:true under the same rules.
|
|
711
493
|
stale_revision returns actual/base revisions. Inspect current content first:
|
|
@@ -726,11 +508,40 @@ The initial revision is emitted immediately. --max-events bounds the run for
|
|
|
726
508
|
scripted use; Ctrl-C exits 0. Watch never writes.
|
|
727
509
|
|
|
728
510
|
`,
|
|
511
|
+
"migrate-themes": `Usage:
|
|
512
|
+
smallpen migrate-themes <package.smallpen> --output NEW_PATH [--json]
|
|
513
|
+
|
|
514
|
+
Purpose:
|
|
515
|
+
Upgrade by copy (the original stays untouched): write a new Package whose
|
|
516
|
+
theme-kind Context Axes and Token contextValues are Penpot token sets and
|
|
517
|
+
themes. For a Product with a Foundation, both are copied: --output names the new
|
|
518
|
+
workspace directory, which receives the Foundation and the Product under their
|
|
519
|
+
current directory names, still linked. Otherwise --output is the new
|
|
520
|
+
<name>.smallpen path.
|
|
521
|
+
|
|
522
|
+
Conversion:
|
|
523
|
+
Each theme-kind axis becomes a theme group named after the axis. The set base
|
|
524
|
+
holds every Token's default value (Token ids, names and bindings stay as they
|
|
525
|
+
are); one set per non-default value holds that value's overrides as Tokens of
|
|
526
|
+
the same name (ids tok_<base id>__<value>); one theme per value activates
|
|
527
|
+
[base, its set]; the default value's theme is active. DTCG token files become
|
|
528
|
+
the token library. A Product stores the active Foundation theme on its
|
|
529
|
+
dependency. Scenario contexts on theme axes become Scenario themes. Legacy
|
|
530
|
+
{x, y} shadows become {offsetX, offsetY}.
|
|
531
|
+
|
|
532
|
+
Warnings:
|
|
533
|
+
contextValues whose when names a non-theme axis, or more than one axis, cannot
|
|
534
|
+
be a theme set: they are kept as they were and listed in warnings with their
|
|
535
|
+
Tokens. Product Token overrides (overrideOf) stay DTCG Tokens.
|
|
536
|
+
|
|
537
|
+
Next:
|
|
538
|
+
smallpen view NEW_PATH --theme Theme/Dark --json`,
|
|
729
539
|
repair: `Usage:
|
|
730
540
|
smallpen repair <product.smallpen> [--conflict N] [--action ACTION]
|
|
731
541
|
[action arguments] [--batch-id ID] [--json]
|
|
732
542
|
|
|
733
543
|
Actions:
|
|
544
|
+
select-instance-variant [--selection JSON]; default: the closest variant
|
|
734
545
|
retarget-reference --replacement-package-id PKG --replacement-asset-id ID
|
|
735
546
|
remove-dependent-usage no additional arguments
|
|
736
547
|
choose-foundation --foundation PATH
|
|
@@ -738,18 +549,70 @@ Actions:
|
|
|
738
549
|
|
|
739
550
|
Without --action, returns all typed conflicts and choices. Each action is checked
|
|
740
551
|
against the selected conflict and committed through one atomic Operation Batch.
|
|
741
|
-
After each step the workspace is resolved again; remaining conflicts stay explicit
|
|
552
|
+
After each step the workspace is resolved again; remaining conflicts stay explicit.
|
|
553
|
+
|
|
554
|
+
Instances whose variant is gone:
|
|
555
|
+
An Instance selects variant values. When its Foundation renames those values
|
|
556
|
+
while the Product is open in the same Desktop or Web session, the Product's
|
|
557
|
+
Instances follow the variant in a batch of their own (with its own undo).
|
|
558
|
+
When the variant is deleted, or the rename happened elsewhere, the Product
|
|
559
|
+
enters Repair: the conflict is missing_variant with degraded:true, the
|
|
560
|
+
Instance still renders with the closest variant (a stale_instance_variant
|
|
561
|
+
diagnostic says so), and the choices are select-instance-variant (the closest
|
|
562
|
+
variant; --selection picks one of validSelections), retarget-reference or
|
|
563
|
+
remove-dependent-usage (delete the Instance).`,
|
|
742
564
|
};
|
|
743
565
|
|
|
744
|
-
export function printHelp(command) {
|
|
745
|
-
|
|
746
|
-
|
|
566
|
+
export function printHelp(command, { full = false, route } = {}) {
|
|
567
|
+
const say = (text) => printText(publicText(text));
|
|
568
|
+
const name = route?.name ?? command;
|
|
569
|
+
if (Object.hasOwn(COMMAND_GROUPS, command) || !command) {
|
|
570
|
+
printBriefHelp(command, undefined, { full });
|
|
571
|
+
say(
|
|
572
|
+
"\nOptions: -h, --help; --version\nUse smallpen help OBJECT ACTION for options. Common rules: smallpen help rules\n",
|
|
573
|
+
);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (!full) {
|
|
577
|
+
if (!command) {
|
|
578
|
+
printBriefHelp();
|
|
579
|
+
say(
|
|
580
|
+
"\nOptions: -h, --help; --version\nUse smallpen COMMAND --help for options. Common rules: smallpen help rules\n",
|
|
581
|
+
);
|
|
582
|
+
} else
|
|
583
|
+
say(
|
|
584
|
+
`SmallPen ${command}\n\n${commandContract(command).purpose}\n\nUsage: smallpen ${command} ${commandContract(
|
|
585
|
+
command,
|
|
586
|
+
)
|
|
587
|
+
.arguments.map((a) => (a.required ? `<${a.name}>` : `[${a.name}]`))
|
|
588
|
+
.join(
|
|
589
|
+
" ",
|
|
590
|
+
)} [options]\n\n${commandHelp(command)}\n\nInput shapes: smallpen schema command ${command} --json\n`,
|
|
591
|
+
);
|
|
592
|
+
if (command && commandOverview(command).notes)
|
|
593
|
+
say(commandOverview(command).notes.join("\n") + "\n");
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
const guidance = commandGuidance(command, route);
|
|
597
|
+
if (command && guidance) {
|
|
598
|
+
say(`SmallPen ${name}\n\n${guidance}
|
|
599
|
+
|
|
600
|
+
${commandHelp(name)}
|
|
747
601
|
|
|
748
602
|
Common output and error contract:
|
|
603
|
+
Default JSON is compact and bounded to 8 KiB. Large complete results are saved
|
|
604
|
+
to resultFile.path with bytes/SHA-256; stdout retains status and write receipts.
|
|
605
|
+
Search/read the JSON with jq or your file tools, and text with rg/sed.
|
|
606
|
+
Each call uses random filenames of a fixed format in one system temporary
|
|
607
|
+
folder: smallpen-TIMESTAMP-UUID-KIND.ext. Every invocation cleans CLI files
|
|
608
|
+
whose mtime is older than 30 minutes; active calls are protected.
|
|
609
|
+
--output chooses a retained file. Lists default to 20 items; --full expands data
|
|
610
|
+
but still uses files for large results. --stdout opts into large stdout.
|
|
611
|
+
--base64 explicitly requests inline image bytes; PNG paths are the default.
|
|
749
612
|
--json emits stable English keys; localized labels remain additional data and
|
|
750
613
|
follow --locale where offered, else LC_ALL, LC_MESSAGES, or LANG (zh* selects
|
|
751
614
|
Chinese, anything else English). Success
|
|
752
|
-
exits 0. Errors exit 1 as {error:{code,message,details}} and include exact
|
|
615
|
+
exits 0. Errors exit 1 as {error:{code,message,details,writeState}} and include exact
|
|
753
616
|
nextOperations when recovery requires refresh, replay, Repair, or confirmation.
|
|
754
617
|
Unknown options are not part of the command contract shown above. Only options
|
|
755
618
|
shown with ..., repeated, or described as repeatable may appear more than once;
|
|
@@ -757,21 +620,27 @@ Common output and error contract:
|
|
|
757
620
|
|
|
758
621
|
Help / next:
|
|
759
622
|
smallpen --help
|
|
760
|
-
smallpen ${
|
|
623
|
+
smallpen ${name} --help
|
|
761
624
|
`);
|
|
762
625
|
return;
|
|
763
626
|
}
|
|
764
|
-
|
|
627
|
+
say(`SmallPen Canonical Package CLI
|
|
765
628
|
|
|
766
629
|
Model:
|
|
767
|
-
One .smallpen directory is one Canonical Package. init creates
|
|
768
|
-
(<name
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
630
|
+
One .smallpen directory is one Canonical Package. init creates one
|
|
631
|
+
self-contained Package (<name>.smallpen) by default: token sets and themes,
|
|
632
|
+
Context Axes, Component Sets, Screens, Presentations, Scenarios. Write
|
|
633
|
+
everything to it and pass it to view, validate, export, token list and
|
|
634
|
+
search. With init --layout foundation-product it creates a Foundation
|
|
635
|
+
(<name>-foundation.smallpen: token sets and themes, Context Axes, shared
|
|
636
|
+
Component Sets) and a Product (<name>.smallpen: Screens, Presentations,
|
|
637
|
+
Scenarios) instead: write Tokens and components to the Foundation, Screens and
|
|
638
|
+
nodes to the Product, and pass the Product to the reads.
|
|
639
|
+
Themes are Penpot token sets + themes. token theme list reads groups/options/defaults;
|
|
640
|
+
token theme add|rename|default|delete write them by Group/Option name. Resolved reads take
|
|
641
|
+
--theme GROUP/NAME for this call only: project defaults, then an explicit
|
|
642
|
+
Scenario, then explicit overrides of named groups. App active selection is
|
|
643
|
+
independent. set-active-token-themes explicitly stores the App selection.
|
|
775
644
|
A Product references exactly one same-workspace Foundation by permanent Package
|
|
776
645
|
ID and relative path. Every CLI call
|
|
777
646
|
receives its Package locator and complete selectors explicitly; there is no current
|
|
@@ -780,45 +649,77 @@ Model:
|
|
|
780
649
|
and one typed Operation Batch contract. No PostgreSQL, collaboration server, MCP,
|
|
781
650
|
or built-in AI Chat is required.
|
|
782
651
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
652
|
+
CLI entry point:
|
|
653
|
+
smallpen help
|
|
654
|
+
smallpen help OBJECT ACTION
|
|
655
|
+
smallpen schema command OBJECT ACTION --json
|
|
656
|
+
smallpen help rules
|
|
657
|
+
CLI usage is complete without a Skill. Scene Skills supply task-specific rules.
|
|
658
|
+
|
|
659
|
+
Separate actions:
|
|
660
|
+
settings token/component/page/canvas/asset/flow actions save changes by
|
|
661
|
+
name; advanced apply runs an exact batch, such as an undo batch.
|
|
662
|
+
definitions token theme list is a cheap settings query; search finds reusable Tokens
|
|
663
|
+
and components.
|
|
664
|
+
view Compact layout outline, or a page/component/region text wireframe.
|
|
665
|
+
validate Problems and coverage; data validity is separate from visual QA.
|
|
666
|
+
export Actual text, wireframe or PNG files with size/hash/selection.
|
|
667
|
+
Read compact text/issues first, then text wireframes. Inspect PNG only when
|
|
668
|
+
useful and the caller supports image input; reuse an unchanged renderHash.
|
|
669
|
+
export defaults to a text wireframe; PNG requires --format png. The CLI does
|
|
670
|
+
not detect model image capability. Text-only models may export PNG deliverables
|
|
671
|
+
but must review text/wireframes and must not claim visual inspection of a PNG.
|
|
792
672
|
|
|
793
673
|
Usage:
|
|
794
674
|
smallpen <command> [arguments] [--json]
|
|
795
675
|
smallpen <command> --help
|
|
796
|
-
smallpen --
|
|
676
|
+
smallpen version --json
|
|
797
677
|
|
|
798
678
|
Commands:
|
|
799
|
-
${
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
smallpen init ./
|
|
803
|
-
smallpen
|
|
804
|
-
smallpen
|
|
805
|
-
smallpen
|
|
806
|
-
smallpen
|
|
807
|
-
smallpen
|
|
808
|
-
smallpen
|
|
809
|
-
smallpen
|
|
810
|
-
smallpen
|
|
811
|
-
smallpen
|
|
812
|
-
smallpen
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
679
|
+
${PUBLIC_PATHS.map(([name, summary]) => ` ${name.padEnd(24)} ${summary}`).join("\n")}
|
|
680
|
+
|
|
681
|
+
Query examples:
|
|
682
|
+
smallpen init ./acme --json
|
|
683
|
+
smallpen themes ./acme/acme.smallpen --json
|
|
684
|
+
smallpen help rules --json
|
|
685
|
+
smallpen validate ./acme/acme.smallpen --json
|
|
686
|
+
smallpen search-tokens ./acme/acme.smallpen --color '#6750a4' --json
|
|
687
|
+
smallpen search-components ./acme/acme.smallpen --query button --json
|
|
688
|
+
smallpen catalog ./acme/acme.smallpen --json
|
|
689
|
+
smallpen view ./acme/acme.smallpen --json
|
|
690
|
+
smallpen apply ./acme/acme.smallpen --batch batch.json --json
|
|
691
|
+
smallpen export ./acme/acme.smallpen --format text --json
|
|
692
|
+
smallpen export ./acme/acme.smallpen --format png --json
|
|
693
|
+
smallpen export ./acme/acme.smallpen --design-system --json
|
|
694
|
+
smallpen import-draft ./acme/import-1.smallpen --kind figma --input clipboard.html --json
|
|
695
|
+
smallpen repair ./acme/acme.smallpen --json
|
|
696
|
+
|
|
697
|
+
Output:
|
|
698
|
+
Defaults are summaries, paginated identities, and artifact paths (8 KiB budget).
|
|
699
|
+
JSON is compact. Directory fields are a public CLI contract, not a dump of
|
|
700
|
+
internal objects. Reuse restrictions appear only when they affect a decision.
|
|
701
|
+
Read one target before editing. --full requests complete data; --base64 requests
|
|
702
|
+
image bytes. Operation schemas are available individually: smallpen schema operation TYPE.
|
|
703
|
+
smallpen schema returns cliVersion/contractRevision for stable contract caching.
|
|
704
|
+
Package reads return revision; workspace views also return dependency revisions.
|
|
705
|
+
Cache a view by those revisions plus its selectors, theme, context and locale.
|
|
706
|
+
|
|
707
|
+
Worked example:
|
|
708
|
+
smallpen schema batch --full
|
|
816
709
|
|
|
817
710
|
Every write input has a schema and a tested example: smallpen schema
|
|
818
|
-
(operations, node, token, component-set, instance, presentation, batch, init).
|
|
711
|
+
(operations, node, token, theme, component-set, instance, presentation, batch, init).
|
|
819
712
|
Run smallpen <command> --help for syntax, defaults, values, examples, outputs,
|
|
820
713
|
errors, and relevant next commands.
|
|
821
714
|
`);
|
|
822
715
|
}
|
|
823
716
|
|
|
824
717
|
export const COMMAND_NAMES = Object.freeze(COMMANDS.map(([name]) => name));
|
|
718
|
+
export function commandGuidance(command, route) {
|
|
719
|
+
if (route && (command === "assets" || route.fixed || !HELP[command])) {
|
|
720
|
+
const contract = commandContract(route.name);
|
|
721
|
+
const args = contract.arguments.map(({ name, required }) => required ? `<${name}>` : `[${name}]`).join(" ");
|
|
722
|
+
return `Usage:\n smallpen ${route.name} ${args} [options]\n\n${route.purpose}`;
|
|
723
|
+
}
|
|
724
|
+
return HELP[command] ? publicText(HELP[command]) : undefined;
|
|
725
|
+
}
|