create-pmos 0.137.0 → 0.138.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pmos",
3
- "version": "0.137.0",
3
+ "version": "0.138.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": {
@@ -1,3 +1,3 @@
1
- kernel-source: pmos@6693e56
1
+ kernel-source: pmos@fe0b38d
2
2
  assembled: 2026-10-12
3
3
  mode: vendor
@@ -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-12T00:57:28Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T01:10:16Z"}
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-12T00:57:28Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T01:10:16Z"}
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-12T00:57:28Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T01:10:16Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -4,7 +4,7 @@
4
4
  * Loads /c3.html?demo=1 (demo mode answers every /api call, so nothing reaches the server) and holds:
5
5
  * R1 two columns: stance + deck + Needs you on the left; Today + Portfolio pulse on the right
6
6
  * R2 Review, Handled, What I could stop and Data you can lean on are not on the Briefing
7
- * R3 the greeting follows the clock; five day-part buttons (Night included) preview a part and the clock's part comes back on a tap
7
+ * R3 the greeting and the lens line follow the clock; there is no day-part switch (initiative c3-daypart-auto-only)
8
8
  * R4 Today: a lead line with a ring, "Open calendar", rows with chips (nrow), no old two-column prepared/before layout
9
9
  * R5 Needs you: "N decisions . M of yours" header, decision tags, a Work home chip on own items
10
10
  * R6 Portfolio pulse: "N need attention", rows, "All initiatives" goes to Initiatives; 400 wide has no sideways scroll
@@ -74,22 +74,16 @@ process.on('unhandledRejection', (e) => { console.error(e); finish(1); });
74
74
  ok('R2 no Review, Handled, Stop or Data trust on the Briefing', await p.evaluate(() => !document.querySelector('[data-c3pg="review-host"], [data-c3pg="handled-host"], [data-c3pg="stop-host"], [data-c3pg="trust-host"]') && !/Data you can lean on|What I could stop|handled for you/i.test(document.querySelector('.c3 .brief').textContent)));
75
75
 
76
76
  /* R3 */
77
- const dp = () => p.evaluate(() => ({ greet: document.querySelector('.stance b').textContent, line: document.querySelector('.stance .dim').textContent, keys: [...document.querySelectorAll('.stance [data-pg-dp]')].map((b) => b.dataset.pgDp), on: [...document.querySelectorAll('.stance [data-pg-dp]')].filter((b) => b.getAttribute('aria-pressed') === 'true').map((b) => b.dataset.pgDp) }));
78
- const d0 = await dp();
79
- ok('R3 five day-part buttons, Night last', d0.keys.join() === 'morning,midday,afternoon,evening,night', d0.keys.join());
80
- ok('R3 the greeting names the part of the day and the PM', /^Good (morning|afternoon|evening|night), \w+/.test(d0.greet) && d0.on.length === 1, JSON.stringify(d0));
81
- const clockPart = d0.on[0];
82
- const other = clockPart === 'night' ? 'midday' : 'night';
83
- await p.click(`.stance [data-pg-dp="${other}"]`);
84
- const d1 = await until(async () => { const d = await dp(); return d.on[0] === other ? d : null; }, 4000);
85
- ok('R3 a tap previews that part: pressed, its greeting', !!d1 && d1.greet !== d0.greet && /^Good /.test(d1.greet), JSON.stringify(d1));
86
- await p.click(`.stance [data-pg-dp="night"]`);
87
- const dn = await until(async () => { const d = await dp(); return d.on[0] === 'night' ? d : null; }, 4000);
88
- ok('R3 Night previews: "Good night" and the Reflect line', !!dn && /^Good night/.test(dn.greet) && /^Reflect/.test(dn.line), JSON.stringify(dn));
89
- ok('R3 the Night preview names Needs you "Carries over"', await p.evaluate(() => /Carries over/i.test(document.querySelector('[data-c3pg="needs"] .sh2 h2').textContent)));
90
- await p.click(`.stance [data-pg-dp="${clockPart}"]`);
91
- const d2 = await until(async () => { const d = await dp(); return d.on[0] === clockPart ? d : null; }, 4000);
92
- ok('R3 a tap on the clock part brings it back', !!d2 && d2.greet === d0.greet, JSON.stringify(d2));
77
+ const d0 = await p.evaluate(() => {
78
+ const h = new Date().getHours();
79
+ const k = h >= 5 && h < 11 ? 'morning' : h >= 11 && h < 14 ? 'midday' : h >= 14 && h < 17 ? 'afternoon' : h >= 17 && h < 21 ? 'evening' : 'night';
80
+ const st = document.querySelector('.stance');
81
+ return { k, part: st.dataset.part, greet: st.querySelector('b').textContent, line: st.querySelector('.dim').textContent, buttons: document.querySelectorAll('[data-pg-dp], .seg.dp').length };
82
+ });
83
+ const want = { morning: ['Good morning', 'Plan'], midday: ['Good afternoon', 'Unblock'], afternoon: ['Good afternoon', 'Close'], evening: ['Good evening', 'Reflect'], night: ['Good night', 'Reflect'] }[d0.k];
84
+ ok('R3 no day-part switch on the page', d0.buttons === 0, JSON.stringify(d0));
85
+ ok('R3 the stance follows the clock: its part, greeting and lens line', d0.part === d0.k && d0.greet.startsWith(want[0] + ', ') && d0.line.startsWith(want[1] + ':'), JSON.stringify(d0));
86
+ ok('R3 at night or in the evening Needs you reads "Carries over"', want[1] !== 'Reflect' || await p.evaluate(() => /Carries over/i.test(document.querySelector('[data-c3pg="needs"] .sh2 h2').textContent)));
93
87
 
94
88
  /* R4 */
95
89
  const td = await p.evaluate(() => {
@@ -123,7 +117,7 @@ process.on('unhandledRejection', (e) => { console.error(e); finish(1); });
123
117
 
124
118
  const M = await open({ viewport: { width: 400, height: 900 } });
125
119
  ok('R6 at 400 wide the Briefing does not scroll sideways', M.up && await M.page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1 && document.getElementById('c3-root').scrollWidth <= innerWidth + 1), 'scrollWidth');
126
- ok('R6 at 400 wide the day-part switch and Needs you are on the page', await M.page.evaluate(() => document.querySelectorAll('.stance [data-pg-dp]').length === 5 && !!document.querySelector('[data-c3pg="needs"]')));
120
+ ok('R6 at 400 wide the stance and Needs you are on the page, with no day-part switch', await M.page.evaluate(() => !!document.querySelector('.stance') && document.querySelectorAll('[data-pg-dp]').length === 0 && !!document.querySelector('[data-c3pg="needs"]')));
127
121
  ok('0 no page error (400 wide)', M.errors.length === 0, M.errors.join(' | '));
128
122
  await M.ctx.close();
129
123
  return finish();
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "The Briefing: today's brief"
4
4
  description: "The Briefing page of the console (/c3.html): the headline cards, Today, Needs you, Portfolio pulse, and what Done, Not yet and Drop do to an item."
5
- timestamp: 2026-10-11
5
+ timestamp: 2026-10-12
6
6
  ---
7
7
 
8
8
  # The Briefing: today's brief
@@ -17,7 +17,7 @@ The Briefing shows only what PMOS already holds. When PMOS holds nothing for a s
17
17
 
18
18
  The cards at the top are the signals that pass the relevance bar. Turn a card over to read its case.
19
19
 
20
- Above the cards, the greeting names the part of the day, for example "Good morning, Wawan". The name is the first word of the git user name on the computer where PMOS runs. When git holds no name, the greeting has none. Five buttons stand for morning, midday, afternoon, evening and night. Press one to preview that part of the day: its line and its cards. Nothing is saved. Press the part that is now, or wait for the clock to move on, and the preview ends.
20
+ Above the cards, the greeting names the part of the day, for example "Good morning, Wawan". The name is the first word of the git user name on the computer where PMOS runs. When git holds no name, the greeting has none. The part of the day follows the clock. There is no button to change it. When the clock moves to a new part, the line under the greeting and the order of the cards change after you stop using the page for a minute.
21
21
 
22
22
  ## Today
23
23
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.137.0",
3
+ "version": "0.138.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.137.0",
9
+ "version": "0.138.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@xterm/addon-fit": "^0.11.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.137.0",
3
+ "version": "0.138.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",
@@ -1,6 +1,6 @@
1
1
  /* pm/briefing-deck.js — the Briefing view (console3 wave C1), built on the console3 mockup's own markup and CSS.
2
- * The mockup (prototype/pmos-console-handoff/mockups/console3.html) is the UI: the stance bar with the day-part switch (.stance,
3
- * the lens follows the clock, no switch), the running line (.tick, .tkt), the card deck (.deck, .fc, .cf, .hero, .dk, .dkd), the flip to the case file (.fb,
2
+ * The mockup (prototype/pmos-console-handoff/mockups/console3.html) is the UI: the stance bar (.stance; the part of the day and its
3
+ * lens follow the clock, with no switch), the running line (.tick, .tkt), the card deck (.deck, .fc, .cf, .hero, .dk, .dkd), the flip to the case file (.fb,
4
4
  * .case, .chgl, .opts, .slt, .cft), the tilt and the flip animation. The styles are pm/console3.css (see pm/console3-lift.md).
5
5
  * This file keeps the data call (GET /api/briefing, the signal engine's cards) and the model (briefing-model.js) and draws
6
6
  * what the engine sent: at most five cards, none invented. A field the engine does not supply is left out.
@@ -12,12 +12,11 @@
12
12
  * Not registered with the registry (Today has no view registry): dest-today.js imports mountBriefing/disposeBriefing. */
13
13
  import { el } from './dom.js';
14
14
  import { createIdleGate, watchIdle, applyDayPart } from './c3-daypart.js';
15
- import { LENSES, TAG_STYLE, PART_STYLE, PARTS, partByKey, partFor, cardView, nextCards, swipeDir, sizeFor, caseModelOf, rawOption } from './briefing-model.js';
15
+ import { TAG_STYLE, PART_STYLE, partByKey, partFor, cardView, nextCards, swipeDir, sizeFor, caseModelOf, rawOption } from './briefing-model.js';
16
16
  import { BX, caseFile, toast } from './c3-brief.js';
17
17
  import { ensureC3Css, c3ic, c3ring, c3Phone } from './pm-work-view.js';
18
18
  import { listenButton } from './shell-readaloud.js';
19
19
  import { onBriefPage } from './c3-brief-data.js';
20
- import { button } from './primitives.js';
21
20
 
22
21
  const NS = 'http://www.w3.org/2000/svg';
23
22
  const roots = new WeakMap(); // host -> state
@@ -336,41 +335,21 @@ async function load(S, lens) {
336
335
  S.data[lens] = null;
337
336
  S.data[lens] = await readLens(lens, S.zoom, S.ctx && S.ctx.scope);
338
337
  if (S.dead) return; // a deck built before its host is attached still draws: it only touches its own root
339
- if (lens === S.lens) draw(S);
340
- else { const old = S.root.querySelector('.stance'); if (old) old.replaceWith(stance(S)); } // another lens arrived: update the switch, keep the open card
338
+ if (lens === S.lens) draw(S); // a lens the clock has since left stays read for later, undrawn
341
339
  }
342
340
 
343
- /* the stance bar (the mockup's stanceBar): the greeting for the part of the day, the lens and its line, the five-part day switch and the read-aloud
344
- * button. The part follows the clock; a tap on the switch previews another part (its lens, its cards) and the preview drops when the clock moves
345
- * to another part. The name is the PM's first name when PMOS holds one (GET /api/brief-page `me`); without one the greeting stands alone. */
341
+ /* the stance bar (the mockup's stanceBar): the icon and greeting for the part of the day, the lens and its line, and the read-aloud button.
342
+ * The part follows the clock and nothing else: there is no switch (the PM's feedback, initiative c3-daypart-auto-only). The name is the
343
+ * PM's first name when PMOS holds one (GET /api/brief-page `me`); without one the greeting stands alone. */
346
344
  function stance(S) {
347
345
  const P = PART_STYLE[S.lens] || PART_STYLE.Plan;
348
- const part = partByKey(S.preview || S.clockPart);
349
- const seg = el('div', { class: 'seg dp', role: 'group', 'aria-label': 'Part of the day', title: 'Follows the clock. Tap to preview another part of the day.' },
350
- ...PARTS.map((x) => {
351
- const b = button({ label: x.label, variant: 'ghost', size: 'sm', onClick: () => setPart(S, x.k), attrs: { 'aria-pressed': String(x.k === part.k), 'data-pg-dp': x.k, title: x.label + ' · ' + x.at + (x.k === S.clockPart ? ' (now)' : ''), 'aria-label': x.label } });
352
- b.replaceChildren(c3ic(x.icon, 'sm')); // the icon alone; the label is the aria-label
353
- return b;
354
- }));
355
- return el('div', { class: 'stance', 'data-bf': 'lens-bar' },
346
+ const part = partByKey(S.clockPart);
347
+ return el('div', { class: 'stance', 'data-bf': 'lens-bar', 'data-part': part.k },
356
348
  el('span', { class: 'ki' }, c3ic(part.icon)),
357
349
  el('div', null, el('b', { title: 'Follows the clock: this is the part of the day it is now.' }, part.greet + (S.me ? ', ' + S.me : '')), el('span', { class: 'dim' }, S.lens + ': ' + P.sub)),
358
- seg,
359
350
  listenButton(() => { const x = S.data[S.lens]; return x && x.ok ? x.cards[S.i] || x.cards[0] : null; })); // the mockup's speaker (data-a=listen) reads the card on top
360
351
  }
361
352
 
362
- /* Preview one part of the day: its lens, its cards. Nothing is saved; the clock's own part comes back by tapping it, or when the clock moves on. */
363
- function setPart(S, k) {
364
- const part = partByKey(k);
365
- S.preview = k === S.clockPart ? null : k;
366
- const lens = part.lens;
367
- const changed = lens !== S.lens;
368
- S.lens = lens; S.i = 0; S.flip = null;
369
- if (changed) load(S, lens);
370
- draw(S);
371
- if (S.ctx.onLens) S.ctx.onLens(lens);
372
- }
373
-
374
353
  /* the mockup's running line (.tick > .tkt, lines 539 to 545): the engine's ticker strings, twice so the marquee loops */
375
354
  function ticker(items) {
376
355
  const one = (hide) => items.map((t) => el('span', { class: 'tki', 'aria-hidden': hide ? 'true' : null }, el('b', { style: 'color:var(--acc)' }, c3ic('bolt', 'sm')), String(t)));
@@ -416,19 +395,18 @@ export function mountBriefing(host, ctx) {
416
395
  host.replaceChildren(root);
417
396
  const clockPart = partFor(new Date()).k;
418
397
  const clock = partByKey(clockPart).lens;
419
- S = { host, root, ctx: ctx || {}, lens: clock, clock, clockPart, preview: null, me: null, zoom: 'week', i: 0, flip: null, data: {}, dead: false };
398
+ S = { host, root, ctx: ctx || {}, lens: clock, clock, clockPart, me: null, zoom: 'week', i: 0, flip: null, data: {}, dead: false };
420
399
  S.stopPhone = c3Phone(root);
421
400
  roots.set(host, S);
422
401
  draw(S);
423
402
  if (!host.closest('[data-daypart]')) applyDayPart(root); // a page without the console3 shell still gets the day part tokens
424
403
  /* The clock moves the lens, but never under the reader: a new part waits for 60 s without pointer or key activity and for every card to be turned back. */
425
404
  const gate = createIdleGate({ current: S.clockPart, part: (ms) => partFor(new Date(ms)).k, busy: () => !!S.flip || !!S.root.querySelector('.fc.back'),
426
- apply: (k) => { if (S.dead) return; const l = partByKey(k).lens; S.clockPart = k; S.preview = null; S.clock = l; S.lens = l; S.i = 0; S.flip = null; load(S, l); draw(S); if (S.ctx.onLens) S.ctx.onLens(l); } });
405
+ apply: (k) => { if (S.dead) return; const l = partByKey(k).lens; S.clockPart = k; S.clock = l; S.lens = l; S.i = 0; S.flip = null; load(S, l); draw(S); if (S.ctx.onLens) S.ctx.onLens(l); } });
427
406
  S.idle = watchIdle(gate);
428
407
  if (!(S.ctx && S.ctx.bare)) onBriefPage((j) => { const me = j && j.ok !== false && j.me ? String(j.me) : null; if (me === S.me || S.dead) return; S.me = me; const old = S.root.querySelector('.stance'); if (old) old.replaceWith(stance(S)); }); // the greeting's name
429
408
  if (S.ctx.onLens) S.ctx.onLens(S.lens); // the page may follow the lens from the start (Reflect: "Carries over", "What I could stop")
430
- // the shown lens first, then the others for their preview line
431
- load(S, S.lens).then(() => Promise.all(LENSES.filter((l) => l !== S.lens).map((l) => load(S, l))));
409
+ load(S, S.lens); // only the clock's lens: the next one is read when the clock moves to it
432
410
  }
433
411
 
434
412
  /* Demo: a tab whose deck follows another control (the Work lens) changes the scope the deck asks for. Real mode never calls it. */
@@ -436,7 +414,7 @@ export function setBriefingScope(host, scope) {
436
414
  const S = roots.get(host);
437
415
  if (!S || S.ctx.scope === scope) return;
438
416
  S.ctx.scope = scope; S.data = {}; S.i = 0; S.flip = null; draw(S);
439
- load(S, S.lens).then(() => Promise.all(LENSES.filter((l) => l !== S.lens).map((l) => load(S, l))));
417
+ load(S, S.lens);
440
418
  }
441
419
 
442
420
  /* Open one card on its case file (the bell's "go to the card", console3.html nopen 2533). True when the card is on this deck. */
@@ -265,7 +265,7 @@ function moveInd() {
265
265
  }
266
266
 
267
267
  /* ── the Briefing tab: two columns, decisions and reads ──
268
- * Left: the stance bar with the day-part switch and the headline deck (briefing-deck.js), then Needs you (c3-brief-needs.js).
268
+ * Left: the stance bar (the part of the day follows the clock) and the headline deck (briefing-deck.js), then Needs you (c3-brief-needs.js).
269
269
  * Right: Today (c3-brief-today.js) and Portfolio pulse (c3-brief-pulse.js). Review lives in Work's Review lens; Handled, What I could stop and
270
270
  * Data you can lean on live in Reports > Drafts (console3-briefing-parity, PM decision 1). The ribbon and the embedded calendar are not here:
271
271
  * the calendar is the Calendar tab. */
@@ -290,7 +290,7 @@ function briefTab(pane) {
290
290
  loadBriefPage();
291
291
  }
292
292
 
293
- /* The day-part switch: Reflect names Needs you "Carries over" (the mockup's vBrief, line 1470). */
293
+ /* The clock's part of the day: Reflect names Needs you "Carries over" (the mockup's vBrief, line 1470). */
294
294
  function lensChanged(l) {
295
295
  setNeedsTitle(S.needsBox, l === 'Reflect');
296
296
  }
@@ -435,7 +435,6 @@
435
435
  .c3 .stance>div:nth-child(2){flex:1;min-width:0;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
436
436
  .c3 .stance b{font-size:var(--fs-3)}
437
437
  .c3 .stance .dim{font-size:var(--fs-3)}
438
- .c3 .dp button{padding:4px 8px}
439
438
  .c3 .lens{display:flex;align-items:center;gap:6px;max-width:100%}
440
439
  .c3 .lens .seg{overflow-x:auto;min-width:0}
441
440
  .c3 .lh{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:10px;align-items:center;padding:2px 0 6px}
@@ -1634,7 +1633,6 @@
1634
1633
  .c3 .psess .c{font:var(--fs-1) var(--mono)}
1635
1634
  /* Briefing as the brief (initiative briefing-brief): one column; Today agenda; own-item rows of Needs you; inline Portfolio pulse */
1636
1635
  /* Briefing, console3-briefing-parity: the day-part switch in the stance bar, the tags, the Today rows */
1637
- .c3 .stance .seg.dp{flex:none}
1638
1636
  .c3 .stance{flex-wrap:wrap}
1639
1637
  .c3 .tag.acc{background:var(--accw);color:var(--acc)}
1640
1638
  .c3 .tag.ok{color:var(--foreground)}