jig-ui 0.18.2 → 0.18.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +115 -51
  2. package/dist/index.js +64 -9
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.5 (2026-09-25)
4
+
5
+ The gate holds an HTML mockup that does not draw the page at every size.
6
+
7
+ ### Fixed
8
+
9
+ - **The gate holds a mockup that does not show every size.** On jig-site three
10
+ HTML mockups in a row were single responsive pages, so the owner saw only the
11
+ width of the window they opened and asked twice where the other sizes were.
12
+ The procedure's wireframe template draws the page once per size, side by
13
+ side, in `.frame[data-size]` boxes, and nothing checked a drawing used them.
14
+ When a `mockup` session stops with an HTML drawing, the gate now requires a
15
+ frame for phone (360), tablet (768), desktop (1280) and wide (1600).
16
+
17
+ ## 0.18.4 (2026-09-25)
18
+
19
+ Every release summary is one or two lines, for jig-site's Versions page.
20
+
21
+ ### Changed
22
+
23
+ - **Every release summary is one or two lines, with no em dash.** jig-site's
24
+ Versions page shows the summary under each release, so it is interface text.
25
+ Nine ran to three to thirteen lines; their detail now sits under
26
+ `### Upgrading` or `### Notes` in the same release. A test keeps summaries
27
+ short.
28
+
29
+ ## 0.18.3 (2026-09-25)
30
+
31
+ Recording a decision no longer undoes the critiques written before it, and an
32
+ older probe file says it is older rather than forged.
33
+
34
+ ### Fixed
35
+
36
+ - **A decision recorded after a critique no longer undoes it.** On jig-site one
37
+ `/jig decide` session added eight decisions; every finished critique turned
38
+ "incomplete", and the gate stopped an unrelated spec session over records that
39
+ could not have judged them. `jig verdicts` now asks git: a decision whose
40
+ heading was added in a commit the critique's `decisions.json` commit does not
41
+ contain, or not committed yet, is left for the next critique and listed as
42
+ such. Without git, or while `decisions.json` has uncommitted changes (a
43
+ critique in progress), every decision is still required.
44
+ - **An older probe file is called older, not forged.** After a release changed
45
+ the probe's version, the old files read "not output of `jig probe` … do not
46
+ write it by hand", and an agent stopped work believing they were fabricated.
47
+ They now say which version took them and to record them again.
48
+
3
49
  ## 0.18.2 (2026-09-25)
4
50
 
5
51
  Every release in this changelog now carries its date and a one-line summary,
@@ -52,9 +98,8 @@ menu, and `A-05` missed an arrow that renders as an emoji.
52
98
 
53
99
  ## 0.18.0 (2026-09-25)
54
100
 
55
- A page's frame gets tokens, a project gets a place to record where its layout
56
- switches, and keyboard access a rule requires fits every script budget. All of
57
- it found building jig-site's header and Reference with the full loop.
101
+ A page's frame gets tokens, a project records where its layout switches, and
102
+ keyboard access a rule requires fits every script budget.
58
103
 
59
104
  ### Added
60
105
 
@@ -161,8 +206,12 @@ The gate judges only the critiques a session touched.
161
206
  ## 0.17.0 (2026-09-24)
162
207
 
163
208
  Thirteen more tells of a generated page, ten of them caught by `check`, and a
164
- picture for every rule. Also carries the probe and verdict fixes tagged as 0.16.2,
165
- which was not published to npm.
209
+ picture for every rule.
210
+
211
+ ### Notes
212
+
213
+ Also carries the probe and verdict fixes tagged as 0.16.2, which was not
214
+ published to npm.
166
215
 
167
216
  ### Added
168
217
 
@@ -448,8 +497,8 @@ One new rule: no em dashes in interface text (`I-118`), with a detector.
448
497
 
449
498
  ## 0.11.1 (2026-09-18)
450
499
 
451
- Two holes in the gate, both found by running the loop twice on 0.11.0 —
452
- once on Haiku, once on Sonnet.
500
+ Two holes in the gate, found by running the loop twice on 0.11.0: once on
501
+ Haiku, once on Sonnet.
453
502
 
454
503
  ### Fixed
455
504
 
@@ -467,9 +516,8 @@ once on Haiku, once on Sonnet.
467
516
 
468
517
  ## 0.11.0 (2026-09-18)
469
518
 
