jig-ui 0.23.0 → 0.24.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jig-ui",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "A design system for coding agents. 159 numbered UI rules, brand x mode design tokens, and an installer for Claude Code, Codex, Cursor and opencode.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -22,7 +22,7 @@
22
22
  "CHANGELOG.md"
23
23
  ],
24
24
  "engines": {
25
- "node": ">=20"
25
+ "node": ">=22"
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsup",
@@ -37,6 +37,7 @@
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.0.0",
39
39
  "tsup": "^8.3.0",
40
+ "tsx": "^4.23.15",
40
41
  "typescript": "^5.6.0",
41
42
  "vitest": "^2.1.0"
42
43
  },
@@ -6,7 +6,7 @@ these, say so, list them, and stop.
6
6
 
7
7
  There are two kinds of subcommand, and they are not run the same way.
8
8
 
9
- **CLI-backed** — `install`, `update`, `init`, `check`, `explain`, `verdicts`, `gate`, `probe`, `seo`, `ship`. Run the
9
+ **CLI-backed** — `install`, `update`, `init`, `check`, `explain`, `verdicts`, `gate`, `probe`, `seo`, `ship`, `checksum`. Run the
10
10
  matching command with `{{scripts_path}}`, passing the flags through unchanged,
11
11
  then do the work below for that subcommand. Read the command's full output —
12
12
  findings are ordered by severity, not position, so `head`, `tail`, `grep` and
@@ -261,10 +261,12 @@ The commands after this run unchanged.
261
261
  ### 1. Ask, two or three questions at a time
262
262
 
263
263
  **This is a required interaction, not a suggestion.** Ask two or three questions,
264
- then **wait**. Do not send a questionnaire. Do not write the spec and present it
265
- for approval on your first response — a spec synthesised from a one-line prompt
266
- and handed over for a yes is the failure this command exists to prevent, and it
267
- looks exactly like the command working.
264
+ then **wait**. Do not send a questionnaire. Do not hand the owner a finished
265
+ spec for approval on your first response — a spec synthesised from a one-line
266
+ prompt and handed over for a yes is the failure this command exists to prevent,
267
+ and it looks exactly like the command working. (This is about what you ask the
268
+ owner, not where you write: when you do write the spec, it goes in
269
+ `.jig/specs/`, step 3.)
268
270
 
269
271
  Ask about **structure**, not appearance. Colour, type scale and density were
270
272
  settled at `init` and live in `{{config_file}}` and the token layer; re-deciding
@@ -327,6 +329,11 @@ hierarchy plainly enough that the squint question can be answered against it.
327
329
 
328
330
  ### 3. Write it down — one composition per screen size
329
331
 
332
+ **Write it at `.jig/specs/<name>.spec.md` from the first draft**, with
333
+ `confirmed: false`, never in a scratchpad or a temporary file. Every check the
334
+ owner relies on reads that file, the check in 3c and the gate among them; a
335
+ draft kept elsewhere is checked by nothing, and reaches the owner unchecked.
336
+
330
337
  `.jig/specs/<surface-slug>.spec.md`. Frontmatter carries what can be compared to
331
338
  a built page; prose carries the reasoning that no check can read.
332
339
 
@@ -340,6 +347,7 @@ phone as a squeezed desktop.
340
347
  ---
341
348
  feature: sign in to an existing account # the task, not the screen
342
349
  surface: login page
350
+ route: /login/ # optional: where the page is served, when the surface's name does not say
343
351
  mode: product # from {{config_file}} — state it, never leave it implied
344
352
  confirmed: false # only the user sets this to true; see below
345
353
  sizes: # phone first. Each size is a whole composition, not a diff.
@@ -384,6 +392,10 @@ critique: each # optional: each, or at-ship; left out, the project's
384
392
  ---
