create-pmos 0.208.0 → 0.209.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-phone-test.js +5 -0
- package/workspace/guide/phone-companion.md +1 -1
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-phone.css +1 -0
- package/workspace/public/pm/c3-phone.js +24 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pmos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.209.0",
|
|
4
4
|
"description": "Scaffold the PMOS portable kit — run the PMOS product-management workflow (initiative → lane-fit spec → contract → build → three gates, with work-type lanes for features, research, maintenance, incidents, and content) entirely inside your own repo, with all state as git-versioned files. Includes `workflow-sweep`, which audits the state every board derives from and separates real defects from work you simply have not done. `create-pmos workspace` also installs + launches the local Terminal Workspace GUI. No database, no network, no telemetry.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
package/payload/KIT-VERSION
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Eval calibration log"
|
|
4
4
|
description: "Append-only record of every PM override of an evaluator verdict."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-14T01:
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-14T01:49:09Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Health budgets"
|
|
4
4
|
description: "Closed registry of health-budget anchors (D59), edited only by the PM."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-14T01:
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-14T01:49:09Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Discoveries and friction log"
|
|
4
4
|
description: "Append-only record of what runs discovered and where the process rubbed."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-14T01:
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-14T01:49:09Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -98,6 +98,11 @@ const writes = (p) => (window.__c3demoWrites || []).filter((w) => w.path === p |
|
|
|
98
98
|
}
|
|
99
99
|
/* ── the brief: everything the desktop Briefing counts waits here, and each row opens ── */
|
|
100
100
|
ok('brief: the morning card counts what waits on you', await waitFor(page, () => /wait on you|waits on you/.test(document.querySelector('[data-c3ph-moment="morning"]')?.textContent || ''), null, 8000));
|
|
101
|
+
ok('brief: the morning shows the top three points of the Briefing deck', await waitFor(page, () => { const c = document.querySelector('[data-c3ph-moment="morning"]'); return !!c && c.querySelectorAll('[data-c3ph-point]').length === 3 && /things this morning/.test(c.textContent); }, null, 8000));
|
|
102
|
+
await page.click('[data-c3ph-moment="morning"] [data-c3ph-point]');
|
|
103
|
+
ok('brief: a point opens its details', await waitFor(page, () => !!document.querySelector('[data-shell="sheet"] [data-c3ph-need]'), null, 5000));
|
|
104
|
+
await page.keyboard.press('Escape');
|
|
105
|
+
await waitFor(page, () => !document.querySelector('[data-shell="sheet"] [data-c3ph-need]'), null, 3000);
|
|
101
106
|
ok('brief: the briefing needs are in the waiting list', await waitFor(page, () => !!document.querySelector('[data-c3ph-all-open]'), null, 8000));
|
|
102
107
|
if (await page.$('[data-c3ph-all-open]')) {
|
|
103
108
|
await page.click('[data-c3ph-all-open]');
|
|
@@ -15,7 +15,7 @@ The top card shows where you are in your day and why it is useful now. PMOS choo
|
|
|
15
15
|
|
|
16
16
|
| Moment | When | What the card shows |
|
|
17
17
|
|---|---|---|
|
|
18
|
-
| Your
|
|
18
|
+
| Your morning | Before noon, with no meeting in the next 30 minutes | Your briefing: the top three points of the desktop Briefing, each opens its details. Then how many things wait on you, how many drafts wait for your review, and the first meeting with **The brief of this meeting** |
|
|
19
19
|
| Before you walk in | The next meeting starts in 30 minutes or less | What is prepared for it, the items to close first, each with **Done**, and **The brief of this meeting** |
|
|
20
20
|
| In the meeting | A meeting is in progress | **Record this meeting?** with **Record** and **Not this one**. Recording opens focus (see below). |
|
|
21
21
|
| Just ended | A meeting ended less than 20 minutes ago | **What came out of it?** If you recorded the meeting, the card shows the summary, the decisions, the actions and the open questions from its notes, the same notes as on the Notes page. While PMOS writes the notes, the card says so. If you did not record it, **Tell PMOS** puts the meeting name in the bar so you can type the result. |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmos-workspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.209.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pmos-workspace",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.209.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@xterm/addon-fit": "^0.11.0",
|
package/workspace/package.json
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* actions and questions picked out so far (dest-notes.js partsOf), as the desktop note shows them
|
|
9
9
|
* before a meeting: when it starts, who, what is prepared, the "before you go" items with Done
|
|
10
10
|
* just ended: tell PMOS what came out of it a free gap: the own items that fit, with Done and Later today
|
|
11
|
-
* morning: the
|
|
11
|
+
* morning ("Your morning"): the briefing, the top three cards of the desktop Briefing's deck (GET /api/briefing cards), each
|
|
12
|
+
* opening its details; how much waits; the drafts waiting for review; then the first meeting with its brief
|
|
12
13
|
* working hours, and a free gap: "Finished for you", the agent's drafts of today (GET /api/phone-day finished), each opens
|
|
13
14
|
* to read (c3-phone-detail.js openDraft); approving one waits for the desk
|
|
14
15
|
* evening (recap, from 17:00): how today went (GET /api/phone-day recap), what moved, what is still open, one thing tonight
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
* There is no way to the desktop pages on a phone.
|
|
32
33
|
* The moment is worked out again every minute; when it changes, a short banner says so. ?at=HH:MM sets the clock in demo mode only. */
|
|
33
34
|
import { el } from './dom.js';
|
|
34
|
-
import { button, iconButton } from './primitives.js';
|
|
35
|
+
import { button, iconButton, ensureComponentsCss } from './primitives.js';
|
|
35
36
|
import { pmPost, pmGet } from './http.js';
|
|
36
37
|
import { ensureC3Css, c3ic } from './pm-work-view.js';
|
|
37
38
|
import { onBriefPage, loadBriefPage } from './c3-brief-data.js';
|
|
@@ -66,7 +67,7 @@ export function phoneWanted(store) {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export function mountPhone(root, ctx = {}) {
|
|
69
|
-
ensureC3Css(); ensureCss();
|
|
70
|
+
ensureC3Css(); ensureComponentsCss(); ensureCss();
|
|
70
71
|
const demo = !!ctx.demo;
|
|
71
72
|
const q = new URLSearchParams(location.search);
|
|
72
73
|
const at = demo && /^\d{1,2}:\d{2}$/.test(q.get('at') || '') ? q.get('at').split(':').map(Number) : null;
|
|
@@ -220,6 +221,15 @@ export function mountPhone(root, ctx = {}) {
|
|
|
220
221
|
return out;
|
|
221
222
|
}
|
|
222
223
|
const decisions = () => waitRows().filter((r) => !r.pm).length;
|
|
224
|
+
/* the top points of the desktop Briefing (GET /api/briefing cards, the deck), at most three, each opening its details */
|
|
225
|
+
function briefPoints() {
|
|
226
|
+
const cards = (S.briefing && Array.isArray(S.briefing.cards) ? S.briefing.cards : []).filter((c) => c && c.headline);
|
|
227
|
+
return cards.slice(0, 3).map((c, i) => {
|
|
228
|
+
const v = cardView(c);
|
|
229
|
+
return { id: String(c.key || 'card' + i), pm: false, decide: !!(c.move && c.move.options), headline: v.headline,
|
|
230
|
+
label: v.tag + (v.deadline && v.deadline.text ? ' · ' + v.deadline.text : ''), why: c.why && c.why.text, url: c.url, urlLabel: c.url_label, facts: v.facts };
|
|
231
|
+
});
|
|
232
|
+
}
|
|
223
233
|
const needOpts = { onDone: (r) => itemDone(r), onLater: (r) => itemLater(r, 'later-today') };
|
|
224
234
|
const focus = (m) => import('./c3-focus.js').then((f) => f.openFocus({ event: { id: m.id, start: m.start, at: m.start, end: m.end || null, title: m.title }, date: String(m.start || '').slice(0, 10), phone: true }))
|
|
225
235
|
.catch(() => toast('Focus did not open.'));
|
|
@@ -316,11 +326,18 @@ export function mountPhone(root, ctx = {}) {
|
|
|
316
326
|
if (mo.kind === 'recap') return recapCard();
|
|
317
327
|
if (mo.kind === 'night') return nightCard();
|
|
318
328
|
if (mo.kind === 'morning') {
|
|
329
|
+
/* the morning is the briefing (mockup version 7, "Your morning"): the top points of the desktop Briefing's deck, then the first meeting */
|
|
319
330
|
const w = waitRows(); const late = w.filter((r) => /overdue|late/i.test(r.label)).length;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
331
|
+
const pts = briefPoints();
|
|
332
|
+
const rv = S.briefing && Array.isArray(S.briefing.review) ? S.briefing.review.length : 0;
|
|
333
|
+
return card(true, { 'data-c3ph-moment': 'morning', 'data-c3ph-brief-points': String(pts.length) }, why('Your morning'),
|
|
334
|
+
big(!S.briefing ? 'Reading your briefing' : pts.length ? (pts.length === 1 ? 'One thing this morning' : ['', '', 'Two', 'Three'][pts.length] + ' things this morning') : 'Nothing pressing this morning'),
|
|
335
|
+
pts.length ? el('div', { class: 'c3ph-pts' }, ...pts.map((r) => row({ title: r.headline, meta: [r.label], compact: true, onOpen: () => openNeed(r, needOpts), openLabel: 'Open ' + r.headline, attrs: { 'data-c3ph-point': r.id } }))) : null,
|
|
336
|
+
line([w.length ? w.length + (w.length === 1 ? ' thing waits on you' : ' things wait on you') + (late ? ', ' + late + ' overdue.' : '.') : 'Nothing waits on you.',
|
|
337
|
+
rv ? (rv === 1 ? '1 draft waits' : rv + ' drafts wait') + ' for your review on your computer.' : null].filter(Boolean).join(' ')),
|
|
338
|
+
mo.next ? el('div', { class: 'c3ph-fit', 'data-c3ph-first': mo.next.id }, el('b', null, 'First up: ' + mo.next.title + ' at ' + hm(mo.next.start)),
|
|
339
|
+
line(inText((Date.parse(mo.next.start) - now().getTime()) / 60000).replace(/^in/, 'In') + (who(mo.next) ? ' · ' + who(mo.next) : '')),
|
|
340
|
+
acts(btn('The brief of this meeting', 'outline', 'calendar', { 'data-c3ph-meeting-open': mo.next.id }, () => meetingSheet(mo.next)))) : line('No meetings today.'));
|
|
324
341
|
}
|
|
325
342
|
return recapCard();
|
|
326
343
|
}
|