create-pmos 0.170.0 → 0.172.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.170.0",
3
+ "version": "0.172.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@b5055b4
1
+ kernel-source: pmos@90450cc
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-12T17:05:32Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T23:07:20Z"}
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-12T17:05:32Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T23:07:20Z"}
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-12T17:05:32Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-12T23:07:20Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -5,7 +5,7 @@
5
5
  * Loads /c3.html against a real server with its own state directory and checks: the gear, the More menu item and
6
6
  * ?tab=settings open Settings; every section draws; search finds a setting across sections; a change to a store setting
7
7
  * is saved through POST /api/settings and read back; the theme switch sets the page theme; the start page and the
8
- * time-of-day switches take effect on the next load; and the page throws no error.
8
+ * time-of-day switches take effect on the next load; Set up Laya opens its terminal; and the page throws no error.
9
9
  */
10
10
  const path = require('path');
11
11
  const { spawn } = require('child_process');
@@ -134,6 +134,16 @@ async function waitFor(page, fn, arg, ms = 8000) {
134
134
  await page.keyboard.type('Settings');
135
135
  ok('G1 the palette lists Settings', await waitFor(page, () => [...document.querySelectorAll('[role="option"], .pal li, .pal button, [data-pal-item]')].some((x) => /Settings/.test(x.textContent)), null, 3000));
136
136
 
137
+ /* ── I: Set up Laya opens its terminal on the page, not only on the server (jev-local-fallback R9) ── */
138
+ await page.goto(BASE + '/c3.html?tab=settings');
139
+ await waitFor(page, () => !!document.querySelector('[data-c3set-nav] [data-c3set-sec="privacy"]'));
140
+ await page.click('[data-c3set-nav] [data-c3set-sec="privacy"]');
141
+ ok('I1 Privacy shows the Set up Laya button', await waitFor(page, () => !!document.querySelector('[data-c3set-laya-setup]')));
142
+ await page.click('[data-c3set-laya-setup]');
143
+ ok('I2 the press opens the Set up Laya terminal', await waitFor(page, () => !!document.querySelector('[data-c3-session-term]'), null, 10000));
144
+ ok('I3 the row says what to do next', await waitFor(page, () => /Press Enter there/.test((document.querySelector('[data-c3set-row="typesafe.local"]') || {}).textContent || '')));
145
+ await page.keyboard.press('Escape').catch(() => {});
146
+
137
147
  ok('H1 the page throws no error', errors.length === 0, errors.slice(0, 3).join(' | '));
138
148
  finish();
139
149
  })();
@@ -13,7 +13,7 @@ The Calendar tab of the console page (`/`) shows time. It shows what happens and
13
13
 
14
14
  The switch at the start of the bar has two parts. **Calendar** shows the grid. **Notes** shows your notes.
15
15
 
16
- In **Notes**, the list is at the left, under the heading **Notes**. The notes are in groups by what they are about: **Portfolio** first, then one group for each board, in the order of the portfolio. **Not linked** is the last group. A note linked to an initiative from an earlier version, with no board, is in **Initiatives**. The number shows how many notes the list shows. Type in **Search notes** to keep only the notes whose title, board, initiative or summary has the words. A row shows when the note was made and its length. In a board group, a row shows its initiative, or **board** when the note is about the whole board. A row also shows **recording** or **paused** while the note is held, **no meeting** when the note has no meeting, and a warning mark when a statement differs from a file.
16
+ In **Notes**, the list is at the left, under the heading **Notes**. The notes are in groups by what they are about: **Portfolio** first, then one group for each board, in the order of the portfolio. **Not linked** is the last group. A note linked to an initiative from an earlier version, with no board, is in **Initiatives**. In each group, the newest meeting is first. A note with no meeting is placed by when its recording started, or else by when it was made. The number shows how many notes the list shows. Type in **Search notes** to keep only the notes whose title, board, initiative or summary has the words. A row shows when the note was made and its length. In a board group, a row shows its initiative, or **board** when the note is about the whole board. A row also shows **recording** or **paused** while the note is held, **no meeting** when the note has no meeting, and a warning mark when a statement differs from a file.
17
17
 
18
18
  Press a row to open the note at the right. The note has three stages. Press **Before**, **During** or **After** to change the stage.
