create-pmos 0.51.0 → 0.53.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.
Files changed (212) hide show
  1. package/package.json +1 -1
  2. package/payload/KIT-VERSION +2 -2
  3. package/payload/mods/pmos-cockpit/README.md +13 -0
  4. package/payload/mods/pmos-cockpit/hooks/lib/commands.mjs +2 -1
  5. package/payload/mods/pmos-cockpit/hooks/lib/grants.mjs +41 -11
  6. package/payload/mods/pmos-cockpit/hooks/lib/guard.mjs +228 -8
  7. package/payload/mods/pmos-cockpit/hooks/register.tsx +11 -3
  8. package/payload/planning/evals/eval-calibration.md +1 -1
  9. package/payload/planning/okrs/health-budgets.md +1 -1
  10. package/payload/scripts/plan-items-stage.js +271 -0
  11. package/payload/scripts/pmos-log.sh +18 -7
  12. package/payload/scripts/workflow-state.js +28 -2
  13. package/payload/state/discoveries.md +1 -1
  14. package/payload/state/log.md +1 -1
  15. package/workspace/bin/pmos.js +15 -1
  16. package/workspace/cut-stub.js +40 -0
  17. package/workspace/first-paint-audit.js +145 -0
  18. package/workspace/fixtures/capture/requirements/capture-2026-10-04-1.md +10 -0
  19. package/workspace/fixtures/initiatives-api/list.json +176 -0
  20. package/workspace/fixtures/initiatives-api/post-403.json +5 -0
  21. package/workspace/fixtures/initiatives-api/post-ok.json +10 -0
  22. package/workspace/fixtures/initiatives-api/roadmap.json +208 -0
  23. package/workspace/fixtures/initiatives-api/sheet.json +112 -0
  24. package/workspace/fixtures/report-api/draft.json +177 -0
  25. package/workspace/fixtures/reports-page/draft-biweekly-2026-10-16.md +97 -0
  26. package/workspace/fixtures/today-api/provider-rows.json +204 -0
  27. package/workspace/fixtures/today-api/seam-probe-kinds.json +5 -0
  28. package/workspace/guide/board.md +81 -0
  29. package/workspace/guide/breakdown.md +154 -0
  30. package/workspace/guide/command-palette.md +75 -0
  31. package/workspace/guide/index.md +27 -17
  32. package/workspace/guide/initiatives-roadmap.md +130 -0
  33. package/workspace/guide/initiatives-screen.md +89 -0
  34. package/workspace/guide/initiatives-timeline.md +57 -0
  35. package/workspace/guide/integrated-work.md +94 -0
  36. package/workspace/guide/knowledge-graph.md +3 -68
  37. package/workspace/guide/layout.md +98 -32
  38. package/workspace/guide/live-notes.md +3 -3
  39. package/workspace/guide/pm-only-acts.md +89 -0
  40. package/workspace/guide/pm-only-lines.md +61 -0
  41. package/workspace/guide/reports-page.md +80 -0
  42. package/workspace/guide/reports.md +73 -0
  43. package/workspace/guide/timeline.md +70 -0
  44. package/workspace/guide/today.md +85 -0
  45. package/workspace/guide/validate-with-typesafe.md +1 -1
  46. package/workspace/lib/actor.js +91 -0
  47. package/workspace/lib/board-cache.js +32 -2
  48. package/workspace/lib/board-cli.js +108 -0
  49. package/workspace/lib/board-fold.js +232 -0
  50. package/workspace/lib/breakdown-export.js +80 -0
  51. package/workspace/lib/capture.js +98 -0
  52. package/workspace/lib/engine/plan-items-stage.js +271 -0
  53. package/workspace/lib/engine/workflow-state.js +28 -2
  54. package/workspace/lib/factory-join.js +158 -0
  55. package/workspace/lib/grant-mint.js +113 -0
  56. package/workspace/lib/health-rules-factory.js +92 -0
  57. package/workspace/lib/health-rules-plan.js +164 -0
  58. package/workspace/lib/health.js +79 -0
  59. package/workspace/lib/initiative-cli.js +222 -0
  60. package/workspace/lib/initiative-display.js +183 -0
  61. package/workspace/lib/initiative-needs.js +127 -0
  62. package/workspace/lib/initiative-rows.js +206 -0
  63. package/workspace/lib/initiative-writer.js +141 -0
  64. package/workspace/lib/issues.js +206 -0
  65. package/workspace/lib/item-cli.js +195 -0
  66. package/workspace/lib/item-spans.js +137 -0
  67. package/workspace/lib/measure-cli.js +100 -0
  68. package/workspace/lib/measurements.js +189 -0
  69. package/workspace/lib/mobile-nav.js +57 -53
  70. package/workspace/lib/needs-providers.js +120 -0
  71. package/workspace/lib/placements.js +440 -0
  72. package/workspace/lib/plan-items.js +922 -0
  73. package/workspace/lib/plan-ledgers.js +85 -0
  74. package/workspace/lib/plan-rules.js +72 -0
  75. package/workspace/lib/plan-tree.js +367 -0
  76. package/workspace/lib/pm-guard.js +174 -0
  77. package/workspace/lib/pm-lines-needs.js +331 -0
  78. package/workspace/lib/pmos-verbs.js +66 -0
  79. package/workspace/lib/proactive.js +7 -4
  80. package/workspace/lib/report-cli.js +152 -0
  81. package/workspace/lib/report-draft.js +579 -0
  82. package/workspace/lib/report-needs.js +213 -0
  83. package/workspace/lib/route-modules.js +128 -0
  84. package/workspace/lib/routes-board.js +91 -0
  85. package/workspace/lib/routes-capture.js +52 -0
  86. package/workspace/lib/routes-initiatives.js +371 -0
  87. package/workspace/lib/routes-reports.js +163 -0
  88. package/workspace/lib/routes-timeline.js +197 -0
  89. package/workspace/lib/routes-today.js +32 -0
  90. package/workspace/lib/today-cli.js +99 -0
  91. package/workspace/lib/today.js +333 -0
  92. package/workspace/lib/triage.js +163 -0
  93. package/workspace/lib/verify-work-cli.js +81 -0
  94. package/workspace/lib/work-check-needs.js +99 -0
  95. package/workspace/package-lock.json +1 -1
  96. package/workspace/package.json +5 -5
  97. package/workspace/public/index.html +29 -19
  98. package/workspace/public/pm/app.js +299 -30
  99. package/workspace/public/pm/bd-board.js +113 -0
  100. package/workspace/public/pm/bd-drag.js +59 -0
  101. package/workspace/public/pm/bd-model.js +152 -0
  102. package/workspace/public/pm/bd-timeline.js +233 -0
  103. package/workspace/public/pm/bd-tree.js +244 -0
  104. package/workspace/public/pm/board-copy.js +57 -0
  105. package/workspace/public/pm/breakdown-api.js +58 -0
  106. package/workspace/public/pm/breakdown-copy.js +138 -0
  107. package/workspace/public/pm/components.css +3054 -0
  108. package/workspace/public/pm/cycle-review.js +125 -0
  109. package/workspace/public/pm/data.js +40 -187
  110. package/workspace/public/pm/dest-board.js +438 -0
  111. package/workspace/public/pm/dest-initiatives.js +134 -0
  112. package/workspace/public/pm/dest-reports.js +270 -0
  113. package/workspace/public/pm/dest-settings.js +217 -0
  114. package/workspace/public/pm/dest-today.js +176 -0
  115. package/workspace/public/pm/dialogs.js +88 -0
  116. package/workspace/public/pm/display-word.js +56 -0
  117. package/workspace/public/pm/dock.js +105 -0
  118. package/workspace/public/pm/fixture.js +8 -227
  119. package/workspace/public/pm/frame-copy.js +94 -0
  120. package/workspace/public/pm/handoff-box.js +82 -0
  121. package/workspace/public/pm/http.js +88 -0
  122. package/workspace/public/pm/icons.js +53 -0
  123. package/workspace/public/pm/initiative-list.js +218 -0
  124. package/workspace/public/pm/initiative-sheet.js +261 -0
  125. package/workspace/public/pm/initiatives-api.js +59 -0
  126. package/workspace/public/pm/initiatives-copy.js +215 -0
  127. package/workspace/public/pm/initiatives-timeline-copy.js +59 -0
  128. package/workspace/public/pm/initiatives-timeline.js +410 -0
  129. package/workspace/public/pm/initiatives-ui.js +123 -0
  130. package/workspace/public/pm/item-sheet.js +251 -0
  131. package/workspace/public/pm/keep-card.js +204 -0
  132. package/workspace/public/pm/lifecycle.js +7 -1
  133. package/workspace/public/pm/mobile.css +49 -20
  134. package/workspace/public/pm/mobile.js +157 -29
  135. package/workspace/public/pm/modes-live.js +7 -883
  136. package/workspace/public/pm/modes.js +32 -1024
  137. package/workspace/public/pm/new-initiative-sheet.js +74 -0
  138. package/workspace/public/pm/next-step-ui.js +3 -2
  139. package/workspace/public/pm/palette-copy.js +51 -0
  140. package/workspace/public/pm/palette.js +312 -0
  141. package/workspace/public/pm/panel-breakdown.js +702 -0
  142. package/workspace/public/pm/panel-cockpit.js +63 -295
  143. package/workspace/public/pm/panel-detail.js +25 -172
  144. package/workspace/public/pm/panel-initiatives.js +1 -19
  145. package/workspace/public/pm/panel-repos.js +31 -81
  146. package/workspace/public/pm/panel-tabs.js +197 -110
  147. package/workspace/public/pm/panel-trees.js +5 -2
  148. package/workspace/public/pm/portfolio-report.js +61 -0
  149. package/workspace/public/pm/primitives.js +656 -0
  150. package/workspace/public/pm/print.css +33 -0
  151. package/workspace/public/pm/provider-cards.js +136 -0
  152. package/workspace/public/pm/registry.js +194 -0
  153. package/workspace/public/pm/release-card.js +110 -0
  154. package/workspace/public/pm/report-view.js +309 -0
  155. package/workspace/public/pm/reports-copy.js +114 -0
  156. package/workspace/public/pm/roadmap.js +271 -0
  157. package/workspace/public/pm/sig-watch.js +41 -0
  158. package/workspace/public/pm/state.js +8 -4
  159. package/workspace/public/pm/status-banner.js +13 -5
  160. package/workspace/public/pm/tab-doc.js +2 -4
  161. package/workspace/public/pm/tab-term.js +12 -2
  162. package/workspace/public/pm/tab-web.js +3 -2
  163. package/workspace/public/pm/timeline-copy.js +48 -0
  164. package/workspace/public/pm/today-cards.js +244 -0
  165. package/workspace/public/pm/today-copy.js +97 -0
  166. package/workspace/public/pm/tokens.css +16 -18
  167. package/workspace/public/pm/topbar.js +102 -0
  168. package/workspace/public/pm/triage-card.js +60 -0
  169. package/workspace/public/pm/undo-hold.js +103 -0
  170. package/workspace/public/pm/view-addrepo.js +2 -1
  171. package/workspace/public/pm/view-livenotes.js +3 -1
  172. package/workspace/public/pm/view-today.js +7 -162
  173. package/workspace/public/vendor/Sortable.min.js +2 -0
  174. package/workspace/public/vendor/lucide-sprite.js +79 -0
  175. package/workspace/replaced-tests.json +2864 -0
  176. package/workspace/run-tests.js +117 -6
  177. package/workspace/server.js +312 -36
  178. package/workspace/sheet-answer.js +61 -0
  179. package/workspace/skills/measure.skill +41 -0
  180. package/workspace/skills/report-biweekly.skill +23 -25
  181. package/workspace/skills/tracker-refresh.skill +50 -0
  182. package/workspace/test-files.json +20 -4
  183. package/workspace/test-lists/base.json +6 -0
  184. package/workspace/test-lists/run2-a.json +6 -0
  185. package/workspace/test-lists/run2-b.json +13 -0
  186. package/workspace/test-lists/run2-c.json +19 -0
  187. package/workspace/test-lists/run2-d.json +22 -0
  188. package/workspace/test-lists/run3-0.json +5 -0
  189. package/workspace/test-lists/run3-a.json +5 -0
  190. package/workspace/test-lists/run3-b.json +6 -0
  191. package/workspace/test-lists/run3-c.json +15 -0
  192. package/workspace/test-lists/run3-d.json +6 -0
  193. package/workspace/test-lists/run4-a.json +8 -0
  194. package/workspace/test-lists/run4-b.json +6 -0
  195. package/workspace/test-lists/run4-c.json +13 -0
  196. package/workspace/test-lists/run4-d.json +9 -0
  197. package/workspace/test-lists/run5-a.json +6 -0
  198. package/workspace/test-lists/run5-b.json +6 -0
  199. package/workspace/test-lists/run5-c.json +15 -0
  200. package/workspace/test-run.js +27 -1
  201. package/workspace/third-party/README.md +44 -0
  202. package/workspace/third-party/lucide-static-1.52.0.LICENSE +43 -0
  203. package/workspace/third-party/sortablejs-1.15.7.LICENSE +21 -0
  204. package/workspace/design-parity.js +0 -673
  205. package/workspace/public/pm/tab-task.js +0 -86
  206. package/workspace/public/pm/view-guide.js +0 -141
  207. package/workspace/public/pm/view-knowledge.js +0 -225
  208. package/workspace/public/pm/view-memory.js +0 -122
  209. package/workspace/public/pm/view-portfolio.js +0 -153
  210. package/workspace/public/pm/view-reports.js +0 -190
  211. package/workspace/public/pm/view-scheduled.js +0 -161
  212. package/workspace/public/pm/view-skills.js +0 -216
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+ /* work-check-needs.js — the work that waits for the PM to check it: the needs-you rows of R12 kind 4
3
+ * (pm-os-absorb Run 4, slice 4D).
4
+ *
5
+ * kinds: item-review · item-no-evidence · release
6
+ * rowsFor(w, { lead }) → rows sig(w) → string (lib/needs-providers.js folds both into /api/needs and Today)
7
+ *
8
+ * R7: Review means the maker has finished and someone else must judge; when that judge is the PM, the item is on Today.
9
+ * The three rows:
10
+ * - item-review an item in Review whose maker is an agent or a person other than the PM (owner `agent` or
11
+ * `person:<name>`). The PM's own item in Review waits for someone else, and a tracker item is judged
12
+ * in the tracker, so neither is a row. A proposed item is not yet kept, so it is not a row either.
13
+ * - item-no-evidence an item the agent moved to Done with no evidence pointer (R7: "no evidence" reaches Today).
14
+ * - release a D65 batch whose items all passed their checks (lib/factory-join.js batches, ready). One row for
15
+ * each batch; one press mints ONE release grant for it (POST /api/board/release).
16
+ * Each row is for a WORK-lane initiative only (D86 point 4); a document-lane initiative has no row.
17
+ *
18
+ * A release row's initiative and batch are in its run_id (`work-check-needs:release:<initiative>:<batch>`), so the row keeps
19
+ * the golden's keys (fixtures/today-api/provider-rows.json) and the card reads them from there.
20
+ * A row's `today` is the card's payload: { kind: 4, source: 'work-check-needs', cause, evidence, act: { label, cli } }.
21
+ * public/pm/release-card.js draws all three kinds: the Release card, and an item card that shows the item's title. `lead` false answers []: these rows are repository-wide, and a linked
22
+ * worktree registered beside its main tree would count every row twice (lib/needs-providers.js).
23
+ *
24
+ * `sig(w)` names every file the rows read: plan-items and the factory join (which reads the work-item ledger), and the
25
+ * initiative records, plan-rules.json and the grants ledger (boardFold.sideSig).
26
+ */
27
+ const crypto = require('crypto');
28
+ const path = require('path');
29
+ const planItems = require('./plan-items.js');
30
+ const factoryJoin = require('./factory-join.js');
31
+ const boardFold = require('./board-fold.js');
32
+
33
+ const kinds = ['item-review', 'item-no-evidence', 'release'];
34
+ const SOURCE = 'work-check-needs';
35
+
36
+ const judgedByPm = (owner) => owner === 'agent' || /^person:/.test(String(owner || ''));
37
+ const noun = (n) => (n === 1 ? '1 work item' : `${n} work items`);
38
+
39
+ /** The ledger paths a row cites, relative to the repository: the runs directory beside plan-items.jsonl. */
40
+ function evidencePaths(root) {
41
+ let plan = 'planning/runs/plan-items.jsonl';
42
+ try { plan = path.relative(path.resolve(root), planItems.ledgerPath(root)).split(path.sep).join('/'); } catch { /* the default stands */ }
43
+ const dir = path.posix.dirname(plan);
44
+ const factory = dir === 'planning/runs' ? 'planning/work-items.jsonl' : dir + '/work-items.jsonl';
45
+ return { plan, factory };
46
+ }
47
+
48
+ function rowsFor(w, { lead } = {}) {
49
+ if (!lead) return [];
50
+ const root = w.root;
51
+ const works = new Set(boardFold.workInitiatives(root).map((i) => i.id));
52
+ const ev = evidencePaths(root);
53
+ const rows = [];
54
+ const fold = planItems.readFold(root);
55
+ for (const id of fold.order) {
56
+ const it = fold.items[id];
57
+ if (!works.has(it.initiative) || it.proposed) continue;
58
+ if (it.state === 'review' && judgedByPm(it.owner)) {
59
+ rows.push({
60
+ run_id: `${SOURCE}:review:${id}`, kind: 'item-review', initiative_id: it.initiative, doc: null,
61
+ question: `"${it.title}" is in Review`,
62
+ today: { kind: 4, source: SOURCE, cause: 'An item waits in Review', evidence: ev.plan, act: { label: 'Open', cli: null } },
63
+ });
64
+ } else if (it.state === 'done' && it.noEvidence) {
65
+ rows.push({
66
+ run_id: `${SOURCE}:no-evidence:${id}`, kind: 'item-no-evidence', initiative_id: it.initiative, doc: null,
67
+ question: `"${it.title}" reads Done with no evidence`,
68
+ today: { kind: 4, source: SOURCE, cause: 'An agent item is Done with no evidence', evidence: ev.plan, act: { label: 'Open', cli: null } },
69
+ });
70
+ }
71
+ }
72
+ const join = factoryJoin.joinFactory(root);
73
+ const granted = boardFold.releaseGrants(root); // a batch that was released has no row
74
+ for (const init of Object.keys(join.byInit || {}).sort()) {
75
+ if (!works.has(init)) continue;
76
+ for (const b of (join.byInit[init].batches || [])) {
77
+ if (!b || !b.ready || granted.has(`${init}:${b.id}`)) continue;
78
+ const n = (b.items || []).length;
79
+ rows.push({
80
+ run_id: `${SOURCE}:release:${init}:${b.id}`, kind: 'release', initiative_id: init, doc: null,
81
+ question: `${noun(n)} ${n === 1 ? 'is' : 'are'} ready to release`,
82
+ today: { kind: 4, source: SOURCE, cause: 'A factory batch is ready', evidence: ev.factory, act: { label: 'Release', cli: null } },
83
+ });
84
+ }
85
+ }
86
+ return rows;
87
+ }
88
+
89
+ function sig(w) {
90
+ let items = 'none';
91
+ try { items = planItems.ledgerSigs([{ id: w.id, root: w.root }], '')[w.id].items; } catch { items = 'unreadable'; }
92
+ let factory = 'none';
93
+ try { factory = crypto.createHash('sha1').update(JSON.stringify(factoryJoin.joinFactory(w.root).byInit || {})).digest('hex'); } catch { factory = 'unreadable'; }
94
+ let side = 'none';
95
+ try { side = boardFold.sideSig(w.root); } catch { side = 'unreadable'; }
96
+ return `${items}:${factory}:${side}`;
97
+ }
98
+
99
+ module.exports = { kinds, rowsFor, sig };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
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.51.0",
3
+ "version": "0.53.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",
@@ -12,13 +12,13 @@
12
12
  "test": "node run-tests.js unit",
