create-pmos 0.52.0 → 0.53.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.
Files changed (229) 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/README.md +2 -0
  16. package/workspace/REMOTE.md +24 -63
  17. package/workspace/bin/pmos.js +19 -3
  18. package/workspace/cut-stub.js +40 -0
  19. package/workspace/first-paint-audit.js +145 -0
  20. package/workspace/fixtures/capture/requirements/capture-2026-10-04-1.md +10 -0
  21. package/workspace/fixtures/initiatives-api/list.json +176 -0
  22. package/workspace/fixtures/initiatives-api/post-403.json +5 -0
  23. package/workspace/fixtures/initiatives-api/post-ok.json +10 -0
  24. package/workspace/fixtures/initiatives-api/roadmap.json +208 -0
  25. package/workspace/fixtures/initiatives-api/sheet.json +112 -0
  26. package/workspace/fixtures/report-api/draft.json +177 -0
  27. package/workspace/fixtures/reports-page/draft-biweekly-2026-10-16.md +97 -0
  28. package/workspace/fixtures/today-api/provider-rows.json +204 -0
  29. package/workspace/fixtures/today-api/seam-probe-kinds.json +5 -0
  30. package/workspace/guide/board.md +81 -0
  31. package/workspace/guide/breakdown.md +154 -0
  32. package/workspace/guide/command-palette.md +75 -0
  33. package/workspace/guide/index.md +28 -17
  34. package/workspace/guide/initiatives-roadmap.md +130 -0
  35. package/workspace/guide/initiatives-screen.md +89 -0
  36. package/workspace/guide/initiatives-timeline.md +57 -0
  37. package/workspace/guide/integrated-work.md +94 -0
  38. package/workspace/guide/knowledge-graph.md +3 -68
  39. package/workspace/guide/launcher.md +51 -0
  40. package/workspace/guide/layout.md +102 -32
  41. package/workspace/guide/live-notes.md +3 -3
  42. package/workspace/guide/pm-only-acts.md +89 -0
  43. package/workspace/guide/pm-only-lines.md +61 -0
  44. package/workspace/guide/proactive-engine.md +21 -5
  45. package/workspace/guide/reports-page.md +80 -0
  46. package/workspace/guide/reports.md +73 -0
  47. package/workspace/guide/timeline.md +70 -0
  48. package/workspace/guide/today.md +85 -0
  49. package/workspace/guide/validate-with-typesafe.md +1 -1
  50. package/workspace/lib/actor.js +91 -0
  51. package/workspace/lib/board-cache.js +32 -2
  52. package/workspace/lib/board-cli.js +108 -0
  53. package/workspace/lib/board-fold.js +232 -0
  54. package/workspace/lib/breakdown-export.js +75 -0
  55. package/workspace/lib/brief.js +20 -2
  56. package/workspace/lib/capture.js +98 -0
  57. package/workspace/lib/engine/plan-items-stage.js +271 -0
  58. package/workspace/lib/engine/workflow-state.js +28 -2
  59. package/workspace/lib/factory-join.js +158 -0
  60. package/workspace/lib/goals.js +165 -0
  61. package/workspace/lib/grant-mint.js +113 -0
  62. package/workspace/lib/health-rules-factory.js +92 -0
  63. package/workspace/lib/health-rules-plan.js +164 -0
  64. package/workspace/lib/health.js +79 -0
  65. package/workspace/lib/initiative-cli.js +222 -0
  66. package/workspace/lib/initiative-display.js +183 -0
  67. package/workspace/lib/initiative-needs.js +127 -0
  68. package/workspace/lib/initiative-rows.js +210 -0
  69. package/workspace/lib/initiative-writer.js +141 -0
  70. package/workspace/lib/issues.js +206 -0
  71. package/workspace/lib/item-cli.js +195 -0
  72. package/workspace/lib/item-spans.js +137 -0
  73. package/workspace/lib/launcher-cli.js +207 -0
  74. package/workspace/lib/measure-cli.js +100 -0
  75. package/workspace/lib/measurements.js +189 -0
  76. package/workspace/lib/mobile-nav.js +57 -53
  77. package/workspace/lib/needs-providers.js +120 -0
  78. package/workspace/lib/placements.js +440 -0
  79. package/workspace/lib/plan-items.js +922 -0
  80. package/workspace/lib/plan-ledgers.js +85 -0
  81. package/workspace/lib/plan-rules.js +72 -0
  82. package/workspace/lib/plan-tree.js +380 -0
  83. package/workspace/lib/pm-guard.js +174 -0
  84. package/workspace/lib/pm-lines-needs.js +331 -0
  85. package/workspace/lib/pmos-verbs.js +69 -0
  86. package/workspace/lib/proactive-cli.js +58 -2
  87. package/workspace/lib/proactive.js +9 -6
  88. package/workspace/lib/qr.js +293 -0
  89. package/workspace/lib/remote-access.js +93 -1
  90. package/workspace/lib/report-cli.js +152 -0
  91. package/workspace/lib/report-draft.js +578 -0
  92. package/workspace/lib/report-needs.js +213 -0
  93. package/workspace/lib/route-modules.js +128 -0
  94. package/workspace/lib/routes-board.js +91 -0
  95. package/workspace/lib/routes-capture.js +52 -0
  96. package/workspace/lib/routes-initiatives.js +371 -0
  97. package/workspace/lib/routes-reports.js +163 -0
  98. package/workspace/lib/routes-timeline.js +197 -0
  99. package/workspace/lib/routes-today.js +32 -0
  100. package/workspace/lib/today-cli.js +99 -0
  101. package/workspace/lib/today.js +333 -0
  102. package/workspace/lib/triage.js +163 -0
  103. package/workspace/lib/verify-work-cli.js +81 -0
  104. package/workspace/lib/work-check-needs.js +99 -0
  105. package/workspace/package-lock.json +1 -1
  106. package/workspace/package.json +4 -5
  107. package/workspace/public/icons/apple-touch-icon.png +0 -0
  108. package/workspace/public/icons/icon-192.png +0 -0
  109. package/workspace/public/icons/icon-512.png +0 -0
  110. package/workspace/public/index.html +40 -19
  111. package/workspace/public/pm/app.js +330 -30
  112. package/workspace/public/pm/bd-board.js +113 -0
  113. package/workspace/public/pm/bd-drag.js +59 -0
  114. package/workspace/public/pm/bd-model.js +152 -0
  115. package/workspace/public/pm/bd-timeline.js +233 -0
  116. package/workspace/public/pm/bd-tree.js +244 -0
  117. package/workspace/public/pm/board-copy.js +57 -0
  118. package/workspace/public/pm/breakdown-api.js +58 -0
  119. package/workspace/public/pm/breakdown-copy.js +138 -0
  120. package/workspace/public/pm/components.css +3135 -0
  121. package/workspace/public/pm/cycle-review.js +125 -0
  122. package/workspace/public/pm/data.js +40 -187
  123. package/workspace/public/pm/dest-board.js +438 -0
  124. package/workspace/public/pm/dest-initiatives.js +134 -0
  125. package/workspace/public/pm/dest-reports.js +270 -0
  126. package/workspace/public/pm/dest-settings.js +217 -0
  127. package/workspace/public/pm/dest-today.js +182 -0
  128. package/workspace/public/pm/dialogs.js +88 -0
  129. package/workspace/public/pm/display-word.js +56 -0
  130. package/workspace/public/pm/dock.js +175 -0
  131. package/workspace/public/pm/fixture.js +8 -227
  132. package/workspace/public/pm/frame-copy.js +99 -0
  133. package/workspace/public/pm/handoff-box.js +82 -0
  134. package/workspace/public/pm/http.js +88 -0
  135. package/workspace/public/pm/icons.js +53 -0
  136. package/workspace/public/pm/initiative-list.js +218 -0
  137. package/workspace/public/pm/initiative-sheet.js +261 -0
  138. package/workspace/public/pm/initiatives-api.js +59 -0
  139. package/workspace/public/pm/initiatives-copy.js +215 -0
  140. package/workspace/public/pm/initiatives-timeline-copy.js +59 -0
  141. package/workspace/public/pm/initiatives-timeline.js +410 -0
  142. package/workspace/public/pm/initiatives-ui.js +123 -0
  143. package/workspace/public/pm/item-sheet.js +251 -0
  144. package/workspace/public/pm/keep-card.js +204 -0
  145. package/workspace/public/pm/lifecycle.js +7 -1
  146. package/workspace/public/pm/mobile.css +49 -20
  147. package/workspace/public/pm/mobile.js +157 -29
  148. package/workspace/public/pm/modes-live.js +7 -883
  149. package/workspace/public/pm/modes.js +32 -1024
  150. package/workspace/public/pm/new-initiative-sheet.js +74 -0
  151. package/workspace/public/pm/next-step-ui.js +3 -2
  152. package/workspace/public/pm/palette-copy.js +51 -0
  153. package/workspace/public/pm/palette.js +312 -0
  154. package/workspace/public/pm/panel-breakdown.js +702 -0
  155. package/workspace/public/pm/panel-cockpit.js +63 -295
  156. package/workspace/public/pm/panel-detail.js +25 -172
  157. package/workspace/public/pm/panel-initiatives.js +1 -19
  158. package/workspace/public/pm/panel-repos.js +31 -81
  159. package/workspace/public/pm/panel-tabs.js +200 -111
  160. package/workspace/public/pm/panel-trees.js +5 -2
  161. package/workspace/public/pm/portfolio-report.js +61 -0
  162. package/workspace/public/pm/primitives.js +656 -0
  163. package/workspace/public/pm/print.css +33 -0
  164. package/workspace/public/pm/provider-cards.js +136 -0
  165. package/workspace/public/pm/registry.js +194 -0
  166. package/workspace/public/pm/release-card.js +110 -0
  167. package/workspace/public/pm/report-view.js +309 -0
  168. package/workspace/public/pm/reports-copy.js +114 -0
  169. package/workspace/public/pm/roadmap.js +271 -0
  170. package/workspace/public/pm/sig-watch.js +41 -0
  171. package/workspace/public/pm/state.js +8 -4
  172. package/workspace/public/pm/status-banner.js +13 -5
  173. package/workspace/public/pm/tab-doc.js +2 -4
  174. package/workspace/public/pm/tab-term.js +12 -2
  175. package/workspace/public/pm/tab-web.js +3 -2
  176. package/workspace/public/pm/timeline-copy.js +48 -0
  177. package/workspace/public/pm/today-cards.js +244 -0
  178. package/workspace/public/pm/today-copy.js +126 -0
  179. package/workspace/public/pm/today-goals.js +172 -0
  180. package/workspace/public/pm/tokens.css +16 -18
  181. package/workspace/public/pm/topbar.js +102 -0
  182. package/workspace/public/pm/triage-card.js +60 -0
  183. package/workspace/public/pm/undo-hold.js +103 -0
  184. package/workspace/public/pm/view-addrepo.js +2 -1
  185. package/workspace/public/pm/view-livenotes.js +3 -1
  186. package/workspace/public/pm/view-today.js +7 -162
  187. package/workspace/public/vendor/Sortable.min.js +2 -0
  188. package/workspace/public/vendor/lucide-sprite.js +79 -0
  189. package/workspace/replaced-tests.json +2877 -0
  190. package/workspace/run-tests.js +56 -5
  191. package/workspace/server.js +446 -40
  192. package/workspace/sheet-answer.js +61 -0
  193. package/workspace/skills/measure.skill +41 -0
  194. package/workspace/skills/morning-brief.skill +15 -9
  195. package/workspace/skills/report-biweekly.skill +23 -25
  196. package/workspace/skills/tracker-refresh.skill +50 -0
  197. package/workspace/test-files.json +21 -3
  198. package/workspace/test-lists/base.json +6 -0
  199. package/workspace/test-lists/run2-a.json +6 -0
  200. package/workspace/test-lists/run2-b.json +13 -0
  201. package/workspace/test-lists/run2-c.json +19 -0
  202. package/workspace/test-lists/run2-d.json +22 -0
  203. package/workspace/test-lists/run3-0.json +5 -0
  204. package/workspace/test-lists/run3-a.json +5 -0
  205. package/workspace/test-lists/run3-b.json +6 -0
  206. package/workspace/test-lists/run3-c.json +15 -0
  207. package/workspace/test-lists/run3-d.json +6 -0
  208. package/workspace/test-lists/run4-a.json +8 -0
  209. package/workspace/test-lists/run4-b.json +6 -0
  210. package/workspace/test-lists/run4-c.json +13 -0
  211. package/workspace/test-lists/run4-d.json +9 -0
  212. package/workspace/test-lists/run5-a.json +6 -0
  213. package/workspace/test-lists/run5-b.json +6 -0
  214. package/workspace/test-lists/run5-c.json +15 -0
  215. package/workspace/test-lists/workspace-launcher.json +5 -0
  216. package/workspace/test-lists/workspace-phone-app.json +5 -0
  217. package/workspace/test-run.js +27 -1
  218. package/workspace/third-party/README.md +44 -0
  219. package/workspace/third-party/lucide-static-1.52.0.LICENSE +43 -0
  220. package/workspace/third-party/sortablejs-1.15.7.LICENSE +21 -0
  221. package/workspace/design-parity.js +0 -673
  222. package/workspace/public/pm/tab-task.js +0 -86
  223. package/workspace/public/pm/view-guide.js +0 -141
  224. package/workspace/public/pm/view-knowledge.js +0 -225
  225. package/workspace/public/pm/view-memory.js +0 -122
  226. package/workspace/public/pm/view-portfolio.js +0 -153
  227. package/workspace/public/pm/view-reports.js +0 -190
  228. package/workspace/public/pm/view-scheduled.js +0 -161
  229. 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.52.0",