19
19
 
@@ -112,7 +112,7 @@ The workspace reads the TypeSafe key only on this machine. After you save the ke
112
112
  If you have no TypeSafe key, a model on your computer can answer the same questions. Two models are supported. Both use the same interface as Jev.
113
113
 
114
114
  - **Winnow**: in a `winnow-inference` folder, run `python3 scripts/serve.py`. It uses port 8091. Winnow-12B needs about 16 GB of memory.
115
- - **Laya**: in Settings, press **Set up Laya**. A terminal named Set up Laya opens with the commands typed in. Read them and press Enter. The first time, they install Laya into the PMOS data folder. Then Laya starts and uses port 8000. Laya is small and runs on a laptop. Laya stops when you close that terminal or restart the computer. Press **Set up Laya** again to start it.
115
+ - **Laya**: in Settings, press **Set up Laya**. A terminal named Set up Laya opens over the Settings page, with the commands typed in. If you close it, open it again from the session list. Read them and press Enter. The first time, they install Laya into the PMOS data folder. Then Laya starts and uses port 8000. Laya is small and runs on a laptop. Laya stops when you close that terminal or restart the computer. Press **Set up Laya** again to start it.
116
116
 
117
117
  1. Start the model.
118
118
  2. Open Settings, then **Privacy and data**. Under **Local model if Jev is missing**, press **Winnow** or **Laya**.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.170.0",
3
+ "version": "0.172.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.170.0",
9
+ "version": "0.172.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.170.0",
3
+ "version": "0.172.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",
@@ -152,7 +152,8 @@ function listCard(s) {
152
152
  }
153
153
 
154
154
  /* the list's groups: Portfolio, each board in the portfolio's order (a board it does not list goes after them by name), an
155
- * initiative linked before boards were (no board on the note) under "Initiatives", then "Not linked" */
155
+ * initiative linked before boards were (no board on the note) under "Initiatives", then "Not linked"; in a group, the newest
156
+ * meeting (or recording) first */
156
157
  function scopeGroups(s, rows) {
157
158
  const order = new Map((s.boards || []).map((b, i) => [boardKey(b), i]));
158
159
  const known = new Map((s.boards || []).map((b) => [boardKey(b), b.name || b.id]));
@@ -162,6 +163,8 @@ function scopeGroups(s, rows) {
162
163
  if (!g.has(k)) g.set(k, { key: k, label: k === '@portfolio' ? 'Portfolio' : k === '@initiative' ? 'Initiatives' : !k ? 'Not linked' : known.get(k) || boardName(r.board), rows: [] });
163
164
  g.get(k).rows.push(r);
164
165
  }
166
+ // the server lists notes by when they were last edited; a group reads newest meeting first
167
+ for (const x of g.values()) x.rows.sort((a, b) => (Date.parse(startOf(b)) || 0) - (Date.parse(startOf(a)) || 0));
165
168
  const rank = (x) => (x.key === '@portfolio' ? [0, 0] : x.key === '@initiative' ? [3, 0] : !x.key ? [4, 0] : order.has(x.key) ? [1, order.get(x.key)] : [2, 0]);
166
169
  return [...g.values()].sort((a, b) => { const p = rank(a); const q = rank(b); return p[0] - q[0] || p[1] - q[1] || a.label.localeCompare(b.label); });
167
170
  }
@@ -624,6 +624,8 @@ export function mountSettings(host, ctx = {}) {
624
624
  if (r && r.ok) {
625
625
  M.typesafe = r.key; delete M.err['typesafe.local'];
626
626
  M.localTest = { ok: !!r.started, text: r.started ? 'A terminal named Set up Laya opened with the commands typed in. Press Enter there, wait until Laya says it is running, then press Test.' : 'No terminal opened (' + (r.reason || 'unknown') + '). Run this in a terminal: ' + r.command };
627
+ // the server only starts the session; the page must open it, or nothing appears to happen
628
+ if (r.started && r.session) import('./c3-session-term.js').then((m) => m.openSessionTerm({ id: r.session, name: 'Set up Laya' })).catch(() => {});
627
629
  } else { M.localTest = null; M.err['typesafe.local'] = (r && r.error) || 'Not started.'; }
628
630
  draw();
629
631
  };