create-pmos 0.185.0 → 0.187.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/scripts/workflow-state.js +2 -1
- package/payload/state/discoveries.md +1 -1
- package/workspace/c3-ib-triage-backlog-test.js +20 -13
- package/workspace/c3-ini-life-test.js +167 -0
- package/workspace/c3-initiatives-test.js +6 -6
- package/workspace/c3-phone-test.js +67 -16
- package/workspace/c3-quiet-test.js +2 -1
- package/workspace/c3-report-setup-test.js +1 -0
- package/workspace/guide/initiative-boards.md +37 -2
- package/workspace/guide/phone-companion.md +19 -4
- package/workspace/guide/reports-set-up.md +4 -2
- package/workspace/lib/engine/boards.js +73 -18
- package/workspace/lib/engine/workflow-state.js +2 -1
- package/workspace/lib/initiative-rows.js +2 -2
- package/workspace/lib/routes-boards.js +119 -6
- package/workspace/lib/routes-meeting-focus.js +19 -7
- package/workspace/lib/routes-report-setups.js +37 -4
- package/workspace/lib/vendor/scripts/workflow-state.js +2 -1
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-demo-boards.js +82 -17
- package/workspace/public/pm/c3-demo-focus.js +39 -1
- package/workspace/public/pm/c3-demo-rs.js +3 -1
- package/workspace/public/pm/c3-focus.css +53 -0
- package/workspace/public/pm/c3-focus.js +188 -44
- package/workspace/public/pm/c3-ib-initiatives.js +127 -60
- package/workspace/public/pm/c3-ib-items.js +2 -2
- package/workspace/public/pm/c3-ini-life.css +32 -0
- package/workspace/public/pm/c3-ini-life.js +379 -0
- package/workspace/public/pm/c3-ini-ui.js +12 -7
- package/workspace/public/pm/c3-initiatives.js +14 -4
- package/workspace/public/pm/c3-phone.css +3 -1
- package/workspace/public/pm/c3-phone.js +28 -8
- package/workspace/public/pm/c3-report-setup.js +8 -3
- package/workspace/public/pm/c3-report-store.js +14 -1
- package/workspace/server.js +7 -2
- package/workspace/test-lists/c3-ini-life.json +9 -0
|
@@ -14,7 +14,7 @@ import { openSheet, closeSheet } from './c3-sheet.js';
|
|
|
14
14
|
import { openDocSheet } from './c3-doc-sheet.js';
|
|
15
15
|
import { toast } from './c3-toast.js';
|
|
16
16
|
import { FORMATS, OUTPUTS, formatOf, ensureReportCss } from './c3-doc-formats.js';
|
|
17
|
-
import { RS, onReports, loadReports, askPmos, changeIt, cancelAsk, setupFrom, dismissLater, pauseResume, fromDashboard, goTo, evidenceKind, normProposal, scheduleLabel, nextDraftDate, dayText, docsOf, outChip, copyChip, srcChip } from './c3-report-store.js';
|
|
17
|
+
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';
|
|
18
18
|
|
|
19
19
|
const MON = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
20
20
|
/** 'Wed 21 Oct 2026' for a day, 'Oct 2026' for a month, any other slot as it is. */
|
|
@@ -122,6 +122,7 @@ function askCard(a, redo) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/* ── a report document in the document sheet ── */
|
|
125
|
+
RS.openDoc = (d) => openReportDoc(d); // the store's toasts open a document through this
|
|
125
126
|
export function openReportDoc(d, mode) {
|
|
126
127
|
ensureReportCss();
|
|
127
128
|
const setup = RS.setups.find((x) => x.id === d.setup) || null; const cyc = slotText(d.slot);
|
|
@@ -205,7 +206,10 @@ export function mountReportSetup(host, ctx) {
|
|
|
205
206
|
el('span', { class: 'chips2' }, stag(d), copyChip(d.output, d.copy), pbtn('ghost', 'Open', 'out', { onclick: () => openReportDoc(d) })))));
|
|
206
207
|
function openSetup(s) {
|
|
207
208
|
const L = docsOf(RS.docs, s.id); const d = L.find((x) => x.state === 'draft') || L[0];
|
|
208
|
-
if (d) openReportDoc(d);
|
|
209
|
+
if (d) { openReportDoc(d); return; }
|
|
210
|
+
if (s.source !== 'work' || s.status !== 'active') { toast('No draft yet. The first draft is ' + (s.next_draft ? dayText(s.next_draft) : 'when you confirm the day') + '.'); return; }
|
|
211
|
+
toast('Drafting ' + s.name + ' now. Nothing is sent.');
|
|
212
|
+
draftNow(s).then((nd) => { if (nd) openReportDoc(nd); });
|
|
209
213
|
}
|
|
210
214
|
function setupRow(s) {
|
|
211
215
|
const paused = s.status === 'paused'; const cy = docsOf(RS.docs, s.id); const n = s.cycles != null ? s.cycles : cy.length; const open = RS.cyc.has(s.id);
|
|
@@ -215,7 +219,8 @@ export function mountReportSetup(host, ctx) {
|
|
|
215
219
|
chip(icon('cal', 'sm'), s.label || scheduleLabel(s.schedule)), paused ? null : chip(icon('clock', 'sm'), 'Next draft ' + (s.next_draft ? dayText(s.next_draft) : 'not set yet')),
|
|
216
220
|
chip(icon('mail', 'sm'), 'Last issued ' + (s.last_issued ? dayText(s.last_issued) : 'not yet'))),
|
|
217
221
|
open ? cycRows(s) : null),
|
|
218
|
-
el('div', { class: 'acts' }, pbtn('outline', 'Open', 'out', { 'data-rs-act': 'open-reg', onclick: () => openSetup(s) })
|
|
222
|
+
el('div', { class: 'acts' }, cy.length || paused || s.source !== 'work' ? pbtn('outline', 'Open', 'out', { 'data-rs-act': 'open-reg', onclick: () => openSetup(s) })
|
|
223
|
+
: pbtn('outline', 'Draft it now', 'spark', { 'data-rs-act': 'draft-now', onclick: () => openSetup(s) }),
|
|
219
224
|
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(); } }),
|
|
220
225
|
pbtn('ghost', paused ? 'Resume' : 'Pause', paused ? 'play' : 'pause', { 'data-rs-act': 'pause', onclick: () => pauseResume(s, !paused) })));
|
|
221
226
|
}
|
|
@@ -114,9 +114,22 @@ export async function setupFrom(body) {
|
|
|
114
114
|
if (r.setup && r.setup.id) RS.newIds.add(r.setup.id);
|
|
115
115
|
await loadReports(RS.ws, true);
|
|
116
116
|
const fd = r.first_draft; const first = (r.setup && r.setup.next_draft) || (fd && typeof fd === 'object' ? fd.day || fd.slot : fd);
|
|
117
|
-
|
|
117
|
+
if (r.drafted && r.drafted.path) openDraftToast(r.setup.id, 'Set up. The first draft is ready to read. Nothing is sent.');
|
|
118
|
+
else toast('Set up. First draft ' + (first ? dayText(first) : 'once you confirm the day') + '. Nothing is sent.' + (r.drafted && r.drafted.error ? ' It could not be drafted yet: ' + r.drafted.error + '.' : ''));
|
|
118
119
|
return r;
|
|
119
120
|
}
|
|
121
|
+
/* the page that draws documents sets RS.openDoc, so a toast here can open one without this store importing the page */
|
|
122
|
+
function openDraftToast(id, text) {
|
|
123
|
+
const d = (RS.docs || []).filter((x) => x.setup === id && x.state === 'draft').sort((a, b) => (a.slot < b.slot ? 1 : -1))[0];
|
|
124
|
+
if (d && typeof RS.openDoc === 'function') toast({ text, actionLabel: 'Open', timeout: 8000, onAction: () => RS.openDoc(d) });
|
|
125
|
+
else toast(text);
|
|
126
|
+
}
|
|
127
|
+
/** Draft it now: the next cycle of a set-up report. → the new draft document, or null. */
|
|
128
|
+
export async function draftNow(setup) {
|
|
129
|
+
const r = await post('draft', { id: setup.id }); if (!r || !r.ok) { fail(r, 'It was not drafted'); return null; }
|
|
130
|
+
await loadReports(RS.ws, true);
|
|
131
|
+
return (RS.docs || []).find((x) => x.setup === setup.id && x.slot === r.drafted.slot) || null;
|
|
132
|
+
}
|
|
120
133
|
/** Not a report: the finding leaves the list at once, the POST waits five seconds, and Undo cancels it. */
|
|
121
134
|
export function dismissLater(id, onChange) {
|
|
122
135
|
RS.hidden.add(id); emit(); if (onChange) onChange();
|
package/workspace/server.js
CHANGED
|
@@ -1969,7 +1969,8 @@ function readLifecycle(w) {
|
|
|
1969
1969
|
for (const r of readLedger(w, 'lifecycle.jsonl')) {
|
|
1970
1970
|
if (!r || typeof r.initiative_id !== 'string') continue;
|
|
1971
1971
|
if (r.state !== 'active' && !STOPPED_STATES.includes(r.state)) continue;
|
|
1972
|
-
|
|
1972
|
+
// `back` (c3-initiative-lifecycle): the day an on-hold initiative comes back to the PM, when the hold named one.
|
|
1973
|
+
latest.set(r.initiative_id, { state: r.state, reason: r.reason || '', pm: r.pm || '', at: r.at || '', ...(r.state === 'on-hold' && /^\d{4}-\d{2}-\d{2}$/.test(r.back || '') ? { back: r.back } : {}) });
|
|
1973
1974
|
}
|
|
1974
1975
|
return latest;
|
|
1975
1976
|
}
|
|
@@ -8648,6 +8649,10 @@ async function handleRequest(req, res) {
|
|
|
8648
8649
|
if (body.state !== 'active' && !STOPPED_STATES.includes(body.state)) {
|
|
8649
8650
|
return json(res, { ok: false, error: `state must be one of ${STOPPED_STATES.concat('active').join(', ')}` }, 400);
|
|
8650
8651
|
}
|
|
8652
|
+
// A hold may name the day it comes back to the PM (c3-initiative-lifecycle). Only on-hold carries it.
|
|
8653
|
+
if (body.back != null && (body.state !== 'on-hold' || !/^\d{4}-\d{2}-\d{2}$/.test(String(body.back)))) {
|
|
8654
|
+
return json(res, { ok: false, error: 'back is a day (YYYY-MM-DD) and only goes with on-hold' }, 400);
|
|
8655
|
+
}
|
|
8651
8656
|
const w = getWs(body.ws);
|
|
8652
8657
|
if (!w) return json(res, { ok: false, error: 'no workspace' }, 400);
|
|
8653
8658
|
const known = new Set(initiativeIndex(w.root).initiatives.map((x) => x.id));
|
|
@@ -8662,7 +8667,7 @@ async function handleRequest(req, res) {
|
|
|
8662
8667
|
grant = m.grant_id;
|
|
8663
8668
|
}
|
|
8664
8669
|
const at = nowISO();
|
|
8665
|
-
const recs = ids.map((x) => ({ initiative_id: x, state: body.state, reason, pm: 'wawan', by: g.actor.by, via: g.actor.via, at, ...(grant ? { grant } : {}) }));
|
|
8670
|
+
const recs = ids.map((x) => ({ initiative_id: x, state: body.state, reason, ...(body.back ? { back: String(body.back) } : {}), pm: 'wawan', by: g.actor.by, via: g.actor.via, at, ...(grant ? { grant } : {}) }));
|
|
8666
8671
|
const rec = recs[0];
|
|
8667
8672
|
// The ledger the ENGINE reads for this repository's layout (scripts/workflow-state.js#layout): a repository
|
|
8668
8673
|
// with planning/initiatives/ keeps its ledgers in planning/runs/, a kit in pmos/state/. Writing anywhere else
|