13
13
  "test:modules": "node run-tests.js modules",
14
14
  "test:ui": "node ui-test.js",
15
- "test:parity": "node design-parity.js --board=WsA",
16
- "test:parity:four-panel": "node design-parity.js --states",
17
- "test:all": "node run-tests.js all && npm run test:parity && npm run test:offline",
15
+ "test:all": "node run-tests.js all && npm run test:offline",
18
16
  "doctor": "node doctor.js",
19
17
  "test:panels": "node run-tests.js panels",
20
18
  "test:offline": "node offline-tarball.test.js",
19
+ "test:conformance": "node conformance-gate.js --self-test && node conformance-gate.js --base origin/main",
21
20
  "test:browser": "node run-tests.js browser",
21
+ "test:changed": "node run-tests.js all --changed",
22
22
  "test:list-check": "node run-tests.js --check"
23
23
  },
24
24
  "engines": {
@@ -32,7 +32,7 @@
32
32
  "playwright-core": "^1.61.1",
33
33
  "ws": "^8.18.0"
34
34
  },
35
- "//devDependencies": "design-parity's pixel axis only. Kept OUT of dependencies deliberately: `create-pmos workspace` installs this package with `npm install -g`, which takes dependencies and not devDependencies, so an adopter installing a local PM tool does not also install a screenshot differ. design-parity.js requires both optionally and degrades to text+style+geometry when they are absent, so the parity check still runs — it just stops measuring pixels, and says so.",
35
+ "//devDependencies": "pixelmatch and pngjs have no consumer since design-parity.js was deleted (Run 3, slice 3D). They stay listed until a later chore removes them. Kept OUT of dependencies deliberately: `create-pmos workspace` installs this package with `npm install -g`, which takes dependencies and not devDependencies.",
36
36
  "devDependencies": {
37
37
  "pixelmatch": "^7.1.0",
38
38
  "pngjs": "^7.0.0"
@@ -3,6 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
+ <meta name="pmos-nonce" content="" />
6
7
  <title>PMOS workspace</title>
7
8
  <!-- The terminal's face is preloaded, not left to be discovered. An @font-face is only fetched when
8
9
  something first RENDERS in it, which for Plex Mono is about the same moment a tab constructs
@@ -59,6 +60,12 @@
59
60
  file scripts/md-newlines.js requires, loaded here as window.MdNormalize, so the one-click
60
61
  repair and the CI ratchet can never disagree about what a normalized document is. -->
61
62
  <script src="/lib/md-normalize.js"></script>
63
+ <!-- pm-os-absorb: the words an initiative shows (R3), read from its derived ladder and never typed. The same file the
64
+ server and the report drafter require, loaded here as window.PMOSInitiativeDisplay. -->
65
+ <script src="/lib/initiative-display.js"></script>
66
+ <!-- pm-os-absorb: the dated bars of a breakdown (R20), one engine for both Timelines and the report strip, loaded here
67
+ as window.PMOSItemSpans. -->
68
+ <script src="/lib/item-spans.js"></script>
62
69
  <link rel="preload" href="/vendor/ibm-plex-mono-500.woff2" as="font" type="font/woff2" crossorigin />
63
70
  </head>
64
71
  <body>
@@ -71,13 +78,15 @@
71
78
  breakpoint this is absent from the accessibility tree rather than merely invisible: a desktop
72
79
  PM must not be able to tab into a second navigation system they cannot see. -->
73
80
 
74
- <!-- The top bar: back · the screen's name · the ⌘K jump palette · theme. It sits ABOVE .body in
81
+ <!-- The top bar: back · Repository · the screen's name · the ⌘K palette · Settings (the frame; the old shell shows its
82
+ brand and theme in place of Repository and Settings). It sits ABOVE .body in
75
83
  DOM order because it is the row above the content on screen, and putting it beside the bottom