385
393
  ```
386
394
 
395
+ - **Only these fields.** The front matter holds the fields above and nothing
396
+ else; the gate refuses one it does not read, since nothing would check what it
397
+ says. Everything else a spec has to say (where its words come from, a round's
398
+ history, a note for `make`) goes in the prose below it.
387
399
  - **`phone` is written first, and in full.** It is the most common screen, and the
388
400
  one a derived composition fails on worst.
389
401
  - **`motion:` lists every movement, and why it moves.** Each names what moves, its
@@ -489,10 +501,9 @@ to the spec, never the spec to the decisions.
489
501
  Step 3b checks the spec against the decisions. Nothing after it checks the spec
490
502
  against the owner's words or against the facts it states: `make` builds a
491
503
  confirmed spec as written, and `critique` compares the page to the spec, never
492
- the spec to what is true. On jig-site a confirmed spec for a docs chapter carried
493
- seven errors to the built page, among them a procedure Jig does not have and a
494
- lock written at the wrong moment, and the owner had confirmed it. The writer
495
- cannot catch these, for the same reason a builder cannot review its own page.
504
+ the spec to what is true. An error a confirmed spec carries (a feature the
505
+ product does not have, a step in the wrong order) is built into the page, and the
506
+ owner confirmed it without knowing. The writer cannot catch these, for the same reason a builder cannot review its own page.
496
507
 
497
508
  **Delegate to a subagent.** Give it the spec, `DECISIONS.md`, the owner's messages
498
509
  from this conversation, and read access to the project. Not your reasoning, and
@@ -501,7 +512,7 @@ not your summary of what the owner meant. It writes
501
512
 
502
513
  ```json
503
514
  {
504
- "spec": "sha256 of the spec file with its confirmed: line removed",
515
+ "spec": "`{{scripts_path}} checksum <name>` prints it: the spec with its confirmed: and mockup: lines emptied",
505
516
  "quotes": [
506
517
  { "quote": "Only where the steps differ by path", "said": "the owner, this conversation", "holds": true }
507
518
  ],
@@ -538,8 +549,8 @@ reader the earlier record and the spec's diff since it. A quotation or fact whos
538
549
  line did not change, and whose source has not changed since (`git diff` on that
539
550
  file), carries over as recorded; the reader checks the changed lines, the new
540
551
  ones, and any fact whose source moved. It still writes the whole record, with
541
- the new checksum. On jig-site each re-check opened every source again, about $10
542
- a round, to confirm facts on lines nobody had touched. **If you cannot
552
+ the new checksum. Opening every source again on each round costs the most on
553
+ exactly the lines nobody touched. **If you cannot
543
554
  delegate, write the record yourself, with `"reader": "the writer"` in it, and say
544
555
  in the confirmation message that nobody else checked the spec.** That is an
545
556
  honest gap the owner can close by reading more closely; a check you ran on your
@@ -584,9 +595,9 @@ they confirm.
584
595
  renames a region at any size, the approved drawing no longer shows the page: set
585
596
  `mockup: pending`, and `{{command_prefix}}mockup` redraws it for the owner. The gate
586
597
  checks it for a drawing in frames: while `mockup: approved`, each region the spec lists must be labelled in
587
- its size's frame of the drawing at `mockup_at:`. On jig-site the header spec went
588
- through five confirmed rounds after its drawing was approved, and still said
589
- `approved` over a drawing of none of them.
598
+ its size's frame of the drawing at `mockup_at:`. Otherwise a spec can go through
599
+ several confirmed rounds after its drawing was approved and still say `approved`
600
+ over a drawing of none of them.
590
601
 
591
602
  ## mockup
592
603
 
@@ -828,9 +839,9 @@ confirmed again.
828
839
  Record where the approved drawing is in `mockup_at:` — the file path, or the
829
840
  Figma or Stitch link. Only their own response counts; your summary of the
830
841
  drawing, or no objection, does not. **A condition they attach goes into the
831
- spec first**, in their words, on the lines it governs: on jig-site the owner
832
- approved with "three columns at 1280 and wider, inside the page margins", the
833
- condition lived only in the conversation, and `make` moved the switch to 1290.
842
+ spec first**, in their words, on the lines it governs. An approval "with three
843
+ columns at 1280 and wider" whose condition lives only in the conversation is
844
+ not what `make` builds: it reads the spec, and may put the switch anywhere.
834
845
  - The user says to skip it → `mockup: skipped — "<their words>"`. For a change
835
846
  small enough that drawing it costs more than building it, that is a reasonable
836
847
  call; it is still theirs to make.
@@ -887,10 +898,9 @@ and `make` is where decisions are carried out, not taken. When the build shows a
887
898
  decision is wrong, missing or in conflict with the spec, stop and say so: the owner
888
899
  changes it through `{{command_prefix}}decide`, or `{{command_prefix}}tweak` for a
889
900
  small change to a built page. A note that a decision has been carried out belongs in
890
- the spec, under `deviations:` or its as-built notes, not in the decision. On jig-site
891
- one make round added a decision and another rewrote one to match the tokens it had
892
- just switched to; the next critique judged the page against text the build had
893
- written. The gate stops a `make` session that changed `DECISIONS.md`.
901
+ the spec, under `deviations:` or its as-built notes, not in the decision. A build
902
+ that adds a decision, or rewrites one to match what it just built, leaves the next
903
+ critique judging the page against text the build wrote. The gate stops a `make` session that changed `DECISIONS.md`.
894
904
 
895
905
  Build V1 only. Nothing in `later:`, however little extra it looks.
896
906
 
@@ -1086,11 +1096,10 @@ refuses a `ruled` with no ruling or with one the file does not hold. A ruled
1086
1096
  verdict is reported, and counted apart (`ruled=`); it is not a finding, and it
1087
1097
  does not go back to `make`, which could only leave it as it is. **Put the field
1088
1098
  in each arm's brief, with its shape:** `{ "id": …, "verdict": "ruled", "ruling":
1089
- "<the decision's heading>", "reason": … }`. On jig-site an arm wrote four ruled
1090
- verdicts that named the decision only in `reason`, `verdicts` refused all four,
1091
- and the parent had to write the field into a file it was not to edit. On jig-site a
1092
- header critique counted 15 findings, five of them rulings labelled "owner-ruled"
1093
- in prose: every count was inflated, and the real findings were harder to see.
1099
+ "<the decision's heading>", "reason": … }`. An arm that names the decision only
1100
+ in `reason` has every ruled verdict refused by `verdicts`, and the parent is left
1101
+ to write the field into a file it is not to edit. Rulings counted as findings
1102
+ inflate every count, and the real findings are harder to see.
1094
1103
  A rule the page breaks with no decision behind it is a `finding`, however sure
