create-pmos 0.499.0 → 0.500.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.499.0",
3
+ "version": "0.500.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": {
@@ -32,6 +32,19 @@
32
32
  "audit"
33
33
  ],
34
34
  "pmosChanges": [
35
+ {
36
+ "v": "0.500.0",
37
+ "at": "2026-11-03T04:17:03.191Z",
38
+ "f": 3,
39
+ "prs": [
40
+ {
41
+ "n": 1183,
42
+ "t": "Delete a captured meeting-note point from its edit card",
43
+ "s": "Delete a captured meeting-note point from its edit card",
44
+ "k": "new"
45
+ }
46
+ ]
47
+ },
35
48
  {
36
49
  "v": "0.499.0",
37
50
  "at": "2026-11-03T03:25:28.533Z",
@@ -409,19 +422,6 @@
409
422
  "s": "Batch 22: feedback fixes (held for one merge)"
410
423
  }
411
424
  ]
412
- },
413
- {
414
- "v": "0.480.0",
415
- "at": "2026-11-01T11:08:09.778Z",
416
- "f": 3,
417
- "prs": [
418
- {
419
- "n": 1139,
420
- "t": "Set up a custom report from chat in one press (held)",
421
- "s": "Set up a custom report from chat in one press (held)",
422
- "k": "fix"
423
- }
424
- ]
425
425
  }
426
426
  ]
427
427
  }
