create-pmos 0.65.2 → 0.65.3

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.65.2",
3
+ "version": "0.65.3",
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@cc06cf0
1
+ kernel-source: pmos@bc7453c
2
2
  assembled: 2026-10-07
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-07T01:20:37Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-07T01:27:56Z"}
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-07T01:20:37Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-07T01:27:56Z"}
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-07T01:20:37Z"}
5
+ generated: {by: process:create-pmos, at: "2026-10-07T01:27:56Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -119,7 +119,7 @@ Every row has a visible ⋯ button. Every control is at least 44 pixels high. No
119
119
 
120
120
  You can have the same session open on your phone and your computer. A session has one size, so the screen you type in or tap last sets it. The other screen keeps showing the session and takes the size back as soon as you type in it.
121
121
 
122
- On an iPhone or an iPad, the terminal gets smaller when the keyboard opens, so the agent's prompt stays above the keyboard. Tapping the terminal does not zoom the page, and dragging at its top or bottom does not pull or reload the page. A swipe from the left edge of the screen is Safari's Back gesture and leaves the workspace. To avoid that, add the workspace to your Home Screen and open it from there.
122
+ On an iPhone or an iPad, the terminal gets smaller when the keyboard opens, so the agent's prompt stays above the keyboard. Tapping the terminal does not zoom the page, and dragging at its top or bottom does not pull or reload the page. Swipe up or down on the terminal to scroll it, also inside Claude Code or any other program that uses the mouse. A swipe from the left edge of the screen is Safari's Back gesture and leaves the workspace. To avoid that, add the workspace to your Home Screen and open it from there.
123
123
 
124
124
  ## The older layout
125
125
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.65.2",
3
+ "version": "0.65.3",
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.65.2",
3
+ "version": "0.65.3",
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",
@@ -915,9 +915,78 @@ function buildReal(tab) {
915
915
  rec.ro = new ResizeObserver(() => refitVisible());
916
916
  try { rec.ro.observe(host); } catch { /* ignore */ }
917
917
  }
918
+ touchScroll(rec);
918
919
  return rec;
919
920
  }
920
921
 
922
+ /* ── a swipe scrolls ───────────────────────────────────────────────────────────────────────────
923
+ * xterm scrolls on a touch drag only while no program has asked for the mouse. A program that has
924
+ * (Claude Code, tmux, an editor) gets nothing from a swipe, because xterm ignores touch then and a
925
+ * touch is not a wheel. On an iPhone or iPad a swipe was therefore dead in exactly the sessions
926
+ * that matter. A vertical drag on the pane is turned into wheel events instead, and xterm does with
927
+ * them what it does with a mouse wheel: it scrolls its own scrollback, or it reports the wheel to
928
+ * the program that asked for the mouse, or it sends arrow keys in a full-screen program that did
929
+ * not. The finger's speed carries on for a moment after it lifts, as a native scroll does. A tap
930
+ * is left alone, so it still focuses the terminal and raises the keyboard. */
931
+ const TOUCH_SLOP = 6; // px a finger moves before a touch is a swipe rather than a tap
932
+ const MOMENTUM_DECAY = 0.95; // the carried speed kept per frame after the finger lifts
933
+
934
+ function touchScroll(rec) {
935
+ const { host, term } = rec;
936
+ let t = null; // the swipe in progress: { x, y, lastY, lastT, v, swiping }
937
+ let glide = 0; // the momentum frame, if one is queued
938
+
939
+ const wheel = (dy, x, y) => {
940
+ const target = (term.element && term.element.querySelector('.xterm-screen')) || term.element;
941
+ if (!target || !dy) return;
942
+ target.dispatchEvent(new WheelEvent('wheel', {
943
+ deltaY: dy, deltaMode: 0, clientX: x, clientY: y, bubbles: true, cancelable: true,
944
+ }));
945
+ };
946
+ const stopGlide = () => { if (glide) { cancelAnimationFrame(glide); glide = 0; } };
947
+
948
+ host.addEventListener('touchstart', (e) => {
949
+ stopGlide();
950
+ if (e.touches.length !== 1) { t = null; return; }
951
+ const p = e.touches[0];
952
+ t = { x: p.clientX, y: p.clientY, lastY: p.clientY, lastT: e.timeStamp, v: 0, swiping: false };
953
+ }, { capture: true, passive: true });
954
+
955
+ host.addEventListener('touchmove', (e) => {
956
+ if (!t || e.touches.length !== 1) return;
957
+ const p = e.touches[0];
958
+ if (!t.swiping) {
959
+ const dx = p.clientX - t.x, dy = p.clientY - t.y;
960
+ if (Math.abs(dy) < TOUCH_SLOP || Math.abs(dy) < Math.abs(dx)) return;
961
+ t.swiping = true;
962
+ }
963
+ // Ours from here: xterm's own touch handling and the page's scroll do not also see it.
964
+ e.preventDefault();
965
+ e.stopPropagation();
966
+ const dy = t.lastY - p.clientY; // finger up = content up = wheel down
967
+ const dt = Math.max(1, e.timeStamp - t.lastT);
968
+ t.v = 0.8 * (dy / dt) + 0.2 * t.v;
969
+ t.lastY = p.clientY; t.lastT = e.timeStamp;
970
+ wheel(dy, p.clientX, p.clientY);
971
+ }, { capture: true, passive: false });
972
+
973
+ const end = () => {
974
+ if (!t || !t.swiping) { t = null; return; }
975
+ let v = t.v * 16; // px per frame
976
+ const x = t.x, y = t.lastY;
977
+ t = null;
978
+ const step = () => {
979
+ v *= MOMENTUM_DECAY;
980
+ if (Math.abs(v) < 0.5) { glide = 0; return; }
981
+ wheel(v, x, y);
982
+ glide = requestAnimationFrame(step);
983
+ };
984
+ if (Math.abs(v) >= 0.5) glide = requestAnimationFrame(step);
985
+ };
986
+ host.addEventListener('touchend', end, { capture: true, passive: true });
987
+ host.addEventListener('touchcancel', end, { capture: true, passive: true });
988
+ }
989
+
921
990
  /* ── the exported surface ──────────────────────────────────────────────────────────────────── */
922
991
 
923
992
  /**