470
- One release, one lesson: a measurement an agent can type is not a
471
- measurement. Everything here came from two live runs at the capability
472
- floor the day 0.10.0 shipped.
519
+ A measurement an agent can type is not a measurement. Everything here came
520
+ from two live runs at the capability floor.
473
521
 
474
522
  ### Added
475
523
 
@@ -496,9 +544,8 @@ floor the day 0.10.0 shipped.
496
544
 
497
545
  ## 0.10.0 (2026-09-18)
498
546
 
499
- Mobile-first, and a design loop that a weak model cannot skip. Everything here
500
- was measured on live runs at the capability floor (Haiku), and most of it exists
501
- because an instruction the agent could choose to ignore was ignored.
547
+ Mobile-first, and a design loop that a weak model cannot skip, measured on live
548
+ runs with Haiku.
502
549
 
503
550
  ### Added
504
551
 
@@ -562,9 +609,8 @@ because an instruction the agent could choose to ignore was ignored.
562
609
 
563
610
  ## 0.9.0 (2026-09-13)
564
611
 
565
- One new rule and one amended correction, both from the same afternoon of
566
- dogfooding and both about the same blind spot: H-47's correction always pointed
567
- at a token, so an agent reading it literally always produced one.
612
+ One new rule and one amended correction, both about the same blind spot: H-47's
613
+ correction always pointed an agent at a token.
568
614
 
569
615
  ### Added
570
616
 
@@ -607,12 +653,12 @@ at a token, so an agent reading it literally always produced one.
607
653
 
608
654
  ## 0.8.2 (2026-09-12)
609
655
 
610
- Every fix here was found by a consumer using Jig rather than by Jig checking
611
- itself: the documentation site was upgraded to 0.8.1 and then styled in
612
- Tailwind, which is the first time Jig's Tailwind guidance had been followed
613
- end to end by anything other than its own tests.
656
+ Four fixes found by following Jig's Tailwind guidance end to end on its own
657
+ documentation site.
658
+
659
+ ### Notes
614
660
 
615
- Three of the four are the same shape — two places answering one question, and
661
+ Three of the four are the same shape: two places answering one question, and
616
662
  disagreeing without either knowing the other existed.
617
663
 
618
664
  ### Fixed
@@ -686,10 +732,8 @@ disagreeing without either knowing the other existed.
686
732
 
687
733
  ## 0.8.1 (2026-09-12)
688
734
 
689
- Both fixes here are the same shape: 0.8.0 corrected the instance it was looking
690
- at and left the class alone, and in each case the commit message claimed a
691
- verification that had only checked the file it had just edited. Both were found
692
- by inspecting the published tarball rather than the working tree.
735
+ Two fixes where 0.8.0 corrected one instance and left the class alone, both
736
+ found by inspecting the published tarball.
693
737
 
694
738
  ### Fixed
695
739
 
@@ -746,9 +790,10 @@ by inspecting the published tarball rather than the working tree.
746
790
 
747
791
  ## 0.8.0 (2026-09-11)
748
792
 
749
- Everything here was found by handing Jig to agents that had never seen it and
750
- asking them to build something real — its own documentation site. None of it
751
- was found by the test suite, which passed throughout.
793
+ Fixes found by agents new to Jig building its documentation site. The test
794
+ suite passed throughout and caught none of them.
795
+
796
+ ### Notes
752
797
 
753
798
  Minor rather than patch: `explain` prints lines it did not print before, and
754
799
  `init` can write a file it did not write before.
@@ -884,6 +929,8 @@ Minor rather than patch: `explain` prints lines it did not print before, and
884
929
 
885
930
  A rule file that contradicted the tool, and the guard that kept it that way.
886
931
 
932
+ ### Notes
933
+
887
934
  Patch: the shipped rules change, but no command writes anything different.
888
935
 
889
936
  ### Fixed
@@ -936,7 +983,9 @@ already knew where the tokens were.
936
983
 
937
984
  ## 0.7.0 (2026-09-11)
938
985
 
939
- A silent no-op, fixed, plus the missing half of 0.6.0's token-layer move.
986
+ A silent no-op, fixed, and the missing half of 0.6.0's token-layer move.
987
+
988
+ ### Notes
940
989
 
941
990
  Minor rather than patch, and the call is arguable. The non-TTY fix is a
942
991
  correction; the relocation offer is new behaviour that can move files, though
@@ -978,19 +1027,25 @@ to move their token layer should read these notes.
978
1027
 
979
1028
  ## 0.6.0 (2026-09-11)
980
1029
 