@@ -1,3 +1,3 @@
1
- kernel-source: pmos@02cdbcfc
1
+ kernel-source: pmos@74d94d5f
2
2
  assembled: 2026-11-03
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-11-03T03:25:24Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T04:17:00Z"}
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-11-03T03:25:24Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T04:17:00Z"}
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-11-03T03:25:24Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-03T04:17:00Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -1,4 +1,17 @@
1
1
  [
2
+ {
3
+ "v": "0.500.0",
4
+ "at": "2026-11-03T04:17:03.191Z",
5
+ "f": 3,
6
+ "prs": [
7
+ {
8
+ "n": 1183,
9
+ "t": "Delete a captured meeting-note point from its edit card",
10
+ "s": "Delete a captured meeting-note point from its edit card",
11
+ "k": "new"
12
+ }
13
+ ]
14
+ },
2
15
  {
3
16
  "v": "0.499.0",
4
17
  "at": "2026-11-03T03:25:28.533Z",
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "Guide: notes"
4
4
  description: "How to take notes in a meeting: one note top to bottom, typed notes as timed lines, key points written each minute and labelled by Jev, delete a note; final notes written after Stop from the whole recording, with speakers and a quote for each item, decisions with their why and who, next steps with an open question, a discussion paragraph, and Wispr Flow's notes merged in and fetched by hand when the fetch fails; listen to your microphone and the meeting on this machine, see decisions, actions and questions caught as they are said, check them against the repository for conflicts, capture highlights during the meeting, create tasks from next steps, correct and tag lines, see what changed in your notes, replay the meeting, see screenshots of the shared screen beside the transcript, link a note to its meeting and its initiative, and get a summary."
5
- timestamp: 2026-11-02
5
+ timestamp: 2026-11-03
6
6
  ---
7
7
 
8
8
  # Guide: notes
@@ -238,6 +238,12 @@ Press **Replay** beside the player (in Calendar › Notes, or on the meeting's c
238
238
 
239
239
  The page reads only records on this machine: the note, the file Focus kept for the meeting, and the screen shots.
240
240
 
241
+ ### Fix or delete a key point
242
+
243
+ In a meeting's Viewer, press a decision, a question or an action to open its edit card. Change the kind or the words, then press **Save**. PMOS remembers what you meant for the next notes, unless you press **Only fix this one**.
244
+
245
+ To delete the point, press the trash on the edit card. The point leaves at once, with no question first. **Undo** shows for 8 seconds and puts it back. A deleted point stays deleted after a reload. It is not in **Left out** and it is not counted. A delete does not teach PMOS anything, and nothing is sent outside PMOS.
246
+
241
247
  The replay page was part of the console, which is deleted. A replay link (for example `/c3.html?replay=n-abcd-1234`) now opens Home.
242
248
 
243
249
  ### Clean up the replay sound
@@ -2,8 +2,9 @@
2
2
  /* meeting-points.js — what the PM said about the key points of a meeting's Replay (initiative premium-uncovered-features, area meetings;
3
3
  * MtReplay.dc.html: the bulk bar's Confirm and Not right). The Replay keeps the points that were agreed, owned or left open; the PM ticks
4
4
  * some and confirms them, or marks them not right. A point marked not right leaves the kept list and goes to "Left out".
5
+ * A point the PM deleted (the trash on its edit card, batch 25 item 10) is gone: not kept, not Left out, not counted. Undo is verdict null.
5
6
  *
6
- * pointsOf(dir, note) → { [pointId]: 'confirmed' | 'wrong' } a later line wins; verdict null forgets the point
7
+ * pointsOf(dir, note) → { [pointId]: 'confirmed' | 'wrong' | 'deleted' } a later line wins; verdict null forgets the point
7
8
  * setPoints(dir, { note, ids, verdict }) → { ok, points } | { ok: false, status, error }
8
9
  *
9
10
  * A point's id is the id lib/meeting-replay.js gives it (d1, a2, q1). One line of <runtime>/meeting-points.jsonl per press, file mode,
@@ -14,7 +15,7 @@ const path = require('path');
14
15
  const FILE = 'meeting-points.jsonl';
15
16
  const NOTE_ID = /^[A-Za-z0-9_-]{1,80}$/;
16
17
  const POINT_ID = /^[A-Za-z0-9_-]{1,40}$/;
17
- const VERDICTS = ['confirmed', 'wrong'];
18
+ const VERDICTS = ['confirmed', 'wrong', 'deleted'];
18
19
 
19
20
  function readLines(file) {
20
21
  let text = '';
@@ -43,7 +44,7 @@ function setPoints(dir, body = {}) {
43
44
  const ids = Array.isArray(body.ids) ? [...new Set(body.ids.map(String))] : [];
44
45
  if (!ids.length || ids.length > 200 || !ids.every((x) => POINT_ID.test(x))) return { ok: false, status: 400, error: 'ids are the key points to mark, 1 to 200 of them' };
45
46
  const verdict = body.verdict == null ? null : String(body.verdict);
46
- if (verdict !== null && !VERDICTS.includes(verdict)) return { ok: false, status: 400, error: 'verdict is confirmed, wrong or null' };
47
+ if (verdict !== null && !VERDICTS.includes(verdict)) return { ok: false, status: 400, error: 'verdict is confirmed, wrong, deleted or null' };
47
48
  fs.mkdirSync(dir, { recursive: true });
48
49
  fs.appendFileSync(path.join(dir, FILE), JSON.stringify({ v: 1, note, ids, verdict, at: new Date().toISOString() }) + '\n');
49
50
  return { ok: true, points: pointsOf(dir, note) };
@@ -186,7 +186,7 @@ function reportSchedules(RN, range) {
186
186
  }
187
187
 
188
188
  /** The decisions and next steps of a note, each with confirmed: true when the PM confirmed or corrected it, else false. A corrected
189
- * point carries the PM's words. A point marked not right is left out. */
189
+ * point carries the PM's words. A point marked not right, or deleted, is left out. */
190
190
  function confirmedPoints(runtimeDir, noteId, decisions, actions) {
191
191
  let pts = {}, eds = {};
192
192
  try { pts = require('./meeting-points.js').pointsOf(runtimeDir, noteId); } catch { pts = {}; }
@@ -194,7 +194,7 @@ function confirmedPoints(runtimeDir, noteId, decisions, actions) {
194
194
  const out = { decisions: [], actions: [] };
195
195
  const put = (list, k) => (list || []).forEach((x, i) => {
196
196
  const id = k[0] + (i + 1), e = eds[id];
197
- if (pts[id] === 'wrong') return;
197
+ if (pts[id] === 'wrong' || pts[id] === 'deleted') return;
198
198
  const kind = e && ['decision', 'action'].includes(e.kind) ? e.kind : e ? null : k;
199
199
  if (!kind) return; // corrected into a question: not a decision or a step any more
200
200
  const row = { text: e ? e.text : x && x.text, confirmed: !!e || pts[id] === 'confirmed' };
@@ -2,8 +2,8 @@
2
2
  /* routes-meeting-points.js — the Replay's Confirm and Not right (initiative premium-uncovered-features, area meetings; lib/route-modules.js).
3
3
  * The data is kept by lib/meeting-points.js.
4
4
  *
5
- * GET /api/meeting-points?note=<id> → { ok, points: { [pointId]: 'confirmed' | 'wrong' } }
6
- * POST /api/meeting-points { note, ids: [pointId], verdict } → { ok, points } verdict confirmed | wrong | null (Undo)
5
+ * GET /api/meeting-points?note=<id> → { ok, points: { [pointId]: 'confirmed' | 'wrong' | 'deleted' } }
6
+ * POST /api/meeting-points { note, ids: [pointId], verdict } → { ok, points } verdict confirmed | wrong | deleted | null (Undo)
7
7
  * The GET also answers { edits, lessons }: the PM's corrections to the note's points and what PMOS learned (lib/meeting-learn.js).
8
8
  * POST /api/meeting-points/edit { note, id, kind, text, orig: { kind, text }, learn, items: [{ id, text }] } → { ok, edits, lesson, check }
9
9
  * a corrected point (XvAReplayEdit). learn false is "Only fix this one". check: the other points of the note that use the learned words.
@@ -58,7 +58,7 @@ function runOf(run) {
58
58
  failed: T.filter((t) => t.status === 'failed').slice(0, 3).map((t) => ({ id: t.id, title: clip(t.title, 200), error: clip(t.error, 200) })) };
59
59
  }
60
60
 
61
- /** deps: { events, items, run, notes: [note with final_notes], adapter, points: (noteId) → { [pointId]: 'confirmed' | 'wrong' }, seen: Set of seen ids }
61
+ /** deps: { events, items, run, notes: [note with final_notes], adapter, points: (noteId) → { [pointId]: 'confirmed' | 'wrong' | 'deleted' }, seen: Set of seen ids }
62
62
  * notes are today's non-private notes, read in full. A decision's point id is the Replay's (lib/meeting-replay.js): d1, d2, … in caughtOf order. */
63
63
  function build(query, deps = {}) {
64
64
  const q = query || {};
@@ -76,7 +76,7 @@ function build(query, deps = {}) {
76
76
  caughtOf(n).decision.forEach((x, i) => {
77
77
  const v = pts['d' + (i + 1)];
78
78
  if (v === 'confirmed') decisions.push({ kind: 'decision', text: clip(x.text, 200), sub: clip(n.title || (n.meeting && n.meeting.title) || 'A meeting', 80) });
79
- else if (v !== 'wrong') toConfirm += 1;
79
+ else if (v !== 'wrong' && v !== 'deleted') toConfirm += 1;
80
80
  });
81
81
  }
82
82
  const done = items.filter((i) => i && i.done && i.done_at && localDate(new Date(i.done_at)) === today);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.499.0",
3
+ "version": "0.500.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.499.0",
9
+ "version": "0.500.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@anthropic-ai/sdk": "^1.3.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.499.0",
3
+ "version": "0.500.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",
@@ -225,6 +225,7 @@
225
225
  .vzp-learn b:empty { display: none; }
226
226
  .vzp-ef { display: flex; align-items: center; gap: 10px; }
227
227
  .vzp-sp { flex: 1; }
228
+ .vzp-del:hover { color: var(--cz-ink); }
228
229
  .vzp-gbtn { min-height: 34px; padding: 0 12px !important; border-radius: 999px; font-size: var(--fs-3); font-weight: 700; }
229
230
 
230
231
  /* one Replay at a time: the phone's below 640px, else the desk's */
@@ -63,7 +63,8 @@ export function replayView(rep, { n = null, points = {}, edits = {}, lessons = [
63
63
  const raw = Array.isArray(rep.raw) ? rep.raw : [];
64
64
  const rawOf = (k) => raw.find((x) => x && (x.id === k.id || (x.k === k.k && x.text === k.text))) || k;
65
65
  const lineAt = (t) => { if (t == null) return null; let best = null; for (const l of rep.lines) if (best === null || Math.abs(l.t - t) < Math.abs(best.t - t)) best = l; return best && Math.abs(best.t - t) <= NEAR ? best : null; };
66
- const all = rep.keys.map((k) => {
66
+ /* a point the PM deleted is gone: not kept, not Left out, not counted (its line still keeps the remark it was caught from out of Left out) */
67
+ const all = rep.keys.filter((k) => points[k.id] !== 'deleted').map((k) => {
67
68
  const r = rawOf(k), ed = edits[k.id] || null, state = ed ? '' : r.state || k.state || '', owner = clip(r.owner || k.owner, 40), line = lineAt(k.t);
68
69
  const quote = line ? clip(line.who, 30) + ': “' + clip(line.text, 90) + '”' : '';
69
70
  const kind0 = k.k === 'action' ? 'action' : k.k === 'question' ? 'question' : 'decision';
@@ -109,7 +110,7 @@ export function replayView(rep, { n = null, points = {}, edits = {}, lessons = [
109
110
  }
110
111
 
111
112
  /* ── html (pure) ── */
112
- const P = { play: 'M8 5v14l11-7z', pause: 'M8 5h3v14H8zM13 5h3v14h-3z', big: 'M14 4h6v6M10 20H4v-6M20 4l-7 7M4 20l7-7', chev: 'M10 7l5 5-5 5', chk: 'M5 12l5 5 9-10', task: 'M5 12l4 4L19 6', x: 'M6 6l12 12M18 6L6 18' };
113
+ const P = { play: 'M8 5v14l11-7z', pause: 'M8 5h3v14H8zM13 5h3v14h-3z', big: 'M14 4h6v6M10 20H4v-6M20 4l-7 7M4 20l7-7', chev: 'M10 7l5 5-5 5', chk: 'M5 12l5 5 9-10', task: 'M5 12l4 4L19 6', x: 'M6 6l12 12M18 6L6 18', bin: 'M5 7h14M10 7V4h4v3M7 7l1 13h8l1-13' };
113
114
  const ic = (k, w = 16, cls = '') => `<svg aria-hidden="true" width="${w}" height="${w}" viewBox="0 0 24 24"${cls ? ` class="${cls}"` : ''}><path d="${P[k]}"/></svg>`;
114
115
  const pct = (x) => Math.min(100, Math.max(0, x)).toFixed(2);
115
116
 
@@ -139,7 +140,8 @@ function pointRow(p, ui) {
139
140
  + (p.check ? `<small class="vzp-chk2">Check: you said “${esc(p.check.phrase)}” means ${esc(p.check.meaning)}</small>` : '') + '</span></button>';
140
141
  }
141
142
  const stop = (t) => (/[.!?…”]$/.test(t) ? t : t + '.');
142
- /** The correction (XvAReplayEdit): the kind, the old words struck, the new words, what PMOS will remember, Cancel and Save.
143
+ /** The correction (XvAReplayEdit): the kind, the old words struck, the new words, what PMOS will remember, the trash (Delete: no confirm,
144
+ * Undo in the message, like a task's Delete), Cancel and Save.
143
145
  * d = { kind, text, learn }; also = how many other points of this note use the learned words. */
144
146
  export function editHtml(p, d = {}, also = 0) {
145
147
  const kind = d.kind || p.kind, text = d.text == null ? p.text : d.text, learn = d.learn !== false;
@@ -152,7 +154,7 @@ export function editHtml(p, d = {}, also = 0) {
152
154
  + (changed ? `<p class="vzp-was"><s>${esc(KIND_OF[p.orig.kind] + ' · ' + p.orig.text)}</s></p>` : '')
153
155
  + `<textarea class="vzp-eta" data-a="etext" rows="3" aria-label="What was really said">${esc(text)}</textarea>`
154
156
  + `<div class="vzp-learn"><b>${learn && changed ? 'I will remember this.' : ''}</b> <span data-pl="lesson">${esc(lessonText)}</span>${changed ? ` <button type="button" class="vzp-link" data-a="elearn" aria-pressed="${!learn}">${learn ? 'Only fix this one' : 'Remember it'}</button>` : ''}</div>`
155
- + `<div class="vzp-ef"><span class="vzp-mut vzp-sm">${esc([p.time, p.by].filter(Boolean).join(' · '))}</span><span class="vzp-sp"></span><button type="button" class="vzp-gbtn" data-a="ecancel">Cancel</button><button type="button" class="vzp-dark" data-a="esave"${changed && text.trim() ? '' : ' disabled'}>Save</button></div></div>`;
157
+ + `<div class="vzp-ef"><span class="vzp-mut vzp-sm">${esc([p.time, p.by].filter(Boolean).join(' · '))}</span><span class="vzp-sp"></span><button type="button" class="vzp-ib vzp-del" data-a="edel" data-id="${esc(p.id)}" aria-label="Delete" title="Delete">${ic('bin', 16)}</button><button type="button" class="vzp-gbtn" data-a="ecancel">Cancel</button><button type="button" class="vzp-dark" data-a="esave"${changed && text.trim() ? '' : ' disabled'}>Save</button></div></div>`;
156
158
  }
157
159
  /** "In this part · <topic>": the kept points said in the stretch the replay is in. */
158
160
  export function partHtml(V, ui = {}) {
@@ -700,7 +700,7 @@ function keydown(me, e, body) {
700
700
  }
701
701
  const bodyEl = () => (MT && vCur() && vCur().id === MT.vid ? document.querySelector('#czViewer .cz-vw-body') : null); // null while a preview covers the meeting
702
702
  const repaint = (me) => { const b = bodyEl(); if (b && MT === me) paint(me, b); };
703
- function say(me, text, tone, undo) { me.ui.msg = { text, tone, undo }; repaint(me); clearTimeout(me.msgT); me.msgT = setTimeout(() => { if (me.ui.msg && me.ui.msg.text === text) { me.ui.msg = null; repaint(me); } }, 9000); }
703
+ function say(me, text, tone, undo, ms = 9000) { me.ui.msg = { text, tone, undo }; repaint(me); clearTimeout(me.msgT); me.msgT = setTimeout(() => { if (me.ui.msg && me.ui.msg.text === text) { me.ui.msg = null; repaint(me); } }, ms); }
704
704
  function tick(me) {
705
705
  if (MT !== me || !me.model) return;
706
706
  const b = bodyEl(); if (!b) return;
@@ -783,6 +783,7 @@ async function press(me, e) {
783
783
  case 'elearn': ui.draft = { ...ui.draft, learn: ui.draft.learn === false, text: draftText() }; return repaint(me);
784
784
  case 'ecancel': ui.edit = null; ui.draft = null; return repaint(me);
785
785
  case 'esave': return saveEdit(me);
786
+ case 'edel': return delPoint(me, t.dataset.id);
786
787
  /* the summary's quiet line and the lines under it */
787
788
  case 'm-about': if (ui.pop === 'about') { ui.pop = ''; return repaint(me); } return openAbout(me);
788
789
  case 'aboutpick': return saveAbout(me, t.dataset.v);
@@ -941,6 +942,15 @@ async function bulk(me, k, ids) {
941
942
  }
942
943
  return verdict(me, ids, k, k === 'confirmed' ? plural(ids.length, 'point') + ' confirmed.' : plural(ids.length, 'point') + ' moved to Left out.', k === 'wrong');
943
944
  }
945
+ /** Delete on the edit card: the point is gone, here and after a reload (verdict deleted). No confirm: Undo stays 8 s, as a task's Delete. */
946
+ async function delPoint(me, id) {
947
+ if (!me.n || !id) return;
948
+ const r = await pmPost('/api/meeting-points', { note: me.n.id, ids: [id], verdict: 'deleted' });
949
+ if (!r || !r.ok) return say(me, 'Not deleted: ' + ((r && r.error) || 'no answer'), 'bad');
950
+ me.ui.edit = null; me.ui.draft = null; if (me.ui.sel) me.ui.sel.delete(id);
951
+ me.D.points = r.points || {}; draw(me);
952
+ say(me, 'Point deleted.', '', async () => verdict(me, [id], null, 'Put back.'), 8000);
953
+ }
944
954
  async function verdict(me, ids, v, text, undo) {
945
955
  const r = await pmPost('/api/meeting-points', { note: me.n.id, ids, verdict: v });
946
956
  if (!r || !r.ok) return say(me, 'Not saved: ' + ((r && r.error) || 'no answer'), 'bad');