create-pmos 0.530.0 → 0.531.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.530.0",
3
+ "version": "0.531.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.530.0",
9
+ "version": "0.531.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@anthropic-ai/sdk": "^1.3.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.530.0",
3
+ "version": "0.531.0",
4
4
  "private": true,
5
5
  "description": "PMOS Terminal Workspace — local companion hosting real PTYs beside the library and gates (D62)",
6
6
  "license": "MIT",
@@ -261,6 +261,7 @@
261
261
  .vz-words .vz-eye { align-self: flex-start; padding: 3px 8px; border-radius: 4px; background: color-mix(in oklab, var(--cz-c-ffffff) 18%, transparent); font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
262
262
  .vz-fr { position: absolute; inset: 0; overflow: hidden; }
263
263
  .vz-fr iframe { width: 1280px; height: 720px; border: 0; transform-origin: 0 0; transform: scale(var(--rp-scale, .4)); pointer-events: none; background: var(--cz-c-ffffff); }
264
+ .vz-fr.vz-live iframe { pointer-events: auto; } /* a slide with CSS-only controls (report library timeline, actions): premium-report-read.js slideCard */
264
265
  .vz-snav { display: flex; align-items: center; gap: 8px; }
265
266
  .vz-snav > b { font-size: var(--fs-label); font-weight: var(--fw-strong); line-height: var(--lh-label); }
266
267
  .vz-snav > span:not(.vz-sp) { font-size: var(--fs-meta); color: var(--cz-ink3); line-height: var(--lh-meta); }
@@ -163,11 +163,32 @@ export function splitRender(html) {
163
163
  return { style, slides, body: d.body.innerHTML };
164
164
  }
165
165
  const href = (f) => new URL('./' + f, import.meta.url).href;
166
+ /* The workspace face inside the frame (batch 27 item 14, report library B2). The frame's origin is opaque, so a font file it asks for is refused
167
+ * by CORS; the page reads the face once (same origin) and hands it to the frame as a data: font. Until it is read the slide shows the fallback face,
168
+ * then it is drawn again. Only a render that names the face takes it. */
169
+ const FACE = { css: '', state: '' };
170
+ function faceCss(style) {
171
+ if (!/Plus Jakarta Sans/.test(style)) return '';
172
+ if (FACE.state === '' && typeof fetch === 'function' && typeof FileReader === 'function') {
173
+ FACE.state = 'reading';
174
+ fetch('/vendor/plus-jakarta-sans-var.woff2').then((r) => (r.ok ? r.blob() : null)).then((b) => {
175
+ if (!b) { FACE.state = 'none'; return; }
176
+ const fr = new FileReader();
177
+ fr.onload = () => { FACE.css = '@font-face{font-family:"Plus Jakarta Sans";font-style:normal;font-weight:200 800;font-display:block;src:url(' + fr.result + ') format("woff2")}'; FACE.state = 'ready'; if (R) draw(); };
178
+ fr.onerror = () => { FACE.state = 'none'; };
179
+ fr.readAsDataURL(b);
180
+ }).catch(() => { FACE.state = 'none'; });
181
+ }
182
+ return FACE.css;
183
+ }
166
184
  function frameDoc(style, inner, cls) {
167
185
  return '<!doctype html><html lang="en"><head><meta charset="utf-8"><link rel="stylesheet" href="' + esc(href('tokens.css')) + '"><link rel="stylesheet" href="' + esc(href('premium-report-frame.css')) + '">'
168
- + '<style>' + String(style || '').replace(/<\/style/gi, '<\\/style') + '</style></head><body class="pmos-frame ' + cls + '">' + String(inner || '') + '</body></html>';
186
+ + '<style>' + faceCss(String(style || '')) + String(style || '').replace(/<\/style/gi, '<\\/style') + '</style></head><body class="pmos-frame ' + cls + '">' + String(inner || '') + '</body></html>';
169
187
  }
170
- const frame = (style, inner, cls, title) => `<iframe sandbox="" tabindex="-1" title="${esc(title)}" srcdoc="${esc(frameDoc(style, inner, cls))}"></iframe>`;
188
+ /* A slide with CSS-only controls (data-pmos-live: the library's timeline span and filter, the ticked actions) takes the pointer and the keyboard in
189
+ * the big view and in Present; a thumbnail never does. Nothing in the frame runs: its sandbox stays empty. */
190
+ const frame = (style, inner, cls, title, live) => `<iframe sandbox=""${live ? '' : ' tabindex="-1"'} title="${esc(title)}" srcdoc="${esc(frameDoc(style, inner, cls))}"></iframe>`;
191
+ const LIVE_RE = /<section\b[^>]*\bdata-pmos-live=/;
171
192
 
172
193
  /* ── what is shown ── */
173
194
  function slides() {
@@ -210,7 +231,7 @@ export function headFigure(w) {
210
231
  }
211
232
  /** One slide: a designed frame, the title slide or a section's words. */
212
233
  export function slideCard(s, mini) {
213
- if (s.k === 'frame') return `<span class="vz-fr">${frame(s.css, s.html, 'pmos-one', s.h)}</span>`;
234
+ if (s.k === 'frame') { const live = !mini && LIVE_RE.test(s.html); return `<span class="vz-fr${live ? ' vz-live' : ''}">${frame(s.css, s.html, 'pmos-one', s.h, live)}</span>`; }
214
235
  if (s.k === 'title') return `<span class="vz-words vz-title"><span class="vz-eye">${esc(s.eye || (R && R.audience) || 'Report')}</span><h4 data-ed="title">${esc(s.title || s.h)}${s.acc ? ` <em class="vz-acc">${esc(s.acc)}</em>` : ''}</h4>${mini ? '' : `${s.sub ? `<b class="vz-tsub">${esc(s.sub)}</b>` : ''}<p>${esc(s.t || '')}</p>`}</span>${!mini && s.fig ? `<span class="vz-tfig"><i class="vz-tdot" aria-hidden="true"></i><span><b>${esc(s.fig.v)}</b>${s.fig.cap ? `<small>${esc(s.fig.cap)}</small>` : ''}</span></span>` : ''}`;
215
236
  return `<span class="vz-words"><h4>${esc(s.h)}</h4>${mini ? '' : s.html}</span>`;
216
237
  }
@@ -36,9 +36,10 @@ Procedure:
36
36
  - Shapes other reports took, as examples and never a menu: a decision (the lean · the options and what each costs · what could reverse it · your call); a watch (today against yesterday and the week · the drop that moved most · why); a stakeholder update (are the dates on track · what each team needs and by when · open decisions · what could stop it); a review (the summary for decision · the outcomes by segment · the challenges and answers · method); did-it-work (what was promised · what we got · the verdict).
37
37
  6. Write `<slot>.report.json` (in a scratch file, then `pmos report write <id> --from <file>`):
38
38
  `{"title":"…{{r:…}}…","answer":{"text":"…","supports":["Label: …{{r:…}}…"]},"sections":[{"id":"…","title":"…","blocks":[{"kind":"p","text":"…"},{"kind":"list","items":["…"]},{"kind":"table","columns":["…"],"rows":[["…"]]},{"kind":"bars","title":"…","rows":[["label","{{r:id}}"]]},{"kind":"options","options":[{"name":"…","text":"…"}]},{"kind":"quote","text":"…"}]}],"ask":{"text":"…","who":"…","by":"YYYY-MM-DD","options":["…"]},"beyond":{"why":"…","so_what":"…","now_what":"…","since":"…","would_change":"…","unknown":["…"],"else":["…"],"next_question":"…"},"questions":[{"question":"<a question of the brief>","answered_in":"<section id or answer>","gap":"<why it cannot be answered>"}],"outline_note":"…"}`.
39
+ - A section can take a slide layout from the report library instead of blocks: `{"title":"…","layout":"<name>","data":{…},"insight":{"head":"…","text":"…","points":[{"tone":"ok|watch|late|bad|info|none","text":"…"}],"note":"…"},"eyebrow":"…","sub":"…"}`. The names: overview, tiles, ledger, timeline, compare, lists, risks, ranked, decisions, quotes, actions, agenda, heatmap, network, schedule, donut, bubbles, people, statement, sources, minutes, focus, next. Run `pmos report library` to see each one with its data; `pmos report write` names a field that does not fit. Pick the layout that fits the finding, never to fill a slide. Every text in `data` and `insight` is checked like any other: a figure is a reading token. A bar's `share`, a `target` mark and a bubble's `x`, `y` and `size` are numbers from 0 to 1: take them from the readings. The insight is optional; leave it out when the slide says it already.
39
40
  - `ask` is null when the readers have nothing to decide. When it is a call with no better option on the evidence, give the options and say "your call".
40
41
  - BEYOND THE ASK. Answer the readers' next three questions before they ask: why (the cause, from the evidence), so what (the effect on the target and its date), now what (the recommendation, who, by), since the last issue (what moved, and each carried ask), what would change it (the one or two readings that would flip the recommendation), what we don't know (the gaps, counted, never padded), what else is here (at most two findings from a named source the readers did not ask about, when their question depends on them) and the next question (the split they will ask for next). Each part cites a reading. Leave a part out when no reading backs it, and leave out a part the brief's rules turn off.
41
42
  - `questions`: map each question of the brief after the first to the section that answers it, or give the gap.
42
- 7. Read what `pmos report write` prints. A refusal names the check: fix the report and run it again. When it passes, it writes `<slot>.md` and `<slot>.checks.json`; the deck, the PDF and the PowerPoint are drawn from the same model, in the report's saved look.
43
+ 7. Read what `pmos report write` prints. A refusal names the check: fix the report and run it again. When it passes, it writes `<slot>.md` and `<slot>.checks.json`; the deck, the PDF and the PowerPoint are drawn from the same model, in the report library's frame.
43
44
  8. Learn. When the PM's change in the chat is about the words (shorter, plainer, another tone) and it would apply to every issue, keep it: `pmos report rule <id> add wording "<the rule, one line>"`. When the PM removes a part beyond the ask, `pmos report rule <id> add off <part>`. Then change report.json and run `pmos report write` again. A change to a number is a change to a reading: read the source again and file it.
44
45
  9. Finish by saying in one line where the draft is and how many readings, findings and gaps it has. Do not commit; the PM's Sync carries the files.
@@ -0,0 +1,9 @@
1
+ {
2
+ "_comment": "Batch 27 item 14, the report library: the B2 frame and its 23 layouts, the templates, the engine deck in that frame, the document and PowerPoint lines, and pmos report library (lib/report-slides.js, lib/report-library.js). Pure.",
3
+ "modules": [
4
+ "report-slides.test.js"
5
+ ],
6
+ "seconds": {
7
+ "report-slides.test.js": 2
8
+ }
9
+ }