@scribe-platform/cli 0.7.0 → 0.9.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.
Files changed (65) hide show
  1. package/README.md +28 -0
  2. package/dist/commands/login.d.ts.map +1 -1
  3. package/dist/commands/login.js +15 -1
  4. package/dist/commands/login.js.map +1 -1
  5. package/dist/commands/proof.d.ts +5 -0
  6. package/dist/commands/proof.d.ts.map +1 -0
  7. package/dist/commands/proof.js +440 -0
  8. package/dist/commands/proof.js.map +1 -0
  9. package/dist/commands/prospect.d.ts +27 -0
  10. package/dist/commands/prospect.d.ts.map +1 -0
  11. package/dist/commands/prospect.js +222 -0
  12. package/dist/commands/prospect.js.map +1 -0
  13. package/dist/commands/request.d.ts +38 -0
  14. package/dist/commands/request.d.ts.map +1 -0
  15. package/dist/commands/request.js +214 -0
  16. package/dist/commands/request.js.map +1 -0
  17. package/dist/commands/site.d.ts +11 -0
  18. package/dist/commands/site.d.ts.map +1 -1
  19. package/dist/commands/site.js +41 -3
  20. package/dist/commands/site.js.map +1 -1
  21. package/dist/commands/update.d.ts +10 -0
  22. package/dist/commands/update.d.ts.map +1 -1
  23. package/dist/commands/update.js +128 -31
  24. package/dist/commands/update.js.map +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +15 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/lib/claude-hook.d.ts +74 -0
  29. package/dist/lib/claude-hook.d.ts.map +1 -0
  30. package/dist/lib/claude-hook.js +108 -0
  31. package/dist/lib/claude-hook.js.map +1 -0
  32. package/dist/lib/client.d.ts +351 -0
  33. package/dist/lib/client.d.ts.map +1 -1
  34. package/dist/lib/client.js +159 -0
  35. package/dist/lib/client.js.map +1 -1
  36. package/dist/lib/proof-folder.d.ts +86 -0
  37. package/dist/lib/proof-folder.d.ts.map +1 -0
  38. package/dist/lib/proof-folder.js +226 -0
  39. package/dist/lib/proof-folder.js.map +1 -0
  40. package/dist/lib/proof-preview.d.ts +39 -0
  41. package/dist/lib/proof-preview.d.ts.map +1 -0
  42. package/dist/lib/proof-preview.js +318 -0
  43. package/dist/lib/proof-preview.js.map +1 -0
  44. package/dist/lib/proof-push.d.ts +42 -0
  45. package/dist/lib/proof-push.d.ts.map +1 -0
  46. package/dist/lib/proof-push.js +91 -0
  47. package/dist/lib/proof-push.js.map +1 -0
  48. package/dist/lib/skill.d.ts +13 -0
  49. package/dist/lib/skill.d.ts.map +1 -1
  50. package/dist/lib/skill.js +33 -2
  51. package/dist/lib/skill.js.map +1 -1
  52. package/dist/lib/update-check.d.ts +46 -0
  53. package/dist/lib/update-check.d.ts.map +1 -0
  54. package/dist/lib/update-check.js +103 -0
  55. package/dist/lib/update-check.js.map +1 -0
  56. package/package.json +5 -3
  57. package/runtime/proof.js +139 -0
  58. package/skills/scribe-site-builder/SKILL.md +175 -33
  59. package/skills/scribe-site-builder/recipes/README.md +11 -3
  60. package/skills/scribe-site-builder/recipes/domains.md +151 -0
  61. package/skills/scribe-site-builder/recipes/forms.md +5 -2
  62. package/skills/scribe-site-builder/recipes/proofs.md +311 -0
  63. package/skills/scribe-site-builder/recipes/prospects.md +192 -0
  64. package/skills/scribe-site-builder/recipes/requests.md +145 -0
  65. package/skills/scribe-site-builder/recipes/schema.md +24 -0
