create-pmos 0.175.0 → 0.176.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.175.0",
3
+ "version": "0.176.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@128e902
1
+ kernel-source: pmos@ad91884
2
2
  assembled: 2026-10-13
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-13T01:08:07Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-13T01:16:54Z"}
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-13T01:08:07Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-13T01:16:54Z"}
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-13T01:08:07Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-13T01:16:54Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -177,6 +177,8 @@ function startShell(name) {
177
177
  /* ── D: End asks first, then ends ── */
178
178
  await page.click('[data-c3pg="agent-button"]');
179
179
  ok('D0 the panel opens again', await waitFor(page, (s) => !!document.querySelector(s), sel));
180
+ ok('D0b it opens on the session opened last: its row is open and marked', await waitFor(page, (i) => { const li = document.querySelector(`[data-c3t="mine"] [data-run="${i}"]`); const end = document.querySelector(`[data-end-session="${i}"]`); return !!li && li.hasAttribute('data-last-open') && !!end && end.offsetParent !== null; }, id)
181
+ && await page.evaluate((i) => localStorage.getItem('pmos.workspace.c3.last-session') === i, id));
180
182
  if (!(await page.isVisible(`[data-end-session="${id}"]`).catch(() => false))) await page.click(sel + ' .nb');
181
183
  await page.click(`[data-end-session="${id}"]`);
182
184
  ok('D1 End asks first', await waitFor(page, (i) => !!document.querySelector(`[data-end-confirm="${i}"]`), id));
@@ -9,6 +9,8 @@ timestamp: 2026-10-13
9
9
 
10
10
  Press the **Sessions** button in the console3 header to open the panel. It is the bolt icon with no label. Point at it to see its name. When a session needs you, a count shows on it. It shows your sessions in four groups: **On a card**, **Started by me**, **Past (7 days)** and **Automatic**.
11
11
 
12
+ The panel opens on the session that you opened last. Its row is open, so you can read the conversation and send a message without searching for it. A session counts as opened when you open its row or its terminal.
13
+
12
14
  ## The dock
13
15
 
14
16
  The dock is folded when you first open the console. To open it, press Ctrl J (⌘J on a Mac), or use **Open the dock** in the **More** menu. The browser keeps your choice: when you leave the dock open, it opens on the Briefing next time. On the other tabs it is folded away, and no rail of buttons is left at the right edge.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.175.0",
3
+ "version": "0.176.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.175.0",
9
+ "version": "0.176.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.175.0",
3
+ "version": "0.176.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",
@@ -19,6 +19,10 @@ const store = {
19
19
  export const SIZE_KEY = 'pmos.workspace.c3.term-size';
20
20
  export const PAD_KEY = 'pmos.workspace.c3.term-pad';
21
21
  export const PAD_H_KEY = 'pmos.workspace.c3.term-pad-h';
22
+ /* the session the PM opened last (its terminal here, or its row in the Sessions panel): the panel opens on it */
23
+ export const LAST_SESSION_KEY = 'pmos.workspace.c3.last-session';
24
+ export const rememberSession = (id) => { if (id) store.set(LAST_SESSION_KEY, String(id)); };
25
+ export const lastSession = () => store.get(LAST_SESSION_KEY) || null;
22
26
  const PAD_ROWS = 4; // the default height
23
27
  /** The pad's height in rows: at least 2, and at most what leaves the terminal its room in a column `room` px high with `lh` px rows. Pure, for Node. */
24
28
  export const clampPad = (rows, room, lh) => Math.max(2, Math.min(Math.round(rows), Math.max(2, Math.floor((room - 200) / (lh || 18)))));
@@ -122,6 +126,7 @@ function makePad(id, term, tab) {
122
126
 
123
127
  export async function openSessionTerm({ id, name } = {}) {
124
128
  if (!id) return null;
129
+ rememberSession(id);
125
130
  if (!name) { const r = await pmGet('/api/sessions').catch(() => null); const x = r && Array.isArray(r.sessions) ? r.sessions.find((y) => y.id === id) : null; name = x ? x.name : id; }
126
131
  const [ok, term] = await Promise.all([loadVendor(), import('./tab-term.js').catch(() => null)]);
127
132
  if (!ok || !term) { toast({ text: 'The terminal could not be loaded on this page.', tone: 'error' }); return null; }
@@ -16,6 +16,7 @@ import { toast } from './c3-toast.js';
16
16
  import { pmPost } from './http.js';
17
17
  import { button } from './primitives.js';
18
18
  import { chatFeed } from './c3-session-chat.js';
19
+ import { rememberSession, lastSession } from './c3-session-term.js';
19
20
 
20
21
  const live = new WeakMap();
21
22
  const DOT = { working: 'w', queued: 'w', asking: 'n', permission: 'n', attention: 'n', not_started: 'n', failed: 'b', quiet: '', paused: 'n', done: '' };
@@ -56,7 +57,7 @@ function row(st, s, card, parts) {
56
57
  li.style.gridTemplateColumns = 'auto minmax(0,1fr) auto';
57
58
  xp.style.gridColumn = '1 / -1';
58
59
  const key = 'r-' + s.id;
59
- attachExpand(li, xp, { key, initial: st.open.has(key), onToggle: (on) => { if (on) st.open.add(key); else st.open.delete(key); } });
60
+ attachExpand(li, xp, { key, initial: st.open.has(key), onToggle: (on) => { if (on) { st.open.add(key); rememberSession(s.id); } else st.open.delete(key); } });
60
61
  return li;
61
62
  }
62
63
  const dim = (t) => el('span', { class: 'dim mono', style: 'font-size:var(--fs-2)' }, t);
@@ -180,7 +181,9 @@ export function mountSessions(host, ctx = {}) {
180
181
  disposeSessions(host);
181
182
  if (ctx && ctx.FIXTURE) return;
182
183
  ensureC3Css();
183
- const st = { src: source(), data: null, showAuto: false, last: '', gone: false, timer: null, refresh: null, redraw: null, open: new Set(), confirm: null,
184
+ // the panel opens on the session the PM opened last: its row starts open, and the first draw brings it into view
185
+ const lastId = lastSession();
186
+ const st = { src: source(), data: null, showAuto: false, last: '', gone: false, timer: null, refresh: null, redraw: null, open: new Set(lastId ? ['r-' + lastId] : []), confirm: null, reveal: lastId,
184
187
  openSession: (id) => { const r = st.data && st.data.groups ? [].concat(...Object.values(st.data.groups).filter(Array.isArray)).find((x) => x.id === id) : null;
185
188
  import('./c3-session-term.js').then((m) => m.openSessionTerm({ id, name: r ? r.name : id })); } };
186
189
  if (st.src.demo) st.openSession = () => toast('In the real workspace this opens the CLI session.');
@@ -194,6 +197,11 @@ export function mountSessions(host, ctx = {}) {
194
197
  st.last = key; st.data = r;
195
198
  if (r.ok && ctx.onNeeds) ctx.onNeeds(needsYou(r));
196
199
  if (!busy()) draw(host, st); else st.last = '';
200
+ if (st.reveal && r.ok) {
201
+ const li = host.querySelector(`[data-run="${CSS.escape(st.reveal)}"]`);
202
+ st.reveal = null;
203
+ if (li) { li.setAttribute('data-last-open', ''); requestAnimationFrame(() => li.scrollIntoView({ block: 'nearest' })); }
204
+ }
197
205
  };
198
206
  st.timer = setInterval(() => { if (!busy()) st.refresh(); }, 5000);
199
207
  if (st.src.subscribe) st.unsub = st.src.subscribe(() => st.refresh());