create-pmos 0.523.0 → 0.524.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 +44 -16
- 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/changelog.json +43 -0
- package/workspace/guide/agent-capabilities.md +6 -3
- package/workspace/guide/home.md +1 -1
- package/workspace/guide/horizon-scan.md +2 -2
- package/workspace/guide/idle-lab.md +46 -0
- package/workspace/guide/index.md +2 -0
- package/workspace/guide/moments.md +43 -0
- package/workspace/guide/welcome.md +37 -28
- package/workspace/lib/bg-queue.js +226 -0
- package/workspace/lib/driver-run.js +8 -1
- package/workspace/lib/first-reveal.js +311 -0
- package/workspace/lib/idle-lab.js +275 -0
- package/workspace/lib/moments.js +241 -0
- package/workspace/lib/morning-goals.js +191 -0
- package/workspace/lib/onboard-fundamentals.js +205 -0
- package/workspace/lib/onboarding-progress.js +13 -1
- package/workspace/lib/orchestrator-spawn.js +9 -2
- package/workspace/lib/project-onboard.js +86 -6
- package/workspace/lib/proposals.js +9 -5
- package/workspace/lib/route-modules.js +4 -0
- package/workspace/lib/routes-lab.js +137 -0
- package/workspace/lib/routes-loose.js +1 -0
- package/workspace/lib/routes-moments.js +42 -0
- package/workspace/lib/routes-morning-goals.js +109 -0
- package/workspace/lib/routes-onboard.js +28 -8
- package/workspace/lib/routes-proposals.js +12 -2
- package/workspace/lib/routes-reveal.js +73 -0
- package/workspace/lib/scan-run.js +4 -3
- package/workspace/lib/scan.js +5 -3
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/project-onboard-flow-test.js +70 -57
- package/workspace/public/pm/cozy-ev.css +3 -0
- package/workspace/public/pm/cozy-lab-ins.js +87 -0
- package/workspace/public/pm/cozy-lab.css +86 -0
- package/workspace/public/pm/cozy-lab.js +138 -0
- package/workspace/public/pm/cozy-nav.js +22 -8
- package/workspace/public/pm/cozy-onboard.css +31 -0
- package/workspace/public/pm/cozy-onboard.js +217 -111
- package/workspace/public/pm/cozy-reveal.css +52 -0
- package/workspace/public/pm/cozy-reveal.js +130 -0
- package/workspace/public/pm/home-app.js +38 -3
- package/workspace/public/pm/home-impact.css +12 -0
- package/workspace/public/pm/home-moment.js +41 -0
- package/workspace/public/pm/ini-props.js +15 -6
- package/workspace/public/pm/premium-board.js +2 -0
- package/workspace/public/pm/premium-first.js +1 -1
- package/workspace/public/pm/premium-insights.js +6 -1
- package/workspace/public/pm/quiet-place.js +31 -0
- package/workspace/public/premium-intelligence.html +3 -0
- package/workspace/replaced-tests.json +14 -0
- package/workspace/server.js +46 -5
- package/workspace/test-files.json +2 -0
- package/workspace/test-lists/first-reveal.json +9 -0
- package/workspace/test-lists/idle-lab.json +9 -0
- package/workspace/test-lists/morning-goals.json +9 -0
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { esc, svg, ICON, wsQ } from './cozy-evui.js';
|
|
23
23
|
import { fabLabel, bannerOf } from './cozy-evmodel.js';
|
|
24
|
-
import { mountToastFaces, loadPrefs, adlerPeek, asleep } from './cozy-adler.js';
|
|
24
|
+
import { mountToastFaces, loadPrefs, adlerPeek, asleep } from './cozy-adler.js';
|
|
25
|
+
import { pmPost } from './http.js'; // Adler (batch 16 item 2): every toast carries his S face; Settings > Adler is read once
|
|
25
26
|
|
|
26
27
|
export const PLACES = [
|
|
27
28
|
{ key: 'home', label: 'Home', href: '/premium.html', d: ICON.home },
|
|
@@ -31,7 +32,11 @@ export const PLACES = [
|
|
|
31
32
|
export { fabLabel };
|
|
32
33
|
const THEME_KEY = 'pmos.c3.theme';
|
|
33
34
|
const CSS = new URL('./cozy-ev.css', import.meta.url).href;
|
|
34
|
-
const N = { news: 0, stale: null, here: 'home', calls: 0 };
|
|
35
|
+
const N = { news: 0, stale: null, here: 'home', calls: 0, fresh: new Set() };
|
|
36
|
+
/* A place that just opened (onboarding B3, ObA4Gradual; GET /api/moments places[p].dot): its menu row gets one soft blue dot until the PM
|
|
37
|
+
* first opens it. Reports live in Intelligence, so their dot is on the Intelligence row. */
|
|
38
|
+
const ROW_OF = { board: 'board', insights: 'insights', reports: 'insights' };
|
|
39
|
+
export const freshRows = (places) => new Set(Object.entries(places || {}).filter(([, v]) => v && v.dot).map(([k]) => ROW_OF[k]).filter(Boolean));
|
|
35
40
|
|
|
36
41
|
const store = { get(k) { try { return localStorage.getItem(k); } catch { return null; } }, set(k, v) { try { if (v) localStorage.setItem(k, v); else localStorage.removeItem(k); } catch { /* a private window */ } } };
|
|
37
42
|
/** The theme the PM picked on this device: light, dark or auto. */
|
|
@@ -50,8 +55,9 @@ export function setTheme(pick, doc = document, { keep = true } = {}) {
|
|
|
50
55
|
export function menuHtml(here, o = {}) {
|
|
51
56
|
const news = o.news > 0, dot = (c) => `<i class="ev-md ${c}" aria-hidden="true"></i>`;
|
|
52
57
|
return PLACES.map((p) => {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
58
|
+
const opened = p.key !== here && !!(o.fresh && o.fresh.has(p.key));
|
|
59
|
+
const you = (p.key === 'home' && news) || opened;
|
|
60
|
+
const lab = p.key === 'home' && news ? ` aria-label="${p.label}. ${o.news} new for you in Your day"` : opened ? ` aria-label="${p.label}. New: it has something to show now"` : '';
|
|
55
61
|
return `<a href="${p.href}"${p.key === here ? ' aria-current="page"' : ''}${lab}>${svg(p.d, 18)}${p.key === here ? `<b>${p.label}</b>` : `<span>${p.label}</span>`}${you ? dot('you') : ''}</a>`;
|
|
56
62
|
}).join('')
|
|
57
63
|
+ '<div class="ev-tray">'
|
|
@@ -88,10 +94,11 @@ export function mountNav(here, doc = document, opts = {}) {
|
|
|
88
94
|
mountToastFaces(doc); loadPrefs();
|
|
89
95
|
const fab = w.querySelector('#czFab'), menu = w.querySelector('#czMenu'), scrim = w.querySelector('#czScrim');
|
|
90
96
|
const draw = () => {
|
|
91
|
-
menu.innerHTML = menuHtml(here, { news: N.news, stale: N.stale });
|
|
92
|
-
|
|
97
|
+
menu.innerHTML = menuHtml(here, { news: N.news, stale: N.stale, fresh: N.fresh });
|
|
98
|
+
const opened = [...N.fresh].some((k) => k !== here);
|
|
99
|
+
w.querySelector('#czFdYou').hidden = !(N.news > 0 || opened) || !menu.hidden;
|
|
93
100
|
w.querySelector('#czFdRisk').hidden = !N.stale || !menu.hidden;
|
|
94
|
-
if (menu.hidden) fab.setAttribute('aria-label', fabLabel(here, false, N.stale, N.news) + (earsOn() ? '. ' + callWords(N.calls) : ''));
|
|
101
|
+
if (menu.hidden) fab.setAttribute('aria-label', fabLabel(here, false, N.stale, N.news) + (opened ? '. A place has something new to show' : '') + (earsOn() ? '. ' + callWords(N.calls) : ''));
|
|
95
102
|
drawEars();
|
|
96
103
|
};
|
|
97
104
|
// AdP6: the ears are drawn once and kept while the count stays above zero, so a redraw never replays them
|
|
@@ -132,7 +139,14 @@ export function mountNav(here, doc = document, opts = {}) {
|
|
|
132
139
|
}, true);
|
|
133
140
|
const read = async () => {
|
|
134
141
|
if (doc.hidden) return;
|
|
135
|
-
const [n, s] = await Promise.all([getj('/api/news-for-you' + wsQ()), getj('/api/sources' + wsQ())]);
|
|
142
|
+
const [n, s, mo] = await Promise.all([getj('/api/news-for-you' + wsQ()), getj('/api/sources' + wsQ()), getj('/api/moments')]);
|
|
143
|
+
if (mo && mo.ok) {
|
|
144
|
+
// the place the PM is on is visited: its dot clears (Intelligence also clears the reports dot, they live here)
|
|
145
|
+
const mine = Object.keys(ROW_OF).filter((k) => ROW_OF[k] === here && mo.places && mo.places[k] && mo.places[k].dot);
|
|
146
|
+
for (const k of mine) { mo.places[k].dot = false; pmPost('/api/moments/visit', { place: k }).catch(() => {}); }
|
|
147
|
+
N.fresh = freshRows(mo.places);
|
|
148
|
+
doc.dispatchEvent(new CustomEvent('cz:moments', { detail: mo }));
|
|
149
|
+
}
|
|
136
150
|
if (n && n.ok) { N.news = n.count || 0; doc.dispatchEvent(new CustomEvent('cz:news-for-you', { detail: n })); }
|
|
137
151
|
if (s && s.ok) { N.stale = bannerOf(s.sources); doc.dispatchEvent(new CustomEvent('cz:sources', { detail: s })); } // Your day's failed source (AdP5)
|
|
138
152
|
if (menu.hidden || !menu.contains(doc.activeElement)) draw();
|
|
@@ -58,3 +58,34 @@ body.ob-on #hmChat[hidden] { display: none; }
|
|
|
58
58
|
.cs-checklist[hidden] { display: none; }
|
|
59
59
|
.cs-checklist p { margin: 0; font-size: var(--fs-meta); color: var(--cz-ink2); line-height: var(--lh-meta); }
|
|
60
60
|
.cs-checklist .ut-btn { align-self: flex-start; text-decoration: none; }
|
|
61
|
+
/* onboarding build B1: the ✦ proposals (✓ ✕ only), the source tiles and the fundamentals card */
|
|
62
|
+
.ob-prop { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px 12px; max-width: 720px; box-sizing: border-box; }
|
|
63
|
+
.ob-pt { margin: 0; display: flex; gap: 8px; align-items: baseline; font-size: var(--fs-body); font-weight: var(--fw-strong); color: var(--cz-ink); line-height: var(--lh-body); }
|
|
64
|
+
.ob-spark { color: var(--cz-blueink); flex: none; }
|
|
65
|
+
.ob-pl { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
|
|
66
|
+
.ob-pl > li { padding: 8px 0; border-top: 1px solid var(--cz-hair); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--cz-ink); overflow-wrap: anywhere; }
|
|
67
|
+
.ob-pl > li b { color: var(--cz-ink2); font-size: var(--fs-meta); line-height: var(--lh-meta); margin-right: 6px; }
|
|
68
|
+
.ob-pl a, .ob-fund a { color: var(--cz-blueink); }
|
|
69
|
+
.ob-yn { display: flex; gap: 8px; justify-content: flex-end; padding-top: 2px; }
|
|
70
|
+
.ob-yn .ob-no { background: var(--cz-well); color: var(--cz-ink2); }
|
|
71
|
+
.ob-yn .ut-ib { width: 44px; height: 44px; }
|
|
72
|
+
.ob-lk { font: inherit; font-size: var(--fs-meta); line-height: var(--lh-meta); border: 0; padding: 0; background: none; color: var(--cz-blueink); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
|
|
73
|
+
.ob-lk:disabled { color: var(--cz-ink3); cursor: default; }
|
|
74
|
+
.ob-fl { display: grid; grid-template-columns: 90px minmax(0, 1fr) auto; gap: 4px 12px; align-items: center; }
|
|
75
|
+
.ob-fl > span { min-width: 0; }
|
|
76
|
+
.ob-fl em { grid-column: 2; font-style: normal; font-size: var(--fs-meta); color: var(--cz-ink3); line-height: var(--lh-meta); }
|
|
77
|
+
.ob-fl .ob-pen { grid-column: 3; grid-row: 1; }
|
|
78
|
+
.ob-miss { color: var(--cz-ink3); }
|
|
79
|
+
.ob-rv .ob-fld { grid-template-columns: 90px minmax(0, 1fr); border-top: 0; padding: 0; }
|
|
80
|
+
.ob-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; max-width: 720px; }
|
|
81
|
+
.ob-tile { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px; min-width: 0; }
|
|
82
|
+
.ob-tile .ob-ts { font-size: var(--fs-label); font-weight: var(--fw-strong); color: var(--cz-blueink); line-height: var(--lh-label); }
|
|
83
|
+
.ob-tile b { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--cz-ink); overflow-wrap: anywhere; }
|
|
84
|
+
.ob-tile b a { color: inherit; text-decoration: none; }
|
|
85
|
+
.ob-tile > span:last-child { font-size: var(--fs-meta); color: var(--cz-ink2); line-height: var(--lh-meta); }
|
|
86
|
+
.ob-fund li { align-items: flex-start; }
|
|
87
|
+
.ob-fund li svg { margin-top: 3px; }
|
|
88
|
+
.ob-fund li > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
89
|
+
.ob-fund li em { font-style: normal; font-size: var(--fs-meta); color: var(--cz-ink3); line-height: var(--lh-meta); overflow-wrap: anywhere; }
|
|
90
|
+
.ob-fund li .ob-lk { align-self: flex-start; }
|
|
91
|
+
@media (max-width: 760px) { .ob-fl { grid-template-columns: minmax(0, 1fr) auto; } .ob-fl em { grid-column: 1; } .ob-fl .ob-pen { grid-column: 2; } .ob-rv .ob-fld { grid-template-columns: minmax(0, 1fr); } }
|