3
+ "version": "0.53.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.52.0",
3
+ "version": "0.53.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",
@@ -12,12 +12,11 @@
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",
22
21
  "test:changed": "node run-tests.js all --changed",
23
22
  "test:list-check": "node run-tests.js --check"
@@ -33,7 +32,7 @@
33
32
  "playwright-core": "^1.61.1",
34
33
  "ws": "^8.18.0"
35
34
  },
36
- "//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.",
37
36
  "devDependencies": {
38
37
  "pixelmatch": "^7.1.0",
39
38
  "pngjs": "^7.0.0"
@@ -3,7 +3,19 @@
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>
8
+ <!-- workspace-phone-app: Add to Home Screen. The manifest is fetched WITH credentials because over the
9
+ tailnet every request needs the session cookie, and a manifest fetch sends none by default. The
10
+ apple-* tags are what iOS reads instead of the manifest. "black" keeps the page below the status
11
+ bar; the top bar does not pad for a translucent one. -->
12
+ <link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials" />
13
+ <meta name="theme-color" content="#090b0c" />
14
+ <meta name="mobile-web-app-capable" content="yes" />
15
+ <meta name="apple-mobile-web-app-capable" content="yes" />
16
+ <meta name="apple-mobile-web-app-title" content="PMOS" />
17
+ <meta name="apple-mobile-web-app-status-bar-style" content="black" />
18
+ <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
7
19
  <!-- The terminal's face is preloaded, not left to be discovered. An @font-face is only fetched when
8
20
  something first RENDERS in it, which for Plex Mono is about the same moment a tab constructs
9
21
  the first xterm — and xterm measures its cell from whatever face is resolved at construction.
@@ -59,6 +71,12 @@
59
71
  file scripts/md-newlines.js requires, loaded here as window.MdNormalize, so the one-click
60
72
  repair and the CI ratchet can never disagree about what a normalized document is. -->
61
73
  <script src="/lib/md-normalize.js"></script>
74
+ <!-- pm-os-absorb: the words an initiative shows (R3), read from its derived ladder and never typed. The same file the
75
+ server and the report drafter require, loaded here as window.PMOSInitiativeDisplay. -->
76
+ <script src="/lib/initiative-display.js"></script>
77
+ <!-- pm-os-absorb: the dated bars of a breakdown (R20), one engine for both Timelines and the report strip, loaded here
78
+ as window.PMOSItemSpans. -->
79
+ <script src="/lib/item-spans.js"></script>
62
80
  <link rel="preload" href="/vendor/ibm-plex-mono-500.woff2" as="font" type="font/woff2" crossorigin />
63
81
  </head>
64
82
  <body>
@@ -71,13 +89,15 @@
71
89
  breakpoint this is absent from the accessibility tree rather than merely invisible: a desktop
72
90
  PM must not be able to tab into a second navigation system they cannot see. -->
73
91
 
74
- <!-- The top bar: back · the screen's name · the ⌘K jump palette · theme. It sits ABOVE .body in
92
+ <!-- The top bar: back · Repository · the screen's name · the ⌘K palette · Settings (the frame; the old shell shows its
93
+ brand and theme in place of Repository and Settings). It sits ABOVE .body in
75
94
  DOM order because it is the row above the content on screen, and putting it beside the bottom