@@ -0,0 +1,103 @@
1
+ export const PACKAGE_NAME = '@scribe-platform/cli';
2
+ /**
3
+ * The published package is **public**, so this is a plain unauthenticated GET
4
+ * — no `npm view` subprocess, no auth, no dependency on the admin app knowing
5
+ * which CLI version is current.
6
+ *
7
+ * The `-/package/<name>/dist-tags` route rather than the package document:
8
+ * it answers in ~200ms with 18 bytes, where the full packument is 30KB of
9
+ * every version ever published. At that price the check can run at every
10
+ * session start instead of being cached, which is the difference between
11
+ * Ashley getting a fix now and getting it tomorrow.
12
+ */
13
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
14
+ /**
15
+ * Short on purpose. This runs at session start, in front of someone waiting to
16
+ * type, and a registry that is slow is indistinguishable from one that is down
17
+ * — in both cases the right answer is to stop waiting and carry on unupdated.
18
+ */
19
+ const FETCH_TIMEOUT_MS = 3_000;
20
+ /**
21
+ * Compares two dotted numeric versions. Returns true when `candidate` is newer
22
+ * than `current`.
23
+ *
24
+ * Deliberately not a semver dependency: this package publishes plain
25
+ * `major.minor.patch` and the one judgement call — what to do with a
26
+ * prerelease suffix — is answered by ignoring it. A `0.8.0-beta.1` compares
27
+ * equal to `0.8.0`, so someone already on the beta is not told to "update" to
28
+ * the release they effectively have, and someone on `0.7.0` is offered it.
29
+ * Shipping a prerelease to `latest` is not something this project does.
30
+ */
31
+ export function isNewer(candidate, current) {
32
+ const parts = (v) => v
33
+ .split('-')[0]
34
+ .split('.')
35
+ .map((n) => Number.parseInt(n, 10))
36
+ .map((n) => (Number.isNaN(n) ? 0 : n));
37
+ const a = parts(candidate);
38
+ const b = parts(current);
39
+ for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
40
+ const left = a[i] ?? 0;
41
+ const right = b[i] ?? 0;
42
+ if (left !== right)
43
+ return left > right;
44
+ }
45
+ return false;
46
+ }
47
+ /** The registry's `latest` dist-tag, or null if it can't be reached in time. */
48
+ async function fetchLatest() {
49
+ const registry = process.env.SCRIBE_CLI_REGISTRY ?? DEFAULT_REGISTRY;
50
+ const url = `${registry}/-/package/${PACKAGE_NAME.replace('/', '%2F')}/dist-tags`;
51
+ const controller = new AbortController();
52
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
53
+ try {
54
+ const res = await fetch(url, { signal: controller.signal });
55
+ if (!res.ok)
56
+ return null;
57
+ const body = (await res.json());
58
+ return body.latest ?? null;
59
+ }
60
+ catch {
61
+ // Offline, slow, rate-limited, or a registry that answered with something
62
+ // unexpected. All the same from here: no opinion about updates.
63
+ return null;
64
+ }
65
+ finally {
66
+ clearTimeout(timer);
67
+ }
68
+ }
69
+ /**
70
+ * Whether a newer CLI has been published.
71
+ *
72
+ * Runs on **every** session start, with no cache. An earlier version cached
73
+ * the answer for a day to keep a round trip off the front of each
74
+ * conversation; measuring it made that look like the wrong trade — 210ms
75
+ * against being up to a day late on a fix, plus a cache that silently
76
+ * swallowed the environment override this is tested with. Checking every time
77
+ * is both faster to the user and less code.
78
+ */
79
+ export async function checkForUpdate(current) {
80
+ // Ahead of the fetch and never persisted. This is the knob the local test
81
+ // recipe turns — see TESTING-UPDATES.md.
82
+ const forced = process.env.SCRIBE_CLI_LATEST;
83
+ if (forced) {
84
+ return { current, latest: forced, updateAvailable: isNewer(forced, current), reachable: true };
85
+ }
86
+ const latest = await fetchLatest();
87
+ return {
88
+ current,
89
+ latest,
90
+ updateAvailable: latest !== null && isNewer(latest, current),
91
+ reachable: latest !== null,
92
+ };
93
+ }
94
+ /**
95
+ * What `npm install -g` is pointed at.
96
+ *
97
+ * Overridable so the whole update path can be exercised against a local
98
+ * `npm pack` tarball before anything is published — see TESTING-UPDATES.md.
99
+ */
100
+ export function installSpec() {
101
+ return process.env.SCRIBE_CLI_PACKAGE ?? `${PACKAGE_NAME}@latest`;
102
+ }
103
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scribe-platform/cli",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Command-line interface for Scribe CMS — scaffold sites, edit content, and triage form submissions from the terminal",
5
5
  "license": "MIT",
6
6
  "author": "Dave Weaver",
@@ -32,6 +32,7 @@
32
32
  "files": [
33
33
  "bin",
34
34
  "dist",
35
+ "runtime",
35
36
  "skills",
36
37
  "README.md",
37
38
  "LICENSE"
@@ -43,9 +44,9 @@
43
44
  "access": "public"
44
45
  },
45
46
  "scripts": {
46
- "build": "tsc -p tsconfig.json",
47
+ "build": "node scripts/bundle-runtime.mjs && tsc -p tsconfig.json",
47
48
  "prepack": "node scripts/bundle-skill.mjs",
48
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
49
+ "test": "node scripts/bundle-runtime.mjs && NODE_OPTIONS=--experimental-vm-modules jest",
49
50
  "lint": "tsc -p tsconfig.json --noEmit",
50
51
  "prepublishOnly": "npm run build"
51
52
  },
@@ -53,6 +54,7 @@
53
54
  "commander": "^12.1.0"
54
55
  },