76
84
  nav would read the app backwards. -->
77
85
  <div class="mob" id="mobShell" hidden>
78
86
  <header class="mob-bar" id="mobBar">
79
- <button class="mob-back" id="mobBack" type="button" hidden aria-label="Back">‹ back</button>
80
- <span class="mob-brand" id="mobBrand" aria-hidden="true">◎</span>
87
+ <button class="mob-back" id="mobBack" type="button" hidden aria-label="Back"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="chevron-left"><use href="#lucide-chevron-left"></use></svg><span>Back</span></button>
88
+ <span class="mob-brand" id="mobBrand" aria-hidden="true">PMOS</span>
89
+ <button class="mob-repo" id="mobRepo" type="button" hidden aria-haspopup="menu">Repository</button>
81
90
  <span class="mob-title" id="mobTitle"></span>
82
91
  <!-- The jump palette lives HERE, not in the control bar below. Two reasons, and the second is
83
92
  the binding one: it is not a terminal control key (every other button in the bar writes a
@@ -87,32 +96,33 @@
87
96
  palette is a jump control for every destination, so it belongs in the bar that is always
88
97
  on screen. -->
89
98
  <button class="mob-pal" id="mobPalette" type="button" aria-label="Open the jump palette (⌘K)">⌘K</button>
90
- <button class="mob-theme" id="mobTheme" type="button" aria-label="Toggle theme">◐</button>
99
+ <button class="mob-theme" id="mobTheme" type="button" aria-label="Toggle theme"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="moon"><use href="#lucide-moon"></use></svg></button>
100
+ <button class="mob-sync" id="mobSync" type="button" hidden>Sync</button>
101
+ <button class="mob-set" id="mobSettings" type="button" hidden aria-current="false">Settings</button>
91
102
  </header>
92
103
  </div>
93
104
 
94
105
  <!-- The bottom block: a terminal control-key accessory bar (terminal screen only — phones have no
95
- Esc/Tab/Ctrl/arrows) over the five-destination nav. The nav is a <nav> of buttons carrying
96
- aria-current, NOT a tablist: the retired markup declared role="tablist" over role="tab"
97
- children with no tabpanel and no aria-controls anywhere, which is a promise the DOM did not
98
- keep. Selecting a destination resets it to its root; depth is pushed on top of it and #mobBack
99
- pops one screen. The glyphs are the mobile prototype's own (◧ ◔ ◐ ◒ ☰). -->
106
+ Esc/Tab/Ctrl/arrows) over the five tabs (pm-os-absorb Run 3, slice 3A): Today · Initiatives · Board · Reports ·
107
+ Agent. The first four are the frame's places; Agent is the dock with its live terminals. The nav is a <nav> of
108
+ buttons carrying aria-current, NOT a tablist: there is no tabpanel to point at. Selecting a tab resets it to its
109
+ root; depth is pushed on top of it and #mobBack pops one screen. Words, not glyphs, name each tab. -->
100
110
  <div class="mobmenu" id="mobMenu" hidden>