981
- The token layer stops hiding in a dotfolder, and `check` starts reading it back.
1030
+ The token layer leaves its dotfolder, and `check` reads the layer's own
1031
+ declarations back.
982
1032
 
983
- Both came from the same question: who should write the tokens. The answer turned
984
- out to depend on something that did not exist — **nothing validated the token
985
- layer's own declarations.** `init` checked a brand colour once, at write time,
986
- and no command ever looked again. A generated file edited afterwards, by a person
987
- or an agent, went unexamined: `--color-text-weak` dropped to 22% opacity and
988
- `check` reported "No findings". With that closed, where the files live and who
989
- writes them become ordinary decisions rather than load-bearing ones.
1033
+ ### Upgrading
990
1034
 
991
- **Upgrading:** run `npx jig-ui@latest update`, then `npx jig-ui@latest init`.
992
- Existing installs keep their `.jig/tokens/` layout — nothing moves unless you
993
- move it, because relocating files could break an import you wrote yourself.
1035
+ Run `npx jig-ui@latest update`, then `npx jig-ui@latest init`. Existing installs
1036
+ keep their `.jig/tokens/` layout. Nothing moves unless you move it, because
1037
+ relocating files could break an import you wrote yourself.
1038
+
1039
+ ### Notes
1040
+
1041
+ Both changes came from the same question: who should write the tokens. The
1042
+ answer turned out to depend on something that did not exist: **nothing
1043
+ validated the token layer's own declarations.** `init` checked a brand colour
1044
+ once, at write time, and no command ever looked again. A generated file edited
1045
+ afterwards, by a person or an agent, went unexamined: `--color-text-weak`
1046
+ dropped to 22% opacity and `check` reported "No findings". With that closed,
1047
+ where the files live and who writes them become ordinary decisions rather than
1048
+ load-bearing ones.
994
1049
 
995
1050
  ### Added
996
1051
 
@@ -1072,18 +1127,24 @@ move it, because relocating files could break an import you wrote yourself.
1072
1127
 
1073
1128
  ## 0.5.0 (2026-09-10)
1074
1129
 
1075
- Four things shipped in 0.4.0 were broken in ways that reported success. `/jig
1076
- update` refreshed to the version already installed and said "Updated Jig →
1077
- 0.4.0". Dark mode could not be reached by choosing it. `check` skipped nearly
1078
- every colour in a project that had not run `init`. And the reconciliation of
1079
- every numeric default against an external reference is finished — 0 rows open —
1080
- which is where most of the rest of this release came from.
1130
+ Four things 0.4.0 reported as working did not, and the reconciliation of every
1131
+ numeric default against an external reference is finished.
1132
+
1133
+ ### Upgrading
1081
1134
 
1082
1135
  **If you are on 0.4.0, run `npx jig-ui@latest update` from a terminal.** The
1083
1136
  `/jig update` fix cannot deliver itself: your command file is the broken one, so
1084
1137
  the slash command will keep reporting a successful no-op until the CLI replaces
1085
1138
  it. Once, from the terminal, and the slash command works from then on.
1086
1139
 
1140
+ ### Notes
1141
+
1142
+ The four: `/jig update` refreshed to the version already installed and said
1143
+ "Updated Jig → 0.4.0". Dark mode could not be reached by choosing it. `check`
1144
+ skipped nearly every colour in a project that had not run `init`. And the
1145
+ reconciliation ended with 0 rows open, which is where most of the rest of this
1146
+ release came from.
1147
+
1087
1148
  ### Fixed
1088
1149
 
1089
1150
  - **`/jig update` could never upgrade anyone.** Every subcommand is invoked at
@@ -1166,11 +1227,14 @@ them, and nothing at all checked that a token cited in the rules exists.
1166
1227
 
1167
1228
  ## 0.4.0 (2026-09-04)
1168
1229
 
1169
- Jig stops copying itself into your project. It is a skill an agent reads, and
1170
- 0.3.0 wrote 220KB across 17 files into every consuming repo to deliver it —
1171
- roughly 200KB of that Jig's own property, read by an agent that already had it
1172
- from the skill install. A single-mode project now gets **three** files, all of
1173
- them its own.
1230
+ Jig stops copying itself into your project. A single-mode project now gets
1231
+ **three** files, all of them its own.
1232
+
1233
+ ### Notes
1234
+
1235
+ Jig is a skill an agent reads, and 0.3.0 wrote 220KB across 17 files into every
1236
+ consuming repo to deliver it. Roughly 200KB of that was Jig's own, read by an
1237
+ agent that already had it from the skill install.
1174
1238
 