55
56
  "devDependencies": {
57
+ "@scribe-cms/proof-runtime": "*",
56
58
  "@types/jest": "^29.5.13",
57
59
  "@types/node": "^22.7.5",
58
60
  "jest": "^29.7.0",
@@ -0,0 +1,139 @@
1
+ "use strict";(()=>{function Se(r){for(let i=r;i&&i!==i.ownerDocument.documentElement;i=i.parentElement)if(i.id||i.hasAttribute("data-proof-option"))return i;return r}function qe(r){let i=globalThis.CSS;return i?.escape?i.escape(r):r.replace(/([^A-Za-z0-9_-])/g,"\\$1")}function Ke(r){if(r.id)return`#${qe(r.id)}`;let i=r.getAttribute("data-proof-option");if(i)return`[data-proof-option="${i.replace(/"/g,'\\"')}"]`;let h=[],d=r;for(;d&&h.length<4;){if(d.id){h.unshift(`#${qe(d.id)}`);break}let p=d.tagName.toLowerCase();if(p==="body"||p==="html"){h.unshift(p);break}let f=d.parentElement,T=f?Array.from(f.children).filter(L=>L.tagName===d.tagName):[];h.unshift(T.length>1?`${p}:nth-of-type(${T.indexOf(d)+1})`:p),d=f}return h.join(" > ")}function me(r){return Number.isFinite(r)?Math.min(1,Math.max(0,r)):0}function Ze(r,i,h,d){let p=Se(r),f=p.getBoundingClientRect();return{selector:Ke(p),x:me(f.width>0?(i-f.left)/f.width:0),y:me(f.height>0?(h-f.top)/f.height:0),viewportWidth:Math.round(d)}}function Qe(r,i,h){let d=yt(Se(r),i),p=d.getBoundingClientRect(),f=D=>me(p.width>0?(D-p.left)/p.width:0),T=D=>me(p.height>0?(D-p.top)/p.height:0),L=f(i.x),E=T(i.y);return{selector:Ke(d),x:L,y:E,w:Math.max(f(i.x+i.width)-L,.001),h:Math.max(T(i.y+i.height)-E,.001),viewportWidth:Math.round(h)}}function yt(r,i){let h=r.ownerDocument.documentElement;for(let d=r;d&&d!==h;d=d.parentElement){let p=d.getBoundingClientRect();if(p.left<=i.x+1&&p.top<=i.y+1&&p.right+1>=i.x+i.width&&p.bottom+1>=i.y+i.height)return Se(d)}return r.ownerDocument.body??r}function Je(r,i){let h=ge(r,i);return h&&{x:h.x,y:h.y}}function ge(r,i){let h=null;try{h=r.querySelector(i.selector)}catch{return null}if(!h)return null;let d=h.getBoundingClientRect();return d.width===0&&d.height===0?null:{x:d.left+i.x*d.width,y:d.top+i.y*d.height,width:(i.w??0)*d.width,height:(i.h??0)*d.height}}var Te="proof";function M(){return{scribe:Te,protocolVersion:8}}var q=/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/,oe=5e3;function be(r){return typeof r=="object"&&r!==null}function et(r){if(!be(r)||r.scribe!==Te)return null;let i=r.protocolVersion;return typeof i=="number"&&i!==8?i:null}function wt(r){return be(r)&&r.scribe===Te&&r.protocolVersion===8}function tt(r){if(!wt(r))return null;switch(r.type){case"init":return(r.mode==="review"||r.mode==="readonly")&&be(r.feedback)&&(r.canReply===void 0||typeof r.canReply=="boolean")?r:null;case"feedback":return be(r.feedback)?r:null;case"open-pin":return typeof r.pinId=="string"?r:null;case"open-option":return typeof r.optionId=="string"&&q.test(r.optionId)?r:null;case"comment-result":return typeof r.ok=="boolean"&&(r.error===null||typeof r.error=="string")?r:null;default:return null}}var kt={options:{},pins:[]},Et={up:0,down:0,mine:null,comments:0,reactions:[]},Rt="M1 21h4V9H1v12zM23 10a2 2 0 0 0-2-2h-6.31l.95-4.57.03-.32a1.5 1.5 0 0 0-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10a2 2 0 0 0 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z",nt="http://www.w3.org/2000/svg",Mt=`
2
+ :host { all: initial; }
3
+ .layer { position: fixed; inset: 0; pointer-events: none; z-index: 2147483646;
4
+ font: 500 13px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
5
+ --accent: #2563eb; --ink: #2c2c2c; --go: #14ae5c; --dim: rgb(255 255 255 / .55);
6
+ --up: #5bc48f; --down: #e2a05c; }
7
+ /* The badge on an Option, built like a pin: dark, so the two markers on a
8
+ page read as the same kind of thing, and so the faces on it are cut out of
9
+ the same colour. */
10
+ .toolbar { position: fixed; display: flex; gap: 2px; padding: 3px; border-radius: 999px; background: #1e1e1e; white-space: nowrap;
11
+ box-shadow: 0 2px 8px rgb(0 0 0 / .35); transform: translate(calc(-100% - 8px), 8px); pointer-events: auto; }
12
+ .toolbar button { all: unset; box-sizing: border-box; cursor: pointer; color: #fff;
13
+ display: inline-flex; align-items: center; gap: 5px; min-height: 28px; padding: 0 10px; border-radius: 999px; }
14
+ .toolbar button:hover { background: rgb(255 255 255 / .12); }
15
+ .toolbar button:focus-visible, .pin:focus-visible, .spot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
16
+ .toolbar button[aria-pressed="true"] { background: var(--accent); }
17
+ .toolbar button:disabled { cursor: default; opacity: .7; }
18
+ .toolbar.open, .toolbar:hover { box-shadow: 0 0 0 2px var(--go), 0 2px 8px rgb(0 0 0 / .35); }
19
+ .count:empty { display: none; }
20
+ .facerow { display: inline-flex; padding: 0 6px 0 2px; }
21
+ .facerow .av + .av { margin-left: -8px; box-shadow: 0 0 0 2px #1e1e1e; }
22
+ .ring { position: fixed; border: 3px solid var(--accent); border-radius: 6px; box-sizing: border-box; pointer-events: none; }
23
+ /* The marker, the way Figma draws one: a dark teardrop whose point is the spot
24
+ being talked about, holding the faces of everyone in the thread. Rounded on
25
+ three corners and square on the fourth \u2014 that corner *is* the anchor, which
26
+ is why the whole thing is translated up and right of the point. */
27
+ .pin, .spot { all: unset; box-sizing: border-box; position: fixed; z-index: 1; display: flex; padding: 3px;
28
+ border-radius: 999px 999px 999px 3px; background: #1e1e1e; cursor: pointer; pointer-events: auto;
29
+ transform: translate(0, -100%); box-shadow: 0 2px 8px rgb(0 0 0 / .35); }
30
+ .pin:hover, .pin.open { box-shadow: 0 0 0 2px var(--go), 0 2px 8px rgb(0 0 0 / .35); }
31
+ .av { flex: none; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
32
+ font-size: 10px; font-weight: 700; color: #fff; }
33
+ /* Overlapped, each cut out of the one behind it. */
34
+ .pin .av + .av, .faces .av + .av { margin-left: -8px; box-shadow: 0 0 0 2px #1e1e1e; }
35
+ /* Where a comment being written will land: the same marker, empty. */
36
+ .spot { color: #fff; background: #1e1e1e; }
37
+ .spot .av { background: rgb(255 255 255 / .18); }
38
+ /* The region a comment is about: dashed, so it reads as a selection over the
39
+ work rather than a border someone designed into it. Drawn while it's being
40
+ dragged out, and again whenever its thread is open or under the pointer. */
41
+ .area { position: fixed; border: 2px dashed var(--go); border-radius: 3px; box-sizing: border-box;
42
+ pointer-events: none; }
43
+ /* The corners the drag ran between, the way a selection shows its grip. */
44
+ .grip { position: fixed; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
45
+ background: var(--go); pointer-events: none; }
46
+ /* Over the whole page, all the time a reviewer can comment \u2014 so a click
47
+ anywhere is a comment and the cursor says so before they make one. No tint:
48
+ this is the resting state of every Proof, and a permanent wash over somebody's
49
+ design would be the first thing they asked us to take off. The bubble is a
50
+ data URI rather than a file because the runtime is one script with nothing
51
+ beside it, and crosshair is the fallback where SVG cursors aren't drawn.
52
+
53
+ Drawn as an outline, twice: a fat white stroke under a thin dark one, so the
54
+ bubble is legible over a black hero and over a white page without knowing
55
+ which it is over. Unfilled on purpose \u2014 a solid cursor hides the pixel being
56
+ pointed at, which on a Proof is the whole subject of the comment. The hotspot
57
+ is the tail's tip, so the pin lands where the point is. */
58
+ .catcher { position: fixed; inset: 0; pointer-events: auto;
59
+ cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26"><g fill="none" stroke-linejoin="round" stroke-linecap="round"><path d="M3 7.5A4 4 0 017 3.5h12a4 4 0 014 4v6a4 4 0 01-4 4h-6.5L8 22v-4.5H7a4 4 0 01-4-4z" stroke="%23fff" stroke-width="4"/><path d="M3 7.5A4 4 0 017 3.5h12a4 4 0 014 4v6a4 4 0 01-4 4h-6.5L8 22v-4.5H7a4 4 0 01-4-4z" stroke="%231f1f1f" stroke-width="1.75"/></g></svg>') 8 22, crosshair; }
60
+ /* The composer and the thread a pin opens are one surface, dark like the
61
+ marker they grow out of. */
62
+ .card, .bubble { position: fixed; width: 340px; max-width: calc(100vw - 24px); box-sizing: border-box;
63
+ border-radius: 12px; background: var(--ink); color: #fff; pointer-events: auto;
64
+ box-shadow: 0 10px 30px rgb(0 0 0 / .4); }
65
+ .card { z-index: 3; }
66
+ /* Tall threads scroll inside the card rather than off the top of the page. */
67
+ .bubble { z-index: 2; max-height: min(70vh, 460px); overflow-y: auto; overscroll-behavior: contain; }
68
+ /* Opening out of the marker it belongs to, rather than being there suddenly.
69
+ Hung off [hidden] alone, so no code has to know the animation exists:
70
+ allow-discrete holds display back until the fade has run, and the pointer
71
+ is let through to the work underneath the moment it starts closing. */
72
+ .bubble { transform-origin: bottom left;
73
+ transition: opacity 190ms ease, transform 190ms ease, display 190ms allow-discrete; }
74
+ .bubble[hidden] { opacity: 0; transform: translateY(5px) scale(.97); pointer-events: none; }
75
+ @starting-style { .bubble:not([hidden]) { opacity: 0; transform: translateY(5px) scale(.97); } }
76
+ @media (prefers-reduced-motion: reduce) { .bubble { transition: none; } }
77
+ .who { display: block; font-size: 13px; font-weight: 600; }
78
+ .ago { margin-left: 7px; font-weight: 400; color: var(--dim); }
79
+ .what { margin-top: 5px; font-size: 13px; font-weight: 400; line-height: 1.55; white-space: pre-wrap; overflow-wrap: break-word; }
80
+ /* The hover preview: who, what, and how many answered \u2014 no controls, because
81
+ nothing here is meant to be clicked except the pin it came from. */
82
+ .peek { padding: 12px 14px; cursor: pointer; }
83
+ .faces { display: flex; margin-bottom: 8px; }
84
+ .more { margin-top: 8px; font-size: 12px; font-weight: 400; color: var(--dim); }
85
+ /* Someone who reacted and left it at that. Dimmed rather than left blank: an
86
+ empty space under a name reads as a comment that failed to load. */
87
+ .none { margin-top: 5px; font-size: 13px; font-weight: 400; font-style: italic; color: var(--dim); }
88
+ /* The thumb: against a name in the list and the preview, and on its own in
89
+ the badge. Sized in ems so it tracks whatever it sits beside. */
90
+ .thumb { width: 1.15em; height: 1.15em; fill: currentColor; vertical-align: -.2em; }
91
+ .who .thumb { margin-right: 6px; }
92
+ /* Chosen, rather than offered: a thumb standing for a decision someone has
93
+ already made takes a colour, while the untouched pair on the badge stays
94
+ white so neither of them looks half-pressed. Muted on purpose \u2014 these sit
95
+ next to the work, and a saturated green would read as part of the design. */
96
+ .thumb[data-reaction="up"] { --react: var(--up); }
97
+ .thumb[data-reaction="down"] { --react: var(--down); }
98
+ .who .thumb, button[aria-pressed="true"] .thumb { fill: var(--react); }
99
+ /* An answer under someone's reaction, stepped in so the list still reads as
100
+ who-said-what rather than one flat run of names. */
101
+ .sub { margin-left: 22px; }
102
+ .reply { all: unset; cursor: pointer; margin-top: 6px; margin-left: 14px; font-size: 12px; color: var(--dim); }
103
+ .reply:hover { color: #fff; }
104
+ .reply:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
105
+ .head { display: flex; align-items: center; justify-content: space-between;
106
+ padding: 12px 14px; border-bottom: 1px solid rgb(255 255 255 / .09); font-size: 13px; font-weight: 600; }
107
+ .head button { all: unset; cursor: pointer; padding: 0 4px; font-size: 15px; line-height: 1; color: var(--dim); }
108
+ .head button:hover { color: #fff; }
109
+ .msgs { padding: 14px; display: flex; flex-direction: column; gap: 16px; }
110
+ .msg { display: flex; gap: 10px; }
111
+ .msg > div { min-width: 0; flex: 1; }
112
+ .msg .av { width: 26px; height: 26px; font-size: 11px; }
113
+ /* Taking a comment back: quiet until it's hovered, and louder once armed \u2014
114
+ the second click is the one that does it. */
115
+ .del { all: unset; cursor: pointer; margin-top: 6px; font-size: 12px; color: var(--dim); }
116
+ .del:hover { color: #fff; }
117
+ .del.armed { color: #fca5a5; }
118
+ .del:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
119
+ .del:disabled { cursor: default; opacity: .5; }
120
+ /* The box that takes a reply, and the one that takes a new comment: the same
121
+ row, so the second thing a reviewer types into behaves like the first. */
122
+ .replybox { display: flex; gap: 10px; align-items: flex-start; padding: 0 14px 14px; }
123
+ .card .replybox { padding: 12px 14px; }
124
+ .replybox .av { width: 26px; height: 26px; font-size: 11px; margin-top: 4px; }
125
+ .field { position: relative; flex: 1; min-width: 0; }
126
+ /* The reset above takes the caret with it, and over a page whose cursor is a
127
+ comment bubble, an arrow in a text box reads as "not here". */
128
+ textarea { all: unset; cursor: text; box-sizing: border-box; display: block; width: 100%; height: 36px; max-height: 160px; resize: none;
129
+ padding: 9px 40px 9px 14px; border-radius: 18px; background: transparent;
130
+ box-shadow: inset 0 0 0 1px rgb(255 255 255 / .22);
131
+ font-size: 13px; font-weight: 400; line-height: 1.4; color: #fff; }
132
+ textarea::placeholder { color: var(--dim); }
133
+ textarea:focus { box-shadow: inset 0 0 0 1px var(--go); }
134
+ .go { all: unset; position: absolute; right: 6px; top: 6px; width: 24px; height: 24px; border-radius: 50%;
135
+ cursor: pointer; display: grid; place-items: center; font-size: 13px; color: #fff; background: var(--go); }
136
+ .go:disabled { cursor: default; background: rgb(255 255 255 / .16); color: var(--dim); }
137
+ .oops { margin: 7px 0 0 2px; font-size: 12px; font-weight: 400; color: #fca5a5; }
138
+ [hidden] { display: none !important; }
139
+ `;function ot(r){let i=r.document,h=r.parent,d=h!==r,p=null,f=!1,T=null,L=null,E=kt,D="",R=[],V=[],xe=!1,g=null,re=!1,K=null,u=null,C=null,y=!1,Z=0,Le=null,ie={feedback:new Set,reviewer:new Set},se=i.createElement("div");se.setAttribute("data-scribe-proof-layer","");let it=se.attachShadow({mode:"open"}),Ae=i.createElement("style");Ae.textContent=Mt;let B=i.createElement("div");B.className="layer",B.hidden=!0;let _=i.createElement("div");_.className="catcher",_.hidden=!0;function l(e,t,n){let o=i.createElement(e);return t&&(o.className=t),n&&(o.textContent=n),o}function ye(e){let t=i.createElementNS(nt,"svg");t.setAttribute("class","thumb"),t.setAttribute("data-reaction",e),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("aria-hidden","true");let n=i.createElementNS(nt,"path");return n.setAttribute("d",Rt),e==="down"&&n.setAttribute("transform","rotate(180 12 12)"),t.append(n),t}function $(e){return ae(l("span","av"),e)}function ae(e,t){return e&&(e.textContent=t?.initials??"",e.style.background=t?.color??"rgb(255 255 255 / .18)",e)}function Pe(e){let t=l("div","replybox"),n=e.face?$(null):null,o=l("div","field"),s=l("textarea");s.rows=1,s.placeholder=e.placeholder,s.setAttribute("aria-label",e.aria);let a=l("button","go","\u2191");a.type="button",a.setAttribute("aria-label","Send");let c=l("p","oops");c.hidden=!0,o.append(s,a,c),t.append(...n?[n,o]:[o]);function m(){s.style.height="auto",s.style.height=`${s.scrollHeight}px`}let w={box:t,face:n,text:s,send:a,oops:c,setBusy(v){s.readOnly=v,a.disabled=v||s.value.trim().length===0},fail(v,F){w.setBusy(!1),c.textContent=v??F,c.hidden=!1},clear(){s.value="",s.readOnly=!1,s.style.height="",c.hidden=!0,w.setBusy(!1)}};return s.addEventListener("input",()=>{m(),w.setBusy(s.readOnly)}),s.addEventListener("keydown",v=>{v.key==="Enter"&&!v.shiftKey&&(v.preventDefault(),e.submit())}),a.addEventListener("click",e.submit),w.setBusy(!1),w}let A=l("div","card");A.hidden=!0,A.setAttribute("role","dialog");let P=Pe({placeholder:"Add a comment",aria:"Your comment",face:!1,submit:()=>ct()});A.append(P.box);let z=l("div","spot");z.hidden=!0;let Oe=$(null);z.append(Oe);let W=l("div","area");W.hidden=!0;let le=l("div","grip"),de=l("div","grip");le.hidden=!0,de.hidden=!0;let Y=l("div","area");Y.hidden=!0;let x=l("div","bubble");x.hidden=!0,x.setAttribute("role","dialog"),x.setAttribute("aria-label","Comment thread");let O=l("div","peek");O.setAttribute("role","button"),O.tabIndex=0,O.addEventListener("click",()=>He()),O.addEventListener("keydown",e=>{(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),He())});let we=l("div","faces"),Q=l("p","who"),J=l("div","what"),ee=l("p","more");O.append(we,Q,J,ee);let te=l("div");te.hidden=!0;let Ie=l("div","head"),ve=l("span","","Comment"),ce=l("button","","\u2715");ce.type="button",ce.setAttribute("aria-label","Close"),ce.addEventListener("click",()=>k({now:!0,force:!0})),Ie.append(ve,ce);let ke=l("div","msgs"),b=Pe({placeholder:"Reply",aria:"Your reply",face:!0,submit:()=>ft()});b.text.addEventListener("keydown",e=>{e.key==="Escape"&&e.stopPropagation()}),te.append(Ie,ke,b.box),x.append(O,te),B.append(_,Y,W,le,de,z,A,x),it.append(Ae,B);function S(e){d&&h.postMessage(e,"*")}function st(e){return e===se}function Ce(){for(let t of R)t.toolbar.remove(),t.ring.remove();R=[];let e=new Set;for(let t of Array.from(i.querySelectorAll("[data-proof-option]"))){let n=t.getAttribute("data-proof-option")?.trim()??"";if(!q.test(n)||e.has(n))continue;e.add(n);let o={id:n,label:t.getAttribute("data-proof-label")?.trim()||null};R.push(at(o,t))}return Me(),R.map(t=>t.info)}function at(e,t){let n=e.label??e.id,o=i.createElement("div");o.className="toolbar",o.setAttribute("role","group"),o.setAttribute("aria-label",`Feedback on ${n}`);function s(v){let F=i.createElement("button");return F.type="button",F.setAttribute("aria-label",`${v==="up"?"Like":"Dislike"} ${n}`),F.append(ye(v),l("span","count")),F.addEventListener("click",()=>{if(lt(e.id)){G(e.id,!0);return}Ue.react(e.id,v),Ee({kind:"reaction",optionId:e.id,element:t,reaction:v})}),F}let a=s("up"),c=s("down"),m=i.createElement("button");m.type="button",m.className="facerow",m.addEventListener("click",()=>G(e.id,!0)),dt(m,e.id),o.append(a,c,m);let w=i.createElement("div");return w.className="ring",w.hidden=!0,B.append(w,o),{info:e,element:t,toolbar:o,up:a,down:c,facesButton:m,ring:w}}function Be(e,t){let n=e.querySelector(".count");n&&(n.textContent=t>0?String(t):"")}function lt(e){return!!E.options[e]?.mine}function dt(e,t){let n=()=>{pe(t).reactions.length>0&&G(t,!1)};e.addEventListener("mouseenter",n),e.addEventListener("focus",n),e.addEventListener("mouseleave",()=>k()),e.addEventListener("blur",()=>k())}function pe(e){return E.options[e]??Et}function $e(e){return R.find(t=>t.info.id===e)?.info.label??e}function Ee(e){p==="review"&&(k({now:!0,force:!0}),g=e,A.setAttribute("aria-label",e.kind==="reaction"?`Say why you ${e.reaction==="up"?"liked":"disliked"} ${$e(e.optionId)}`:e.pin.w?"Comment on this area of the page":"Comment on this spot on the page"),P.text.placeholder=e.kind==="reaction"?"Say why (optional)":"Add a comment",P.clear(),ae(Oe,L),A.hidden=!1,z.hidden=e.kind!=="pin",N(),P.text.focus())}function ue(){g=null,re=!1,A.hidden=!0,z.hidden=!0,I(W,null),Re(null),P.clear(),N()}function I(e,t){e.hidden=t===null,t&&Object.assign(e.style,{left:`${t.x}px`,top:`${t.y}px`,width:`${t.width}px`,height:`${t.height}px`})}function Re(e){le.hidden=e===null,de.hidden=e===null,e&&(Object.assign(le.style,{left:`${e.x}px`,top:`${e.y}px`}),Object.assign(de.style,{left:`${e.x+e.width}px`,top:`${e.y+e.height}px`}))}function ct(){let e=P.text.value.trim();!e||!g||re||p!=="review"||(K="composer",re=!0,P.setBusy(!0),S(g.kind==="reaction"?{...M(),type:"react",optionId:g.optionId,reaction:g.reaction,body:e.slice(0,oe)}:{...M(),type:"comment",body:e.slice(0,oe),optionId:g.optionId,pin:g.kind==="pin"?g.pin:null,parentId:null}))}function ze(e){let t=new Set,n=[];for(let o of[e.person,...e.replies.map(s=>s.person)]){let s=o.initials+o.color;t.has(s)||n.length===3||(t.add(s),n.push(o))}return n}function he(e){let t=l("div","msg"),n=l("div"),o=l("p","who");e.reaction&&o.append(ye(e.reaction)),o.append(i.createTextNode(e.author),l("span","ago",e.when));let s=e.body?l("div","what"):l("div","none","No comment");if(e.body&&(s.textContent=e.body),n.append(o,s),e.mine&&f&&n.append(pt(e.id,e.withReplies??!1,e.undo??"Delete")),e.onReply&&f){let a=l("button","reply","Reply");a.type="button",a.addEventListener("click",e.onReply),n.append(a)}return t.append($(e.person),n),t}let j=null;function pt(e,t,n){let o=l("button","del",n);o.type="button";let s=t?`${n} thread?`:`${n}?`,a=0;function c(){j===e&&(j=null),o.textContent=n,o.classList.remove("armed")}return j===e&&(o.textContent=s,o.classList.add("armed"),a=r.setTimeout(c,4e3)),o.addEventListener("click",()=>{if(j!==e){j=e,o.textContent=s,o.classList.add("armed"),a=r.setTimeout(c,4e3);return}r.clearTimeout(a),j=null,o.disabled=!0,S({...M(),type:"delete-comment",commentId:e})}),o}function ut(e){let t=null;try{t=i.querySelector(e.selector)}catch{return}t?.scrollIntoView({behavior:"smooth",block:"center"})}function He(){if(!u||y)return;if(u.kind==="option"){G(u.id,!0);return}let e=E.pins.find(t=>t.id===u.id);e&&(X(e,!0),S({...M(),type:"focus-pin",pinId:e.id}))}function G(e,t){if(p===null)return;r.clearTimeout(Z);let n=pe(e);if(n.reactions.length===0){if(!t)return;k({now:!0,force:!0});return}let o=u?.kind==="option"&&u.id===e;u={kind:"option",id:e},t&&(y=!0);let s=y;if(s)ve.textContent=$e(e),ke.replaceChildren(...n.reactions.flatMap(a=>[he({...a,author:a.mine?"You":a.author,withReplies:a.replies.length>0,undo:"Clear",onReply:()=>ht(a.id,a.mine?"You":a.author)}),...a.replies.map(c=>{let m=he({...c,author:c.mine?"You":c.author});return m.classList.add("sub"),m})])),o||(C=null,b.clear()),b.box.hidden=C===null||!f,ae(b.face,L);else{let c=n.reactions.find(w=>w.mine)??n.reactions[n.reactions.length-1];we.replaceChildren(...Ne(n).map($)),Q.replaceChildren(ye(c.reaction),i.createTextNode(c.mine?"You":c.author)),Q.append(l("span","ago",c.when)),J.textContent=c.body||"No comment",J.classList.toggle("none",!c.body);let m=n.reactions.length-1;ee.textContent=m===1?"1 other":`${m} others`,ee.hidden=m===0}O.hidden=s,te.hidden=!s;for(let a of V)a.button.classList.remove("open");for(let a of R)a.toolbar.classList.toggle("open",s&&a.info.id===e);x.hidden=!1,x.scrollTop=0,N()}function ht(e,t){C=e,b.text.placeholder=`Reply to ${t}`,b.box.hidden=!f,b.text.focus()}function Ne(e){return e.reactions.slice(0,3).map(t=>t.person)}function X(e,t){r.clearTimeout(Z);let n=u?.kind==="pin"&&u.id===e.id,o=y;u={kind:"pin",id:e.id,anchor:e.anchor},t&&(y=!0);let s=y;if(s)ke.replaceChildren(he({...e,author:e.mine?"You":e.author,withReplies:e.replies.length>0}),...e.replies.map(a=>he({...a,author:a.mine?"You":a.author}))),C=e.id,b.text.placeholder="Reply",b.box.hidden=!f,ae(b.face,L),n||b.clear();else{we.replaceChildren(...ze(e).map($)),Q.textContent=e.mine?"You":e.author,Q.append(l("span","ago",e.when)),J.textContent=e.body;let a=e.replies.length;ee.textContent=a===1?"1 reply":`${a} replies`,ee.hidden=a===0}ve.textContent="Comment",O.hidden=s,J.classList.remove("none"),te.hidden=!s;for(let a of V)a.button.classList.toggle("open",s&&a.id===e.id);for(let a of R)a.toolbar.classList.remove("open");x.hidden=!1,x.scrollTop=0,N(),s&&f&&(!n||!o)&&b.text.focus()}function ft(){let e=b.text.value.trim();!e||!C||!f||K||(K="reply",b.oops.hidden=!0,b.setBusy(!0),S({...M(),type:"comment",body:e.slice(0,oe),optionId:null,pin:null,parentId:C}))}function k(e={}){if(y&&!e.force||!e.force&&b.text.value.trim())return;y=!1,r.clearTimeout(Z);let t=()=>{x.hidden=!0,u=null,C=null,I(Y,null),b.box.hidden=!0,b.clear();for(let n of V)n.button.classList.remove("open");for(let n of R)n.toolbar.classList.remove("open");H(null)};e.now?t():Z=r.setTimeout(t,180)}x.addEventListener("mouseenter",()=>{r.clearTimeout(Z),H(u?.kind==="pin"?u.id:null)}),x.addEventListener("mouseleave",()=>{k(),H(null)});function H(e){Le!==e&&(Le=e,S({...M(),type:"hover-pin",pinId:e}))}function Me(){let e=p!=="review";for(let t of R){let n=pe(t.info.id),o=n.mine!==null;Be(t.up,n.up),Be(t.down,n.down),t.up.hidden=o&&n.mine!=="up",t.down.hidden=o&&n.mine!=="down",t.up.setAttribute("aria-pressed",String(n.mine==="up")),t.down.setAttribute("aria-pressed",String(n.mine==="down")),t.up.disabled=e&&!o,t.down.disabled=e&&!o,t.facesButton.replaceChildren(...Ne(n).map($)),t.facesButton.hidden=n.reactions.length===0,t.facesButton.setAttribute("aria-label",`${n.reactions.length} ${n.reactions.length===1?"reaction":"reactions"} on ${t.info.label??t.info.id}`)}for(let t of V)t.button.remove();if(V=E.pins.map(t=>{let n=l("button","pin");return n.type="button",n.append(...ze(t).map($)),n.setAttribute("aria-label",`Comment ${t.number} from ${t.mine?"you":t.author}, ${t.replies.length} replies`),n.addEventListener("mouseenter",()=>{X(t,!1),H(t.id)}),n.addEventListener("mouseleave",()=>{k(),H(null)}),n.addEventListener("focus",()=>{X(t,!1),H(t.id)}),n.addEventListener("blur",()=>{k(),H(null)}),n.addEventListener("click",()=>{y&&u?.id===t.id?k({now:!0,force:!0}):X(t,!0),S({...M(),type:"focus-pin",pinId:t.id})}),B.append(n),{id:t.id,button:n,anchor:t.anchor}}),u?.kind==="option")pe(u.id).reactions.length>0?G(u.id,y):k({now:!0,force:!0});else if(u){let t=E.pins.find(n=>n.id===u.id);t?X(t,y):k({now:!0,force:!0})}N()}function N(){if(xe)return;xe=!0,(r.requestAnimationFrame?.bind(r)??(t=>r.setTimeout(t,16)))(()=>{xe=!1,mt()})}function mt(){for(let n of R){let o=n.element.getBoundingClientRect(),s=o.width>0||o.height>0;n.toolbar.hidden=!s,n.toolbar.style.left=`${o.right}px`,n.toolbar.style.top=`${o.top}px`,n.ring.hidden=!s||g?.kind!=="reaction"||g.optionId!==n.info.id,Object.assign(n.ring.style,{left:`${o.left}px`,top:`${o.top}px`,width:`${o.width}px`,height:`${o.height}px`})}let e=[];for(let n of V){let o=Je(i,n.anchor);if(n.button.hidden=!o,!o){e.push(n.id);continue}n.button.style.left=`${o.x}px`,n.button.style.top=`${o.y}px`}if(g)if(g.kind==="pin"){let n=ge(i,g.pin);n&&(z.style.left=`${n.x}px`,z.style.top=`${n.y}px`,I(W,g.pin.w?n:null),De(A,{x:n.x+n.width,y:n.y},n.x))}else{let n=g.element.getBoundingClientRect();(n.width>0||n.height>0)&&De(A,{x:n.right,y:n.top},n.left)}if(u?.kind==="option"){let n=R.find(c=>c.info.id===u.id),o=n?.element.getBoundingClientRect();x.hidden=!o||o.width===0&&o.height===0,I(Y,null);let s=n?.toolbar.getBoundingClientRect(),a=s&&(s.width>0||s.height>0);if(o&&!x.hidden){let c=a?{x:s.left,y:s.bottom}:{x:o.right,y:o.top};Fe(c,(a?s.bottom:o.top+34)+8)}}else if(u){let n=ge(i,u.anchor);x.hidden=!n,I(Y,n&&u.anchor.w?n:null),n&&Fe(n)}else I(Y,null);let t=e.join(",");t!==D&&(D=t,S({...M(),type:"unplaced-pins",pinIds:e}))}function Fe(e,t=e.y+36){let o=x.offsetWidth||300,s=x.offsetHeight||150,a=r.innerWidth||o+16,c=r.innerHeight||s+16,m=e.x+(y?40:0);m+o+8>a&&(m=e.x-o-(y?8:0)),x.style.left=`${fe(m,8,a-o-8)}px`;let w=e.y-(y?Math.min(s,70):s);x.style.top=`${fe(w<8?t:w,8,c-s-8)}px`}function De(e,t,n=t.x){let a=e.offsetWidth||272,c=e.offsetHeight||120,m=r.innerWidth||a+16,w=r.innerHeight||c+16,v=t.x+18;v+a+8>m&&(v=n-18-a),e.style.left=`${fe(v,8,m-a-8)}px`,e.style.top=`${fe(t.y-12,8,w-c-8)}px`}function fe(e,t,n){return Math.max(t,Math.min(e,Math.max(t,n)))}function gt(){_.hidden=p!=="review"}function Ve(e,t){return(i.elementsFromPoint?i.elementsFromPoint(e,t):[i.elementFromPoint(e,t)]).find(o=>!!o&&!st(o)&&o!==i.documentElement)??i.body}let bt=6,ne=null,U=!1;function _e(e,t,n){return{x:Math.min(e.x,t),y:Math.min(e.y,n),width:Math.abs(t-e.x),height:Math.abs(n-e.y)}}_.addEventListener("mousedown",e=>{g||y||(ne={x:e.clientX,y:e.clientY},U=!1,e.preventDefault())}),r.addEventListener("mousemove",e=>{if(!ne)return;let t=_e(ne,e.clientX,e.clientY);!U&&Math.max(t.width,t.height)<bt||(U=!0,I(W,t),Re(t))}),r.addEventListener("mouseup",e=>{let t=ne;if(ne=null,!t||!U)return;let n=_e(t,e.clientX,e.clientY);Re(null);let o=Ve(t.x,t.y);if(!o){I(W,null);return}let s=Qe(o,n,r.innerWidth);Ee({kind:"pin",pin:s,optionId:We(o)})}),_.addEventListener("click",e=>{if(U){U=!1;return}if(g){ue();return}if(y){k({now:!0,force:!0});return}let t=Ve(e.clientX,e.clientY);if(!t)return;let n=Ze(t,e.clientX,e.clientY,r.innerWidth);Ee({kind:"pin",pin:n,optionId:We(t)})});function We(e){let t=e.closest("[data-proof-option]")?.getAttribute("data-proof-option")??null;return t&&q.test(t)?t:null}r.addEventListener("keydown",e=>{e.key==="Escape"&&(g?ue():y&&k({now:!0,force:!0}))}),r.addEventListener("message",e=>{if(e.source!==h)return;let t=tt(e.data);if(!t){xt(et(e.data));return}if(t.type==="init"){p=t.mode,f=t.canReply??t.mode==="review",T=t.reviewer,L=t.me??null,E=t.feedback,B.hidden=!1,gt(),p!=="review"&&ue(),Me();for(let n of ie.reviewer)n(T);for(let n of ie.feedback)n(E)}else if(t.type==="feedback"){E=t.feedback,Me();for(let n of ie.feedback)n(E)}else if(t.type==="open-pin"){let n=E.pins.find(o=>o.id===t.pinId);if(!n)return;ut(n.anchor),k({now:!0,force:!0}),X(n,!0)}else if(t.type==="open-option"){let n=R.find(o=>o.info.id===t.optionId);if(!n)return;n.element.scrollIntoView({behavior:"smooth",block:"center"}),k({now:!0,force:!0}),G(t.optionId,!0)}else if(t.type==="comment-result"){let n=K;if(K=null,n==="reply"){t.ok?k({now:!0,force:!0}):b.fail(t.error,"That didn\u2019t send.");return}if(!g)return;t.ok?ue():(re=!1,P.fail(t.error,"That didn\u2019t save."))}});for(let e of["scroll","resize","load"])r.addEventListener(e,N,{capture:!0,passive:!0});function Ye(){i.documentElement.append(se);let e=Ce(),t=r.ResizeObserver;if(t){let s=new t(N);s.observe(i.documentElement);for(let a of R)s.observe(a.element)}let o=r.location.pathname.split("/").slice(3).join("/")||"index.html";S({...M(),type:"ready",options:e,path:o})}let je=!1;function xt(e){e===null||je||(je=!0,console.warn(`ScribeProof: this page's script speaks protocol ${8} and the page around it speaks ${e}. Reload to pick up the current script.`))}let Ge=!1;function Xe(){return d&&p==="review"?!0:(Ge||(Ge=!0,console.warn("ScribeProof: feedback is only recorded when this page is opened from its review link.")),!1)}let Ue={get reviewer(){return T},get mode(){return p},react(e,t){!q.test(e)||t!=="up"&&t!=="down"||!Xe()||S({...M(),type:"react",optionId:e,reaction:t,body:null})},comment(e,t){let n=t?.option??null;typeof e!="string"||!e.trim()||n!==null&&!q.test(n)||!Xe()||S({...M(),type:"comment",body:e.slice(0,oe),optionId:n,pin:null,parentId:null})},on(e,t){let n=ie[e];return n.add(t),()=>n.delete(t)},refresh(){Ce()}};return i.readyState==="loading"?i.addEventListener("DOMContentLoaded",Ye,{once:!0}):Ye(),Ue}var rt=window;rt.ScribeProof||(rt.ScribeProof=ot(window));})();