1095
1104
  you are the owner would agree.
1096
1105
 
@@ -1168,11 +1177,17 @@ Each reader arm writes its own file. The arm reports back only that it wrote it.
1168
1177
  **`differences` holds what no rule names:** the page against its spec (step 3),
1169
1178
  or against a source it quotes or teaches. Each counts as a finding. Never carry
1170
1179
  one as a verdict under an id you made up: `verdicts` refuses an id the corpus
1171
- does not hold, and on jig-site both arms of one critique invented one
1172
- (`page-vs-corpus-1`), which the parent then had to move by hand. `ruled` is for a
1180
+ does not hold (`page-vs-corpus-1`), and the parent is left to move it by hand. `ruled` is for a
1173
1181
  rule a decision overrides; a decision in `decisions.json` is judged `ok`,
1174
1182
  `finding` or `n/a`, never ruled.
1175
1183
 
1184
+ **One problem, one entry.** A difference goes under `differences` only when no
1185
+ rule and no decision holds it. A stale figure is `I-148`'s finding; a page
1186
+ paraphrasing a source the owner decided it quotes is that decision's. File it
1187
+ there and nowhere else, and let the two arms' entries agree rather than repeat.
1188
+ One stale number filed as a rule's finding, a decision's, and a difference in
1189
+ each arm is four findings for one problem, and every count built on them is wrong.
1190
+
1176
1191
  **And the project's own decisions, one verdict each**, in
1177
1192
  `.jig/critique/<surface>/decisions.json`:
1178
1193
 
@@ -1328,9 +1343,8 @@ control or claim the page carries that no line of the spec asks for is a
1328
1343
  difference too, however accurate it is. The owner confirmed the spec, not the
1329
1344
  page; content the spec never held is content they never approved, and every
1330
1345
  later tweak and critique works from a spec that no longer says what is there.
1331
- On jig-site a chapter carried an accurate paragraph with no spec line and no
1332
- deviation, and two critiques in a row saw it and filed nothing, because it broke
1333
- no rule. Report it among the findings as a difference from the spec, naming the
1346
+ An accurate paragraph with no spec line and no deviation breaks no rule, so a
1347
+ critique that reads only the spec against the page sees it and files nothing. Report it among the findings as a difference from the spec, naming the
1334
1348
  content and where it is: the fix is a tweak that writes it into the spec for the