101
111
  <div class="ctrlbar" id="ctrlBar" role="toolbar" aria-label="Terminal control keys">
102
112
  <button type="button" data-seq="esc" aria-label="Escape"><span class="lbl">esc</span></button>
103
113
  <button type="button" data-seq="tab" aria-label="Tab"><span class="lbl">tab</span></button>
104
114
  <button type="button" id="ctrlKey" aria-pressed="false" aria-label="Control modifier (one-shot)"><span class="lbl">ctrl</span></button>
105
- <button type="button" data-seq="left" aria-label="Left arrow">←</button>
106
- <button type="button" data-seq="up" aria-label="Up arrow">↑</button>
107
- <button type="button" data-seq="down" aria-label="Down arrow">↓</button>
108
- <button type="button" data-seq="right" aria-label="Right arrow">→</button>
115
+ <button type="button" data-seq="left" aria-label="Left arrow"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="arrow-left"><use href="#lucide-arrow-left"></use></svg></button>
116
+ <button type="button" data-seq="up" aria-label="Up arrow"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="arrow-up"><use href="#lucide-arrow-up"></use></svg></button>
117
+ <button type="button" data-seq="down" aria-label="Down arrow"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="arrow-down"><use href="#lucide-arrow-down"></use></svg></button>
118
+ <button type="button" data-seq="right" aria-label="Right arrow"><svg class="pmc-icon" width="16" height="16" aria-hidden="true" focusable="false" data-icon="arrow-right"><use href="#lucide-arrow-right"></use></svg></button>
109
119
  </div>
