create-pmos 0.240.0 → 0.241.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 +1 -1
- package/payload/KIT-VERSION +1 -1
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/state/discoveries.md +1 -1
- package/workspace/c3-report-structure-real-test.js +211 -0
- package/workspace/c3-report-structure-test.js +382 -0
- package/workspace/guide/index.md +2 -0
- package/workspace/guide/report-design.md +4 -0
- package/workspace/guide/report-structure.md +91 -0
- package/workspace/guide/reports-dashboards.md +1 -1
- package/workspace/guide/reports-set-up.md +2 -0
- package/workspace/lib/charts-store.js +124 -0
- package/workspace/lib/headless.js +17 -3
- package/workspace/lib/needs-providers.js +1 -0
- package/workspace/lib/report-structure-needs.js +64 -0
- package/workspace/lib/report-structure.js +515 -0
- package/workspace/lib/route-modules.js +1 -0
- package/workspace/lib/routes-report-setups.js +11 -6
- package/workspace/lib/routes-report-structure.js +619 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-demo-rd.js +4 -0
- package/workspace/public/pm/c3-design-studio.js +7 -3
- package/workspace/public/pm/c3-report-setup.js +3 -0
- package/workspace/public/pm/c3-report-structure.css +40 -0
- package/workspace/public/pm/c3-report-structure.js +455 -0
- package/workspace/public/pm/c3-reports.css +2 -0
- package/workspace/public/pm/c3-reports.js +22 -3
- package/workspace/public/pm/c3-shell.js +2 -0
- package/workspace/server.js +38 -9
- package/workspace/skills/report-source-check.skill +45 -0
- package/workspace/skills/report-structure-dry.skill +51 -0
- package/workspace/skills/report-structure.skill +61 -0
- package/workspace/skills/report-template.skill +10 -0
- package/workspace/test-lists/report-structure-backend.json +5 -0
- package/workspace/test-lists/report-structure-ui.json +11 -0
|
@@ -407,6 +407,10 @@ function press(k, b) {
|
|
|
407
407
|
/** The routes. Returns a Response, or undefined for a route this file does not answer. */
|
|
408
408
|
export function rdRoute(method, u, body) {
|
|
409
409
|
const p = u.pathname; const qp = u.searchParams;
|
|
410
|
+
/* the Structure step (initiative report-structure): demo mode holds no structure and no data chart, and saves nothing */
|
|
411
|
+
if (p === '/api/report-structure' && method === 'GET') { const id = qp.get('id'); const s = ctx.setups().find((x) => x.id === id); return s ? json({ ok: true, setup: { id, name: s.name, cadence: s.schedule && s.schedule.cadence }, structure: { running: false, job: null, current: null, saved: null, versions: [], log: [], plan: null, dry: null, checks: {}, errors: [] } }) : json({ ok: false, error: 'no such report' }, 404); }
|
|
412
|
+
if (p === '/api/charts' && method === 'GET') return json({ ok: true, charts: [] });
|
|
413
|
+
if (p.startsWith('/api/report-structure') && method === 'POST') return json({ ok: false, error: 'Demo data: nothing is saved' });
|
|
410
414
|
if (!p.startsWith('/api/report-design') && !p.startsWith('/api/report-notes')) return undefined;
|
|
411
415
|
if (method === 'GET') {
|
|
412
416
|
if (p === '/api/report-design') { const id = qp.get('id'); if (!ctx.setups().some((x) => x.id === id)) return json({ ok: false, error: 'no such report' }, 404); return json(designView(id)); }
|
|
@@ -16,6 +16,7 @@ import { toast } from './c3-toast.js';
|
|
|
16
16
|
import { RS, scheduleLabel } from './c3-report-store.js';
|
|
17
17
|
import { formatOf } from './c3-doc-formats.js';
|
|
18
18
|
import { RD, failed, splitRender, slideCard, frame, wireFrame, diffOutlines, ensureDeckCss, slotWord } from './c3-report-deck.js';
|
|
19
|
+
import { openStructure, structureSection } from './c3-report-structure.js';
|
|
19
20
|
|
|
20
21
|
const MAX = 20 * 1024 * 1024;
|
|
21
22
|
const KIND_OF = (name) => { const e = String(name || '').toLowerCase().split('.').pop(); return e === 'pdf' ? 'pdf' : e === 'pptx' ? 'pptx' : e === 'docx' ? 'docx' : /^(png|jpe?g)$/.test(e) ? 'image' : ''; };
|
|
@@ -304,7 +305,9 @@ export function openStudio({ ws, id, name, view, onClose } = {}) {
|
|
|
304
305
|
const sb = body.closest('.sb'); const y = sb ? sb.scrollTop : 0; const log = body.querySelector('.rd-dks-log'); const ly = log ? log.scrollTop : null;
|
|
305
306
|
const focus = document.activeElement && body.contains(document.activeElement) && document.activeElement.matches('[data-rd-in],[data-rd-link]') ? document.activeElement.getAttribute('data-rd-in') != null ? '[data-rd-in]' : '[data-rd-link]' : null;
|
|
306
307
|
S.dks = S.dks || el('div', { class: 'rd-dks' }); S.out = S.out || el('div', { class: 'rd-dks-out', 'data-rd-preview': '' });
|
|
307
|
-
keep(body, el('div', { class: 'rd-dk-bar' }, el('div', { class: 'chips2 rd-wrap' }, el('div', { class: 'seg', role: 'group', 'aria-label': '
|
|
308
|
+
keep(body, el('div', { class: 'rd-dk-bar' }, el('div', { class: 'chips2 rd-wrap' }, el('div', { class: 'seg', role: 'group', 'aria-label': 'Studio step', 'data-rd-steps': '' },
|
|
309
|
+
btn({ 'data-rd-step': 'structure', 'aria-pressed': 'false', onclick: () => openStructure({ ws, id, name: nm }) }, icon('todo', 'sm'), '1 Structure'), btn({ 'data-rd-step': 'design', 'aria-pressed': 'true' }, icon('img', 'sm'), '2 Design')),
|
|
310
|
+
el('div', { class: 'seg', role: 'group', 'aria-label': 'Report type' },
|
|
308
311
|
btn({ 'data-rd-fmt': 'deck', 'aria-pressed': String(K.fmt === 'deck'), onclick: () => setFmt('deck') }, icon('img', 'sm'), 'Deck'), btn({ 'data-rd-fmt': 'doc', 'aria-pressed': String(K.fmt === 'doc'), onclick: () => setFmt('doc') }, icon('doc', 'sm'), 'Document')),
|
|
309
312
|
el('b', null, nm), D.saved ? el('span', { class: 'chip2 ds-good', 'data-rd-saved': String(D.saved.version) }, icon('check', 'sm'), 'Saved design: D' + D.saved.version) : el('span', { class: 'chip2', 'data-rd-saved': '' }, 'Not saved yet')),
|
|
310
313
|
el('div', { class: 'chips2' }, pbtn('primary', 'This is it', 'check', { 'data-rd-act': 'accept', disabled: !D.versions.length, onclick: () => accept() }),
|
|
@@ -332,8 +335,9 @@ export function openBrief({ ws, id, name } = {}) {
|
|
|
332
335
|
const nm = setup.name || name || id; const out = formatOf(setup.output);
|
|
333
336
|
const lh = el('div', { class: 'lh' }, el('span', { class: 'ki' }, icon('report')), el('div', { class: 'rs-min0' }, el('b', null, nm),
|
|
334
337
|
el('div', { class: 'dim' }, (setup.label || scheduleLabel(setup.schedule)) + '. Output: ' + (setup.output === 'google-slides' ? 'a slide deck in PMOS. A Google Slides copy is optional.' : out.l + '.'))));
|
|
338
|
+
const SS = await structureSection({ ws, id, name: nm }); // the saved structure (step 1), above the design
|
|
335
339
|
if (!D.saved) {
|
|
336
|
-
put(body, lh, sect({ ic: 'spark', title: 'Design', attrs: { 'data-rd-design': '' } }, el('div', { class: 'fold', 'data-rd-nosaved': '' }, icon('info', 'sm'), ' No saved design yet. Describe the report and refine it in the Design studio, then press This is it.'),
|
|
340
|
+
put(body, lh, SS, sect({ ic: 'spark', title: 'Design', attrs: { 'data-rd-design': '' } }, el('div', { class: 'fold', 'data-rd-nosaved': '' }, icon('info', 'sm'), ' No saved design yet. Describe the report and refine it in the Design studio, then press This is it.'),
|
|
337
341
|
el('div', { class: 'ds-acts' }, pbtn('primary', 'Design how it looks', 'spark', { 'data-rd-act': 'studio', onclick: () => openStudio({ ws, id, name: nm }) }))));
|
|
338
342
|
return;
|
|
339
343
|
}
|
|
@@ -345,7 +349,7 @@ export function openBrief({ ws, id, name } = {}) {
|
|
|
345
349
|
const rules = D.rules || {};
|
|
346
350
|
const cycHost = el('ul', { class: 'chgl', 'data-rd-briefcycles': '' });
|
|
347
351
|
const docs = (RS.docs || []).filter((d) => d.setup === id).sort((a, b) => String(b.slot).localeCompare(String(a.slot)));
|
|
348
|
-
put(body, lh,
|
|
352
|
+
put(body, lh, SS,
|
|
349
353
|
sect({ ic: 'spark', title: 'Design', right: el('span', { class: 'tag acc' }, 'Design D' + n), attrs: { 'data-rd-design': '' } },
|
|
350
354
|
el('div', { class: 'dim rd-small' }, 'Written by PMOS from your studio session. It is not a template: PMOS reads it each cycle and drafts to match it. Saved ' + dayAt(D.saved.at) + ', version D' + n + '.'),
|
|
351
355
|
el('h3', { class: 'ds-h' }, 'Your description'), el('blockquote', { class: 'rd-dks-q', 'data-rd-desc': '' }, D.description || 'No description.'),
|
|
@@ -16,6 +16,7 @@ import { toast } from './c3-toast.js';
|
|
|
16
16
|
import { FORMATS, OUTPUTS, formatOf, ensureReportCss } from './c3-doc-formats.js';
|
|
17
17
|
import { createDeck } from './c3-report-deck.js';
|
|
18
18
|
import { openStudio, openBrief } from './c3-design-studio.js';
|
|
19
|
+
import { openStructure } from './c3-report-structure.js';
|
|
19
20
|
import { RS, onReports, loadReports, askPmos, changeIt, cancelAsk, setupFrom, draftNow, dismissLater, pauseResume, fromDashboard, goTo, evidenceKind, normProposal, scheduleLabel, nextDraftDate, dayText, docsOf, outChip, copyChip, srcChip } from './c3-report-store.js';
|
|
20
21
|
|
|
21
22
|
const MON = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
@@ -118,6 +119,7 @@ function askCard(a, redo) {
|
|
|
118
119
|
return sect({ ic: 'spark', title: 'PMOS answer', attrs, right: confTag('') }, el('div', { class: 'rs-stack' }, head,
|
|
119
120
|
lbl('WHAT PMOS FOUND'), ...foundList(P), lbl('PROPOSED REPORT'), proposed(key, P, redo), lbl('LEARNED FROM'), ...[].concat(learnedBlock(P)), lbl('FIXES IT WILL APPLY'), fixesList(P), ...(cb ? [].concat(cb) : []),
|
|
120
121
|
el('div', { class: 'chips2' }, pbtn('primary', 'Set up', 'check', { 'data-rs-act': 'setup', onclick: () => setupFrom({ ask: a.id, proposal: P }) }),
|
|
122
|
+
pbtn('outline', 'Shape it with PMOS', 'todo', { 'data-rs-act': 'shape', title: 'Set the report up, then decide with PMOS what it answers, where each number comes from and how it is worked out', onclick: async () => { const r = await setupFrom({ ask: a.id, proposal: P }); if (r && r.ok && r.setup) openStructure({ ws: RS.ws, id: r.setup.id, name: r.setup.name }); } }),
|
|
121
123
|
pbtn('outline', 'Change', 'edit', { 'data-rs-act': 'change', onclick: () => { RS.chg[key] = { ...st, open: true }; redo(); } }),
|
|
122
124
|
pbtn('ghost', 'Cancel', 'x', { 'data-rs-act': 'cancel-ask', onclick: async () => { const r = await cancelAsk(a.id); if (r && r.ok) toast('Cancelled. Nothing was set up.'); } })),
|
|
123
125
|
help('PMOS reads your past copies to learn the sections. It drafts only; you issue.')));
|
|
@@ -232,6 +234,7 @@ export function mountReportSetup(host, ctx) {
|
|
|
232
234
|
open ? cycRows(s) : null),
|
|
233
235
|
el('div', { class: 'acts' }, cy.length || paused || s.source !== 'work' ? pbtn('outline', 'Open', 'out', { 'data-rs-act': 'open-reg', onclick: () => openSetup(s) })
|
|
234
236
|
: pbtn('outline', 'Draft it now', 'spark', { 'data-rs-act': 'draft-now', onclick: () => openSetup(s) }),
|
|
237
|
+
s.source === 'work' ? pbtn('ghost', 'Shape the report', 'todo', { 'data-rs-act': 'shape', onclick: () => openStructure({ ws: RS.ws, id: s.id, name: s.name }) }) : null,
|
|
235
238
|
s.source === 'work' ? pbtn('ghost', 'Design how it looks', 'spark', { 'data-rs-act': 'design', onclick: () => openStudio({ ws: RS.ws, id: s.id, name: s.name }) }) : null,
|
|
236
239
|
pbtn('ghost', 'All cycles (' + n + ')', 'fold', { 'data-rs-act': 'cyc', 'aria-expanded': String(open), onclick: () => { if (RS.cyc.has(s.id)) RS.cyc.delete(s.id); else RS.cyc.add(s.id); drawSetups(); } }),
|
|
237
240
|
pbtn('ghost', paused ? 'Resume' : 'Pause', paused ? 'play' : 'pause', { 'data-rs-act': 'pause', onclick: () => pauseResume(s, !paused) })));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* pm/c3-report-structure.css — the Structure step of the report studio (c3-report-structure.js; mockup 43-reportstructure.css).
|
|
2
|
+
The conversation reuses the Design studio's .rd-dks-* rules (c3-report-deck.css). Tokens only; font sizes are the --fs-* scale. */
|
|
3
|
+
.c3 .rs-st { display: grid; gap: var(--sp-3); min-width: 0; }
|
|
4
|
+
.c3 .rs-st-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
|
|
5
|
+
.c3 .rs-st-bar .seg button { display: inline-flex; gap: 4px; align-items: center; }
|
|
6
|
+
.c3 .rs-st .rd-dks-out > .card.sect { margin: 0; }
|
|
7
|
+
.c3 .rs-st-q { display: grid; gap: 4px; }
|
|
8
|
+
.c3 .rs-st-q b { font-size: var(--fs-2); font-weight: 500; }
|
|
9
|
+
.c3 .rs-st-small { font-size: var(--fs-2); }
|
|
10
|
+
.c3 .rs-st-tiny { font-size: var(--fs-1); }
|
|
11
|
+
.c3 .rs-st-fg { color: var(--foreground); }
|
|
12
|
+
.c3 .rs-st-field { display: grid; gap: 2px; font-size: var(--fs-2); }
|
|
13
|
+
.c3 .rs-st-field input { width: 100%; box-sizing: border-box; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--card); color: var(--foreground); font: var(--fs-3)/1.4 var(--sans); }
|
|
14
|
+
.c3 .rs-st-form { display: grid; gap: 8px; padding: 8px 10px; margin: 0 0 4px; border: 1px solid var(--border); border-radius: 8px; background: var(--background); }
|
|
15
|
+
.c3 .rs-st-tw { overflow-x: auto; }
|
|
16
|
+
.c3 .rs-st-tbl { min-width: 640px; font-size: var(--fs-2); }
|
|
17
|
+
.c3 .rs-st-tbl td { vertical-align: top; }
|
|
18
|
+
.c3 .rs-st-row.on td { background: var(--muted); }
|
|
19
|
+
.c3 .rs-st-tbl .tt { text-align: left; }
|
|
20
|
+
.c3 .rs-st-det > td { border-top: 0; padding-top: 0; }
|
|
21
|
+
.c3 .rs-st-detb { display: grid; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--background); }
|
|
22
|
+
.c3 .rs-st-detb p, .c3 .rs-st-opt p, .c3 .rs-st-p { margin: 2px 0 0; font-size: var(--fs-3); line-height: 1.5; }
|
|
23
|
+
.c3 .rs-st-detb .dim.mono, .c3 .rs-st-opt .dim.mono { font-size: var(--fs-1); }
|
|
24
|
+
.c3 .rs-st-code { font-size: var(--fs-2); overflow-wrap: anywhere; }
|
|
25
|
+
.c3 .rs-st-ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
|
|
26
|
+
.c3 .rs-st-ol > li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 8px; align-items: start; }
|
|
27
|
+
.c3 .rs-st-ol .chips { margin-top: 4px; }
|
|
28
|
+
.c3 .rs-st-n { display: grid; place-items: center; width: 24px; height: 24px; border: 1px solid var(--border); border-radius: 6px; font-size: var(--fs-1); color: var(--muted-foreground); }
|
|
29
|
+
.c3 .rs-st-mini { margin: 0; padding-left: 20px; display: grid; gap: 2px; font-size: var(--fs-2); }
|
|
30
|
+
.c3 .rs-st-opts { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-2); }
|
|
31
|
+
.c3 .rs-st-opt { display: grid; gap: 10px; align-content: start; margin: 0; }
|
|
32
|
+
.c3 .rs-st-chk > li { grid-template-columns: 16px minmax(0, 1fr) auto; }
|
|
33
|
+
.c3 .rs-st-saved { display: grid; gap: var(--sp-3); }
|
|
34
|
+
.c3 .rs-st .rd-dks-panel { display: flex; flex-direction: column; max-height: 42vh; overflow: auto; }
|
|
35
|
+
.c3 .rs-st .rd-dks-panel > * { flex: none; }
|
|
36
|
+
@media (max-width: 760px) {
|
|
37
|
+
.c3 .rs-st .rd-dks { grid-template-columns: minmax(0, 1fr); }
|
|
38
|
+
.c3 .rs-st .rd-dks-chat { position: static; max-height: none; }
|
|
39
|
+
.c3 .rs-st .rd-dks-log { max-height: 420px; }
|
|
40
|
+
}
|