1335
1349
  owner to confirm, or removes it.
1336
1350
 
@@ -1462,10 +1476,10 @@ its own line, `B-106`), there is nothing to decide; do not invent a decision.
1462
1476
 
1463
1477
  The owner's words are the ones tweak.json records as `change`. A `**Why:**` you
1464
1478
  add quotes them, in quotation marks, and nothing else; what you read into them,
1465
- or into a screenshot the owner pointed at, goes under `**Why (inferred):**`. On
1466
- jig-site a tweak shown a picture of a copy button wrote an exception to `E-51`
1467
- "given directly by the owner … by reference rather than words": a ruling nobody
1468
- gave, which every later critique would have judged the page by. The gate stops a
1479
+ or into a screenshot the owner pointed at, goes under `**Why (inferred):**`. A
1480
+ tweak shown a picture that writes an exception "given directly by the owner … by
1481
+ reference rather than words" records a ruling nobody gave, and every later
1482
+ critique judges the page by it. The gate stops a
1469
1483
  tweak whose new `**Why:**` quotes words tweak.json does not hold.
1470
1484
 
1471
1485
  **A decision you record or amend covers the whole page, not the one place it
@@ -1473,9 +1487,9 @@ was raised.** The owner rules on an instance ("keep this apostrophe curly") and
1473
1487
  the decision states a kind ("every apostrophe, curly"). Before you build, look
1474
1488
  through the page, and the chrome it shares, for every other instance of that
1475
1489
  kind, and bring each one in line in the same change; name them in your report.
1476
- On jig-site a tweak recorded "every apostrophe and quotation mark curly" and
1477
- fixed the one apostrophe the critique had named; three straight ones and a pair
1478
- of straight quotation marks on the same page survived to the next critique.
1490
+ A tweak that records "every apostrophe and quotation mark curly" and fixes only
1491
+ the one the critique named leaves the rest of the page's straight marks for the
1492
+ next critique to find.
1479
1493
 
1480
1494
  ### 2. Bring the spec in line, if it disagrees
1481
1495
 
@@ -1547,7 +1561,9 @@ Build the project the way it ships, then run `{{scripts_path}} ship`. It runs
1547
1561
  `check --all --ci` and `seo`, and reads every confirmed spec's critique: a page
1548
1562
  is owed a critique when it has none, when its page changed after it was judged,
1549
1563
  when a tweak deferred its re-judge, when its verdicts are incomplete, or when a
1550
- finding stands that the owner has not ruled on. It prints each page's state and
1564
+ finding stands that the owner has not ruled on. A page that is as judged but
1565
+ whose stylesheets or scripts changed is owed only a re-probe
1566
+ (`{{scripts_path}} verdicts <page> --reprobe`), not a critique. It prints each page's state and
1551
1567
  a `JIG_SHIP:` line, and exits non-zero until the project is ready. A spec that
1552
1568
  is not confirmed yet is in progress and not held against the ship. Nor is a spec
1553
1569
  another has replaced: `superseded_by: <spec>` in its front matter leaves its page
@@ -1617,14 +1633,15 @@ review, never by the builder editing the last one.
1617
1633
  When a `critique` or `tweak` session stops, the gate records its verdicts in
1618
1634
  `.jig/critique/<surface>/verdicts.lock`. That happens after you have committed, so
1619
1635
  if your verdicts are committed it stops you once more to commit the lock on its
1620
- own; the next stop passes.
1636
+ own; the next stop passes. The same goes for a page's probe files: when the page
1637
+ changed since they were taken, the gate renders it again as you stop, and if
1638
+ your work is committed it stops you once to commit them on their own.
1621
1639
 
1622
1640
  **The lock is the gate's to write, never yours.** When the gate is wrong (it
1623
1641
  misreads the session, or asks for something the procedure does not), say what it
1624
- got wrong, leave the lock as it is, and report the work as held by the gate. On
1625
- jig-site the gate misread a tweak as no command at all, and the session computed
1626
- the lock by hand and committed it. The lock was right that time, and a lock an
1627
- agent can write is still a record of nothing.
1642
+ got wrong, leave the lock as it is, and report the work as held by the gate. A
1643
+ lock computed by hand may even be right, and a lock an agent can write is still a
1644
+ record of nothing.
1628
1645
 
