create-pmos 0.54.0 → 0.54.1

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.54.0",
3
+ "version": "0.54.1",
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@65fcbaf
1
+ kernel-source: pmos@4291761
2
2
  assembled: 2026-10-06
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-06T02:54:46Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-06T03:42:06Z"}
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-06T02:54:46Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-06T03:42:06Z"}
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-06T02:54:46Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-06T03:42:06Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -23,6 +23,7 @@ On a desktop the workspace is one frame. [Layout](layout.md) explains each part.
23
23
  |---|---|
24
24
  | What is waiting for you now | Today |
25
25
  | The initiatives of a repository, or of every repository | Initiatives. Choose **All repositories** in Repository ▾ for every repository. |
26
+ | The branches of a repository and the sessions running in each | Repository ▾ → **Branches and sessions**. |
26
27
  | The items of an initiative | Board, or Breakdown in the initiative detail |
27
28
  | Run reports | Reports |
28
29
  | Repositories, Profiles, New sessions (the default CLI and model), Validate consent, Theme | Settings |
@@ -14,6 +14,7 @@ On a desktop screen the workspace is one frame. It has one top bar, the place on
14
14
  The top bar has these parts, from left to right:
15
15
 
16
16
  - **Repository ▾** names the current repository. Press it to choose another repository, or **All repositories** to see the work of every repository at once. All repositories replaces the old Portfolio mode.
17
+ - **Branches and sessions**, at the end of Repository ▾ (or in ⌘K), opens a sheet with every branch of the repository (main first) and how many sessions run in each. Press a branch to see its sessions, open one, end one, or start a session there. **+ branch** makes a branch, and **+ session** starts one with a branch, an agent and a profile. With All repositories, the sheet lists every repository.
17
18
  - **Today, Initiatives, Board and Reports** are the four places. Press one to show it. The Today count shows how many items need you.
18
19
  - **Search or capture ⌘K** opens the command palette. Type to find an initiative, a repository, an open tab or a command.
19
20
  - **Sync** shows only when the current repository is not in sync with its remote. Press it to fetch, bring in the work of the other machine, record your changes and push. If the repository has not fetched in the last 10 minutes, Sync also shows, because a push from another machine is not visible until a fetch. When the repository fetched recently and is in sync, Sync is not shown. If Sync stops, the message names the step that stopped.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.54.0",
3
+ "version": "0.54.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.54.0",
3
+ "version": "0.54.1",
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",
@@ -42,6 +42,7 @@ import { createDockRail } from './dock.js';
42
42
  import { SEL, ensureComponentsCss, iconButton, button, menu, toast } from './primitives.js';
43
43
  import { ensureSprite } from './icons.js';
44
44
  import { COPY as FC } from './frame-copy.js';
45
+ import { registerCommand } from './registry.js';
45
46
 
46
47
  /* The LEGACY layout is the three-column shell of column-layout: repositories with the list under them, the detail, the tabs, and
47
48
  * a list that a mode (skills, memory …) replaces. A phone still draws it until Run 4 of workspace-cockpit-nav, and `?layout=legacy`
@@ -482,9 +483,20 @@ function repoMenu(anchor) {
482
483
  const items = tuples.map((t) => ({ label: t[0], icon: t[0] === cur ? 'check' : null, onSelect: () => chooseRepo(t[0]) }));
483
484
  if (items.length) items.push({ sep: true });
484
485
  items.push({ label: FC.repo.all, icon: fr.scope === 'all' ? 'check' : null, onSelect: chooseAll });
486
+ if (tuples.length) items.push({ sep: true }, { label: FC.repo.branches, onSelect: openBranchesSheet });
485
487
  menu({ anchor, items, ariaLabel: FC.repo.menu });
486
488
  }
487
489
 
490
+ /* Branches and sessions (0.54.1): the legacy panel 1's working trees, which the frame never drew. The current repository,
491
+ * or every repository when the scope is All. */
492
+ function openBranchesSheet() {
493
+ const tuples = mods.repos && typeof mods.repos.repoTuples === 'function' ? mods.repos.repoTuples() : [];
494
+ const cur = fr.scope === 'all' ? null : activeRepo();
495
+ const repos = cur ? [cur] : tuples.map((t) => t[0]);
496
+ import('./branches-sheet.js').then((m) => m.openBranches(repos)).catch((e) => console.error('[pm] could not open the branches:', e));
497
+ }
498
+ if (FRAME) registerCommand({ id: 'branches-open', label: FC.repo.branches, hint: FC.branches.hint, cli: 'git worktree list', run: () => openBranchesSheet() });
499
+
488
500
  /* Sync: the bar shows it only while the current repository is not in sync. The reading is local git (GET
489
501
  * /api/sync/status), re-read a minute after the last one and at once after a Sync. */
490
502
  const syncSeen = new Map(); // repo -> { at, st, pending }