1175
1239
  ### Changed
1176
1240
 
package/dist/index.js CHANGED
@@ -5673,8 +5673,9 @@ Could not write to ${wireTarget}: ${err.message}`);
5673
5673
  }
5674
5674
 
5675
5675
  // src/commands/verdicts.ts
5676
+ import { execFileSync as execFileSync3 } from "child_process";
5676
5677
  import { existsSync as existsSync23, readFileSync as readFileSync30 } from "fs";
5677
- import { join as join37, resolve as resolve5 } from "path";
5678
+ import { join as join37, relative as relative4, resolve as resolve5 } from "path";
5678
5679
 
5679
5680
  // src/rules/citations.ts
5680
5681
  import { join as join29 } from "path";
@@ -6258,6 +6259,10 @@ function readProbes(projectRoot, dir, errors) {
6258
6259
  for (const f of readdirSync13(dir).filter((n) => /^probe-\d+\.json$/.test(n)).sort()) {
6259
6260
  try {
6260
6261
  const p = JSON.parse(readFileSync27(join34(dir, f), "utf8"));
6262
+ if (typeof p.jigProbe === "number" && p.jigProbe < PROBE_VERSION && typeof p.width === "number") {
6263
+ errors.push(`${f} was taken by an older \`jig probe\` (version ${p.jigProbe}; this Jig reads version ${PROBE_VERSION}). Record it again with \`jig probe --run\`.`);
6264
+ continue;
6265
+ }
6261
6266
  if (p.jigProbe !== PROBE_VERSION || typeof p.width !== "number") {
6262
6267
  errors.push(`${f} is not output of \`jig probe\` (version ${PROBE_VERSION}). Re-run the probe; do not write it by hand.`);
6263
6268
  continue;
@@ -6366,21 +6371,24 @@ function decisionsFile(projectRoot) {
6366
6371
  return void 0;
6367
6372
  }
6368
6373
  function decisionNames(projectRoot) {
6374
+ return [...decisionHeadings(projectRoot).keys()];
6375
+ }
6376
+ function decisionHeadings(projectRoot) {
6377
+ const headings = /* @__PURE__ */ new Map();
6369
6378
  const path = decisionsFile(projectRoot);
6370
- if (!path) return [];
6379
+ if (!path) return headings;
6371
6380
  let body;
6372
6381
  try {
6373
6382
  body = readFileSync28(join35(projectRoot, path), "utf8");
6374
6383
  } catch {
6375
- return [];
6384
+ return headings;
6376
6385
  }
6377
- const names = [];
6378
6386
  for (const match of body.matchAll(HEADING3)) {
6379
6387
  const name = match[2].replace(/[`*]/g, "").trim();
6380
6388
  if (!name || NOT_A_DECISION.test(name)) continue;
6381
- if (!names.includes(name)) names.push(name);
6389
+ if (!headings.has(name)) headings.set(name, match[0].trim());
6382
6390
  }
6383
- return names;
6391
+ return headings;
6384
6392
  }
6385
6393
 
6386
6394
  // src/check/spec-shape.ts
@@ -6583,11 +6591,41 @@ function checkDecisions(projectRoot, dir, errors) {
6583
6591
  else if (ABSENCE.test(reason)) errors.push(`decisions.json: "${match}" \u2014 "${reason}" says the decision was not read.`);
6584
6592
  if (v.verdict === "finding") findings++;
6585
6593
  }
6586
- const missing = required.filter((r) => !seen.has(r));
6594
+ const unjudged = required.filter((r) => !seen.has(r));
6595
+ const since = decisionsSince(projectRoot, dir, unjudged);
6596
+ const missing = unjudged.filter((r) => !since.includes(r));
6597
+ const total = required.length - since.length;
6587
6598
  if (missing.length) {
6588
- errors.push(`decisions.json: ${missing.length} of ${required.length} decisions have no verdict: ${missing.join(", ")}.`);
6599
+ errors.push(`decisions.json: ${missing.length} of ${total} decisions have no verdict: ${missing.join(", ")}.`);
6600
+ }
6601
+ return { state: missing.length ? "incomplete" : "ran", judged: total - missing.length, total, findings, ...since.length ? { since } : {} };
6602
+ }
6603
+ function decisionsSince(projectRoot, dir, unjudged) {
6604
+ if (unjudged.length === 0) return [];
6605
+ const path = decisionsFile(projectRoot);
6606
+ if (!path) return [];
6607
+ const git = (args) => execFileSync3("git", args, { cwd: projectRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
6608
+ try {
6609
+ const verdictFile = relative4(projectRoot, join37(dir, "decisions.json"));
6610
+ if (git(["status", "--porcelain", "--", verdictFile])) return [];
6611
+ const judgedIn = git(["log", "-1", "--format=%H", "--", verdictFile]);
6612
+ if (!judgedIn) return [];
6613
+ const headings = decisionHeadings(projectRoot);
6614
+ return unjudged.filter((name) => {
6615
+ const line = headings.get(name);
6616
+ if (!line) return false;
6617
+ const addedIn = git(["log", "--format=%H", "-S", line, "--", path]).split("\n").filter(Boolean).pop();
6618
+ if (!addedIn) return true;
6619
+ try {
6620
+ git(["merge-base", "--is-ancestor", addedIn, judgedIn]);
6621
+ return false;
6622
+ } catch {
6623
+ return true;
6624
+ }
6625
+ });
6626
+ } catch {
6627
+ return [];
6589
6628
  }
6590
- return { state: missing.length ? "incomplete" : "ran", judged: required.length - missing.length, total: required.length, findings };
6591
6629
  }
6592
6630
  function verifyVerdicts(opts) {
6593
6631
  const root = opts.packageRoot ?? assetRoot();
@@ -6760,6 +6798,7 @@ function commandProblems(root, command) {
6760
6798
  else if (!/^https?:/i.test(at) && !existsSync24(join38(root, at))) problems.push(`${spec.path}: \`mockup_at: ${at}\` does not exist.`);
6761
6799
  else if (!/^https?:/i.test(at) && !at.startsWith(".jig/mockups/")) problems.push(`The drawing is at ${at}. A mockup lives in .jig/mockups/, outside what check scans and outside what ships.`);
6762
6800
  }
6801
+ if (at && /\.html?$/i.test(at) && existsSync24(join38(root, at))) problems.push(...mockupFrameProblems(root, at));
6763
6802
  }
6764
6803
  if (command === "critique") {
6765
6804
  const dir = join38(root, ".jig", "critique");
@@ -6867,6 +6906,20 @@ ${problems.join("\n\n")}`
6867
6906
  ${problems.join("\n\n")}`
6868
6907
  };
6869
6908
  }
6909
+ var MOCKUP_FRAMES = [["phone", 360], ["tablet", 768], ["desktop", 1280], ["wide", 1600]];
6910
+ function mockupFrameProblems(root, at) {
6911
+ let html;
6912
+ try {
6913
+ html = readFileSync31(join38(root, at), "utf8");
6914
+ } catch {
6915
+ return [];
6916
+ }
6917
+ const missing = MOCKUP_FRAMES.filter(([size]) => !new RegExp(`data-size\\s*=\\s*["']${size}["']`).test(html));
6918
+ if (missing.length === 0) return [];
6919
+ return [
6920
+ `${at} has no frame for ${missing.map(([size, px2]) => `${size} (${px2}px)`).join(", ")}. A mockup draws the page once per size, side by side, in the wireframe template's \`<div class="frame" data-size="\u2026">\` boxes, so the owner sees every size at once. A single responsive page shows only the width of the window it is opened in.`
6921
+ ];
6922
+ }
6870
6923
  var VERDICT_FILES = ["screen.json", "code.json", "decisions.json"];
6871
6924
  var LOCK = "verdicts.lock";
6872
6925
  function verdictChecksum(dir) {
@@ -7120,6 +7173,8 @@ program.command("verdicts").description("Verify a critique's verdict files and c
7120
7173
  const result = verifyVerdicts({ projectRoot, surface });
7121
7174
  for (const error of result.errors) console.error(` \u2717 ${error}`);
7122
7175
  if (result.ok) console.log(` Every rule in both passes has a verdict.`);
7176
+ const since = result.decisions.since ?? [];
7177
+ if (since.length) console.log(` ${since.length} decision(s) recorded after this critique, for the next one to judge: ${since.join(", ")}.`);
7123
7178
  console.log(` ${result.line}`);
7124
7179
  process.exit(result.ok ? 0 : 1);
7125
7180
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jig-ui",
3
- "version": "0.18.2",
3
+ "version": "0.18.5",
4
4
  "description": "A design system for coding agents. 143 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",