create-pmos 0.22.0 → 0.23.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pmos-workspace",
9
- "version": "0.22.0",
9
+ "version": "0.23.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@xterm/addon-fit": "^0.11.0",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "pmos-workspace",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "private": true,
5
- "description": "PMOS Terminal Workspace \u2014 local companion hosting real PTYs beside the library and gates (D62)",
5
+ "description": "PMOS Terminal Workspace — local companion hosting real PTYs beside the library and gates (D62)",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "pmos": "bin/pmos.js"
@@ -29,7 +29,7 @@
29
29
  "playwright-core": "^1.61.1",
30
30
  "ws": "^8.18.0"
31
31
  },
32
- "//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 \u2014 it just stops measuring pixels, and says so.",
32
+ "//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.",
33
33
  "devDependencies": {
34
34
  "pixelmatch": "^7.1.0",
35
35
  "pngjs": "^7.0.0"
@@ -922,71 +922,58 @@ function library(root) {
922
922
  // ("— not tracked"), never invented (D14/D40 honesty).
923
923
  const PHASE_OF = { planning: 'plan', building: 'deliver', blocked: 'deliver', delivered: 'report', accepted: 'report', unknown: 'plan' };
924
924
 
925
- // ── Delivery evidence (board-delivery-truth R-2/R-3). ──────────────────────────────────────────
925
+ // ── Delivery evidence (board-delivery-truth R-2/R-3; shared reader, workflow-status-sweep R-1). ──
926
926
  // "Has this shipped?" answered from the trunk's own history rather than from anything anyone typed.
927
927
  //
928
- // ONE `git log` per trunk head, memoised on that sha — ~0.3s and ~800 KB on this repo's 1,214
929
- // commits, paid once and reused by every surface until the trunk moves. Local only: git reads the
930
- // object store on disk, so the suite's "no network" guarantee (K. Surfaces) is untouched.
928
+ // THIS DERIVATION NO LONGER LIVES HERE. It was module-private to this file, which meant the GUI's
929
+ // initiative board answered the question with attribution while the engine's ladder
930
+ // (`scripts/workflow-state.js`) answered it without any — `buildCommits` counted every build commit
931
+ // in a range with no idea which initiative it was answering about, and over the trunk reported the
932
+ // same 488 commits as evidence for all 177 initiatives. Two readers, one repository, different
933
+ // answers to "did this ship". `scripts/delivery-index.js` is now the single reader, in the same
934
+ // shape and for the same reason as `scripts/anchor-resolve.js`; its header carries the two-signal
935
+ // rationale that used to be written here.
931
936
  //
932
- // TWO signals, because one is not enough. The branch convention (`initiative/<id>`) is precise but
933
- // incomplete: 31% of this repo's merged PRs shipped on `claude/*` branches, which match no id. So a
934
- // commit that MENTIONS the id and TOUCHES a build path counts too. The build-path requirement is
935
- // what keeps the mention signal honest — `feat(planning): add <id> PRD` mentions the id while
936
- // delivering nothing, and without the path test every specified initiative would read as shipped.
937
- const BUILD_EXCLUDE = /^(planning|okf|prototype)\//;
938
- function isDeliveryPath(f) {
939
- if (!f) return false;
940
- if (BUILD_EXCLUDE.test(f)) return false;
941
- return !/^[^/]+\.md$/.test(f); // root governance prose (DECISIONS.md, CLAUDE.md…) is not a build
942
- }
943
- const deliveryCache = new Map(); // root -> { head, index }
944
- function trunkRef(root) {
945
- for (const c of ['origin/main', 'main', 'origin/master', 'master']) {
946
- const r = gitCap(root, ['rev-parse', '--verify', '--quiet', c]);
947
- if (r.ok && r.out.trim()) return { ref: c, head: r.out.trim() };
937
+ // Resolution follows the ANCHOR_LIB_PATHS pattern below: a repo checkout first (so a dev surface and
938
+ // CI cannot disagree), then the copy `scripts/vendor-workspace-engine.js` vendors into the bundle.
939
+ // The engine requires this module, so it is already inside the vendored closure — an adopter's
940
+ // install carries it without a second packaging step to remember.
941
+ const DELIVERY_LIB_PATHS = [
942
+ path.join(__dirname, '..', 'scripts', 'delivery-index.js'),
943
+ path.join(__dirname, 'lib', 'engine', 'delivery-index.js'),
944
+ ];
945
+ function deliveryLib() {
946
+ for (const p of DELIVERY_LIB_PATHS) {
947
+ if (!fs.existsSync(p)) continue;
948
+ try { return require(p); } catch { return null; }
948
949
  }
949
950
  return null;
950
951
  }
951
- function gitCap(root, args) {
952
- try {
953
- const r = spawnSync('git', args, { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
954
- if (r.error || r.status !== 0) return { ok: false, out: '', err: (r.stderr || (r.error && r.error.message) || '').trim() };
955
- return { ok: true, out: r.stdout || '' };
956
- } catch (e) { return { ok: false, out: '', err: String((e && e.message) || e) }; }
952
+ function isDeliveryPath(f) {
953
+ const D = deliveryLib();
954
+ // Absent library → no path can be CONFIRMED as a delivery path. Returning `true` here would let
955
+ // every commit count as delivery evidence in exactly the install where the evidence cannot be
956
+ // read, which is the false-green direction. `deliveryIndex` below reports the absence out loud.
957
+ return D ? D.isDeliveryPath(f) : false;
957
958
  }
958
959
  /**
959
960
  * → { ok, reason?, byBranch:Set<id>, byMention:Set<id> }
960
961
  * `ok:false` is a REAL answer and never degrades into "nothing was delivered" — the caller renders
961
962
  * it red and marks every initiative's delivery `unknown` (R-3). A board that cannot read the
962
963
  * history must say so; silently reporting `planning` for 110 shipped initiatives is the failure
963
- * this whole initiative exists to remove.
964
+ * this whole initiative exists to remove. A missing library is the same class of answer as an
965
+ * unreadable history and takes the same `ok:false` path.
964
966
  */
965
967
  function deliveryIndex(root, ids) {
966
- const t = trunkRef(root);
967
- if (!t) return { ok: false, reason: 'no trunk branch (main/master) is reachable from this repository — delivery cannot be derived', byBranch: new Set(), byMention: new Set() };
968
- const hit = deliveryCache.get(root);
969
- if (hit && hit.head === t.head) return hit.index;
970
-
971
- // %x1e separates commits, %x1f separates the message from --name-only's file list.
972
- const r = gitCap(root, ['log', '--format=%x1e%s %b%x1f', '--name-only', t.head]);
973
- if (!r.ok) {
974
- return { ok: false, reason: `git could not read the history at ${t.ref}${r.err ? ` — ${r.err}` : ''}`, byBranch: new Set(), byMention: new Set() };
975
- }
976
- const byBranch = new Set(), byMention = new Set();
977
- const known = Array.isArray(ids) ? ids : [...ids];
978
- for (const chunk of r.out.split('\x1e')) {
979
- if (!chunk.trim()) continue;
980
- const cut = chunk.indexOf('\x1f');
981
- const msg = cut < 0 ? chunk : chunk.slice(0, cut);
982
- const files = cut < 0 ? [] : chunk.slice(cut + 1).split('\n').map((s) => s.trim()).filter(Boolean);
983
- for (const m of msg.matchAll(/initiative\/([A-Za-z0-9][\w.-]*)/g)) byBranch.add(m[1]);
984
- if (!files.some(isDeliveryPath)) continue;
985
- for (const id of known) if (id.length > 3 && msg.includes(id)) byMention.add(id);
986
- }
987
- const index = { ok: true, byBranch, byMention };
988
- deliveryCache.set(root, { head: t.head, index });
989
- return index;
968
+ const D = deliveryLib();
969
+ if (!D) {
970
+ return {
971
+ ok: false,
972
+ reason: 'the delivery reader (scripts/delivery-index.js) is not present in this install — delivery cannot be derived here',
973
+ byBranch: new Set(), byMention: new Set(),
974
+ };
975
+ }
976
+ return D.deliveryIndex(root, ids);
990
977
  }
991
978
  /**
992
979
  * The five states, in precedence order. Every one of them names the artifact it was read from, so