110
- <nav class="mobnav" id="mobNav" aria-label="Sections">
111
- <button type="button" class="mobnav-b" data-dest="board" aria-current="page"><span class="g" aria-hidden="true">◧</span><span class="l">board</span></button>
112
- <button type="button" class="mobnav-b" data-dest="scheduled" aria-current="false"><span class="g" aria-hidden="true">◔</span><span class="l">scheduled</span></button>
113
- <button type="button" class="mobnav-b" data-dest="agents" aria-current="false"><span class="g" aria-hidden="true">◐</span><span class="l">agents</span></button>
114
- <button type="button" class="mobnav-b" data-dest="memory" aria-current="false"><span class="g" aria-hidden="true">◒</span><span class="l">memory</span></button>
115
- <button type="button" class="mobnav-b" data-dest="more" aria-current="false"><span class="g" aria-hidden="true">☰</span><span class="l">more</span></button>
120
+ <nav class="mobnav" id="mobNav" aria-label="Destinations">
121
+ <button type="button" class="mobnav-b" data-dest="today" aria-current="page"><span class="l">Today</span><span class="mobnav-n" id="mobTodayCount" hidden></span></button>
122
+ <button type="button" class="mobnav-b" data-dest="initiatives" aria-current="false"><span class="l">Initiatives</span></button>
123
+ <button type="button" class="mobnav-b" data-dest="board" aria-current="false"><span class="l">Board</span></button>
124
+ <button type="button" class="mobnav-b" data-dest="reports" aria-current="false"><span class="l">Reports</span></button>
125
+ <button type="button" class="mobnav-b" data-dest="agent" aria-current="false"><span class="l">Agent</span></button>
116
126
  </nav>
117
127
  </div>
118
128