@@ -681,7 +693,7 @@ function frameKey(e) {
681
693
 
682
694
  /* What the suites and the phone chrome reach the frame by. */
683
695
  const frameApi = {
684
- on: true, go, toggleDock, foldDock, openDock, toggleFocus, dockWidth, chooseRepo, chooseAll, openPalette, repoMenu, closeDetail, sync: runSync,
696
+ on: true, go, toggleDock, foldDock, openDock, toggleFocus, dockWidth, chooseRepo, chooseAll, openPalette, repoMenu, openBranchesSheet, closeDetail, sync: runSync,
685
697
  get unsynced() { return !!fr.unsynced; },
686
698
  get dest() { return fr.dest; }, get scope() { return fr.scope; }, get dockOpen() { return dockOpen(); }, get dockMax() { return !!fr.dockMax; },
687
699
  get detailOpen() { return !!state.col2; }, get syncing() { return fr.syncing; }, get needs() { return fr.needs || 0; },
@@ -0,0 +1,56 @@
1
+ /* pm/branches-sheet.js — the working trees of a repository and the sessions in each, in the frame (0.54.1).
2
+ *
3
+ * The legacy panel 1 listed every tree (main first) with its live sessions, `+ branch` and `+ session` (panel-trees.js).
4
+ * The frame never drew panel 1, so from 0.53.0 the branches and their sessions had no place. This sheet draws the same
5
+ * blocks, unchanged: one repository, or every repository when the scope is All. It repaints on every state change while
6
+ * it is open, so a session that starts or ends elsewhere (a terminal, the CLI) shows here within one poll.
7
+ *
8
+ * openBranches(repos) → the sheet. `repos` is the list of repository names to show, in order.
9
+ */
10
+
11
+ import { el, setChildren } from './dom.js';
12
+ import { sheet } from './primitives.js';
13
+ import { state, subscribe } from './state.js';
14
+ import { treesOf } from './panel-repos.js';
15
+ import { treesBlock, branchForm, treeNoteFor, sessionsIn } from './panel-trees.js';
16
+ import { refreshTrees } from './data.js';
17
+ import { COPY } from './frame-copy.js';
18
+
19
+ const live = (s) => s && s.state !== 'exited' && s.shown !== 'exited';
20
+
21
+ function sub(repos) {
22
+ let trees = 0; let sessions = 0;
23
+ for (const r of repos) for (const t of treesOf(r)) { trees++; sessions += sessionsIn(t.ws).filter(live).length; }
24
+ return COPY.branches.sub(trees, sessions);
25
+ }
26
+
27
+ function body(repos) {
28
+ if (!repos.length) return [el('p', { class: 'fr-branches__empty' }, COPY.branches.none)];
29
+ return repos.map((r) => {
30
+ const trees = treesOf(r);
31
+ return el('section', { class: 'fr-branches__repo', 'data-fr-branches': r },
32
+ repos.length > 1 ? el('h3', { class: 'fr-branches__name' }, r) : null,
33
+ branchForm(r),
34
+ trees.length ? treesBlock(r, trees, true) : el('p', { class: 'fr-branches__empty' }, COPY.branches.noTrees),
35
+ treeNoteFor(r));
36
+ });
37
+ }
38
+
39
+ export function openBranches(repos) {
40
+ const list = (repos || []).filter(Boolean);
41
+ const s = sheet({ title: COPY.branches.title, sub: sub(list), body: body(list), attrs: { 'data-fr': 'branches' }, onClose: () => stop() });
42
+ // The trees can change behind the page (a branch made in a terminal): read them once more on open.
43
+ try { Promise.resolve(refreshTrees()).catch(() => {}); } catch { /* no data layer */ }
44
+ let last = null;
45
+ const stop = subscribe(() => {
46
+ if (!s.open) return;
47
+ // Repaint only when something the sheet shows changed, so an input the PM types in keeps its node between polls.
48
+ const key = JSON.stringify([state.branchForm && { ...state.branchForm, name: null, from: null }, state.treeNote, state.treeSel, state.treeConfirm,
49
+ list.map((r) => treesOf(r).map((t) => [t.ws, t.branch, sessionsIn(t.ws).map((x) => [x.id, x.state, x.shown, x.name, x.initiative])]))]);
50
+ if (key === last) return;
51
+ last = key;
52
+ s.setHead(COPY.branches.title, sub(list));
53
+ setChildren(s.body, body(list));
54
+ });
55
+ return s;
56
+ }
@@ -11,6 +11,14 @@ export const COPY = {
11
11
  none: 'No repository',
12
12
  menu: 'Choose a repository',
13
13
  open: (name) => 'Repository: ' + name + '. Choose a repository.',
14
+ branches: 'Branches and sessions',
15
+ },
16
+ branches: {
17
+ title: 'Branches and sessions',
18
+ sub: (trees, live) => trees + (trees === 1 ? ' branch' : ' branches') + ' · ' + live + ' live ' + (live === 1 ? 'session' : 'sessions'),
19
+ none: 'Add a repository to see its branches.',
20
+ noTrees: 'This repository has no working tree the workspace can read.',
21
+ hint: 'Every branch and the sessions running in it',
14
22
  },
15
23
  nav: {
16
24
  label: 'Destinations',