1629
1646
  It judges the critiques this session touched: any with a file changed since the
1630
1647
  session began, and the current spec's surface when you ran `critique`. Another
@@ -1645,6 +1662,14 @@ It exists because every "run check" and "run verdicts" step in these procedures
1645
1662
  skipped in a live run, and pages that did not render their styles were reported
1646
1663
  clean.
1647
1664
 
1665
+ ## checksum
1666
+
1667
+ Run `{{scripts_path}} checksum <spec>`, passing the argument through, and report the
1668
+ value it prints. It is the `spec` field of `.jig/specs/<name>.checked.json`: the
1669
+ spec's checksum with its `confirmed:` and `mockup:` lines emptied, which the owner's
1670
+ answer sets after the check. Never compute it yourself: a hand-computed value is
1671
+ easily wrong, and a wrong one reads as a spec that changed after its check.
1672
+
1648
1673
  ## verdicts
1649
1674
 
1650
1675
  Run `{{scripts_path}} verdicts <surface>`, passing the argument through, and report its
@@ -1852,9 +1877,9 @@ weighs it as the team's and applies the rule where the team never would.
1852
1877
 
1853
1878
  What you add to explain a reason, work out from it, or carry over from what the
1854
1879
  owner said elsewhere goes in its own paragraph, `**Why (inferred):**`, which says it
1855
- is yours. On jig-site, reasons read "given directly by the owner", followed by
1856
- sentences the agent had written; a later agent could not tell which half to weigh
1857
- as the team's. The gate checks each decision this session wrote or changed: its
1880
+ is yours. A reason that reads "given directly by the owner" and goes on in the
1881
+ agent's own sentences leaves a later agent unable to tell which half to weigh as
1882
+ the team's. The gate checks each decision this session wrote or changed: its
1858
1883
  `Why` is quoted, `not given`, or labelled inferred.
1859
1884
 
1860
1885
  **Record what is still open in its own section, at the end:**
@@ -36,6 +36,18 @@ cite the number when you follow or deliberately break one.
36
36
  `.jig/specs/<name>.checked.json` (its step 4), `{{command_prefix}}mockup`'s
37
37
  size by size against the spec (its step 3, rendering every frame). Confirm
38
38
  only what you checked yourself, and name to the owner what you could not.
39
+ **Recording the owner's word?** A spec confirmed, a drawing approved or
40
+ skipped, a re-judge left for later, a tweak's change, a decision's reason:
41
+ each is the owner's words, quoted as they said them, and words that say that
42
+ thing. A remark about the layout is not a skip of the mockup; a yes to one
43
+ question is not a yes to the spec. When they have not said it, ask. What you
44
+ read into their words goes under a label that says it is yours
45
+ (`**Why (inferred):**`), never inside their quotation marks.
46
+ **Recording something Jig has no field for?** Write it in prose, below a
47
+ spec's front matter or in the report. Never invent a front-matter key, a
48
+ verdict id or a JSON field for it: nothing reads an invented one, so what it
49
+ says is lost to every check. If it keeps recurring, tell the owner, since
50
+ Jig may be missing a field.
39
51
  **Building a screen rather than a single component?** Read `L-01 · Layout
40
52
  method` in `{{rules_path}}/03-patterns.md` and run its five steps before
41
53
  writing any markup. It is a procedure, not a component, so step 4 never
@@ -34,6 +34,11 @@
34
34
  "argumentHint": "",
35
35
  "status": "available"
36
36
  },
37
+ "checksum": {
38
+ "description": "Print a spec's checksum: the value its `.checked.json` records as `spec`, so a spec's reader never computes it by hand.",
39
+ "argumentHint": "<spec>",
40
+ "status": "available"
41
+ },
37
42
  "verdicts": {
38
43
  "description": "Verify a critique's verdict files: every rule in each pass judged once, no id that does not exist, no rule in the wrong arm, rendered only with a screenshot. Computes the counts the critique reports, so the agent never writes them.",
39
44
  "argumentHint": "<surface>",