76
95
  nav would read the app backwards. -->
77
96
  <div class="mob" id="mobShell" hidden>
78
97
  <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>
98
+ <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>
99
+ <span class="mob-brand" id="mobBrand" aria-hidden="true">PMOS</span>
100
+ <button class="mob-repo" id="mobRepo" type="button" hidden aria-haspopup="menu">Repository</button>
81
101
  <span class="mob-title" id="mobTitle"></span>
82
102
  <!-- The jump palette lives HERE, not in the control bar below. Two reasons, and the second is
83
103
  the binding one: it is not a terminal control key (every other button in the bar writes a
@@ -87,32 +107,33 @@
87
107
  palette is a jump control for every destination, so it belongs in the bar that is always
88
108
  on screen. -->
89
109
  <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>
110
+ <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>
111
+ <button class="mob-sync" id="mobSync" type="button" hidden>Sync</button>
112
+ <button class="mob-set" id="mobSettings" type="button" hidden aria-current="false">Settings</button>
91
113
  </header>
92
114
  </div>
93
115
 
94
116
  <!-- 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 (◧ ◔ ◐ ◒ ☰). -->
117
+ Esc/Tab/Ctrl/arrows) over the five tabs (pm-os-absorb Run 3, slice 3A): Today · Initiatives · Board · Reports ·
118
+ Agent. The first four are the frame's places; Agent is the dock with its live terminals. The nav is a <nav> of
119
+ buttons carrying aria-current, NOT a tablist: there is no tabpanel to point at. Selecting a tab resets it to its
120
+ root; depth is pushed on top of it and #mobBack pops one screen. Words, not glyphs, name each tab. -->
100
121
  <div class="mobmenu" id="mobMenu" hidden>
101
122
  <div class="ctrlbar" id="ctrlBar" role="toolbar" aria-label="Terminal control keys">
102
123
  <button type="button" data-seq="esc" aria-label="Escape"><span class="lbl">esc</span></button>
103
124
  <button type="button" data-seq="tab" aria-label="Tab"><span class="lbl">tab</span></button>
104
125
  <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>
126
+ <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>
127
+ <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>
128
+ <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>
129
+ <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
130
  </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>
131
+ <nav class="mobnav" id="mobNav" aria-label="Destinations">
132
+ <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>
133
+ <button type="button" class="mobnav-b" data-dest="initiatives" aria-current="false"><span class="l">Initiatives</span></button>
134
+ <button type="button" class="mobnav-b" data-dest="board" aria-current="false"><span class="l">Board</span></button>
135
+ <button type="button" class="mobnav-b" data-dest="reports" aria-current="false"><span class="l">Reports</span></button>
136
+ <button type="button" class="mobnav-b" data-dest="agent" aria-current="false"><span class="l">Agent</span></button>
116
137
  </nav>
117
138
  </div>
118
139