openplanr 3.0.0 → 3.0.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 (50) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/cli/commands/upgrade.d.ts.map +1 -1
  3. package/dist/cli/commands/upgrade.js +4 -2
  4. package/dist/cli/commands/upgrade.js.map +1 -1
  5. package/dist/dashboard/.vite/manifest.json +1 -1
  6. package/dist/dashboard/assets/{index-Csby7_ur.js → index-n08LJ6bK.js} +2 -2
  7. package/dist/dashboard/assets/{index-Csby7_ur.js.map → index-n08LJ6bK.js.map} +1 -1
  8. package/dist/dashboard/dashboard-manifest.json +8 -8
  9. package/dist/dashboard/index.html +1 -1
  10. package/dist/services/claude-plugin-service.d.ts +9 -0
  11. package/dist/services/claude-plugin-service.d.ts.map +1 -1
  12. package/dist/services/claude-plugin-service.js +12 -0
  13. package/dist/services/claude-plugin-service.js.map +1 -1
  14. package/dist/services/upgrade-report.d.ts.map +1 -1
  15. package/dist/services/upgrade-report.js +5 -2
  16. package/dist/services/upgrade-report.js.map +1 -1
  17. package/dist/services/upgrade-service.d.ts +14 -0
  18. package/dist/services/upgrade-service.d.ts.map +1 -1
  19. package/dist/services/upgrade-service.js +66 -10
  20. package/dist/services/upgrade-service.js.map +1 -1
  21. package/lib/host-packages/adapter-registry.json +5 -5
  22. package/lib/host-packages/capability-map.json +1 -1
  23. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  24. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  25. package/lib/host-packages/claude/openplanr/.openplanr-content.json +9 -9
  26. package/lib/host-packages/claude/openplanr/README.md +1 -1
  27. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  28. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  29. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  30. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +4 -4
  31. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  32. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  33. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +8 -8
  34. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  35. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  36. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  37. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  38. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +4 -4
  39. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  40. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  41. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  42. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  43. package/lib/host-packages/openai/openplanr/.openplanr-content.json +8 -8
  44. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  45. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  46. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  47. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +4 -4
  48. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +5 -1
  49. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +5 -1
  50. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/design",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Canonical OpenPlanr design helpers and design-loop engine",
@@ -46,8 +46,8 @@
46
46
  "node": ">=22.13.0"
47
47
  },
48
48
  "dependencies": {
49
- "@openplanr/artifact": "0.6.6",
50
- "@openplanr/protocol": "0.11.0"
49
+ "@openplanr/artifact": "0.6.7",
50
+ "@openplanr/protocol": "0.12.0"
51
51
  },
52
52
  "scripts": {
53
53
  "test": "node --test --test-concurrency=2 tests/*.test.mjs",
@@ -32,6 +32,34 @@
32
32
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("rect", { x: "127", y: "71", width: "18", height: "18", rx: "3", fill: "currentColor" })
33
33
  ] }) }) });
34
34
  }
35
+ function inlineGap(element) {
36
+ const view = element?.ownerDocument.defaultView;
37
+ return view && element ? parseFloat(view.getComputedStyle(element).gap) || 0 : 0;
38
+ }
39
+ function measureLeadingFloor(leading) {
40
+ const view = leading.ownerDocument.defaultView;
41
+ if (!view) return 128;
42
+ const leadingControls = [...leading.children].filter(
43
+ (node) => node instanceof view.HTMLElement && !node.classList.contains("planr-brand") && node.getClientRects().length > 0
44
+ );
45
+ const branding = [
46
+ ...leading.querySelectorAll(".planr-mark,.design-wordmark")
47
+ ].filter((node) => node.getClientRects().length);
48
+ const brandGap = inlineGap(leading.querySelector(".planr-brand"));
49
+ const brandingWidth = branding.reduce(
50
+ (total, node) => total + node.getBoundingClientRect().width + brandGap,
51
+ 0
52
+ );
53
+ const titleBlock = leading.querySelector(".planr-title-block");
54
+ const badge = titleBlock?.querySelector(".studio-type-badge");
55
+ const title = titleBlock?.querySelector("strong,.de-title");
56
+ const titleFloor = Math.max(36, parseFloat(view.getComputedStyle(title ?? leading).fontSize) * 3);
57
+ const identityFloor = Math.max(
58
+ 128,
59
+ (badge?.getBoundingClientRect().width || 0) + inlineGap(titleBlock) + titleFloor
60
+ );
61
+ return identityFloor + brandingWidth + leadingControls.reduce((total, control) => total + control.getBoundingClientRect().width, 0) + leadingControls.length * inlineGap(leading);
62
+ }
35
63
  function StudioToolbar({
36
64
  title,
37
65
  titleNode,
@@ -44,6 +72,7 @@
44
72
  viewPicker,
45
73
  status,
46
74
  actions,
75
+ secondaryActions,
47
76
  className = ""
48
77
  }) {
49
78
  const toolbar = (0, import_react3.useRef)(null);
@@ -54,6 +83,7 @@
54
83
  const center = element.querySelector(".studio-toolbar-center");
55
84
  const trailing = element.querySelector(".studio-toolbar-trailing");
56
85
  const leading2 = element.querySelector(".studio-toolbar-leading");
86
+ const secondary = element.querySelector(".studio-toolbar-secondary");
57
87
  if (!center || !trailing || !leading2) return;
58
88
  const measure = () => {
59
89
  const width = element.getBoundingClientRect().width;
@@ -61,24 +91,28 @@
61
91
  element.dataset.studioDensity = width <= 680 ? "narrow" : "regular";
62
92
  const style = window2.getComputedStyle(element);
63
93
  const available = width - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
64
- const gap = parseFloat(style.columnGap) || 0;
94
+ const gap = Math.max(12, parseFloat(style.columnGap) || 0);
65
95
  element.dataset.studioCenter = "true";
66
96
  const centerWidth = center.scrollWidth;
67
97
  element.dataset.studioCenter = String(centerWidth > 0);
68
98
  const controlSelector = 'button,a,summary,input,select,output,[role="status"]';
69
- const controls = [...trailing.querySelectorAll(controlSelector)].filter(
99
+ const controls = [
100
+ ...trailing.querySelectorAll(controlSelector),
101
+ ...secondary?.querySelectorAll(controlSelector) ?? []
102
+ ].filter(
70
103
  (control) => control.getClientRects().length && !control.closest('[role="menu"],.studio-tooltip,[role="dialog"]') && (!control.closest("details") || !!control.closest("summary")) && !control.parentElement?.closest(controlSelector)
71
104
  );
72
- const actionWidth = controls.reduce((total, control) => total + control.getBoundingClientRect().width, 0) + Math.max(0, controls.length - 1) * (parseFloat(window2.getComputedStyle(trailing).gap) || 8);
73
- const leadingControl = leading2.firstElementChild;
74
- const branding = [
75
- ...leading2.querySelectorAll(".planr-mark,.design-wordmark")
76
- ].filter((node) => node.getClientRects().length);
77
- const brandingWidth = branding.reduce(
78
- (total, node) => total + node.getBoundingClientRect().width + 8,
79
- 0
80
- );
81
- const leadingFloor = 128 + brandingWidth + (leadingControl instanceof window2.HTMLElement && !leadingControl.classList.contains("planr-brand") ? leadingControl.getBoundingClientRect().width + 8 : 0);
105
+ const actionWidth = controls.reduce((total, control) => {
106
+ if (secondary?.contains(control) && control.getAttribute("role") === "status") {
107
+ const range = element.ownerDocument.createRange();
108
+ range.selectNodeContents(control);
109
+ const textWidth = range.getBoundingClientRect().width;
110
+ const controlStyle = window2.getComputedStyle(control);
111
+ return total + textWidth + (parseFloat(controlStyle.paddingLeft) || 0) + (parseFloat(controlStyle.paddingRight) || 0);
112
+ }
113
+ return total + control.getBoundingClientRect().width;
114
+ }, 0) + Math.max(0, controls.length - 1) * (parseFloat(window2.getComputedStyle(trailing).gap) || 8);
115
+ const leadingFloor = measureLeadingFloor(leading2);
82
116
  const outerWidth = Math.max(leadingFloor, actionWidth);
83
117
  element.dataset.studioLayout = centerWidth > 0 ? width <= 680 || centerWidth + outerWidth * 2 + gap * 2 > available ? "compact" : "inline" : leadingFloor + actionWidth + gap > available ? "compact" : "inline";
84
118
  };
@@ -92,7 +126,7 @@
92
126
  });
93
127
  };
94
128
  const resize = typeof window2.ResizeObserver === "function" ? new window2.ResizeObserver(scheduleMeasure) : null;
95
- for (const node of [element, center, trailing]) resize?.observe(node);
129
+ for (const node of [element, center, trailing, secondary]) if (node) resize?.observe(node);
96
130
  const mutations = new window2.MutationObserver(scheduleMeasure);
97
131
  mutations.observe(element, {
98
132
  subtree: true,
@@ -150,7 +184,8 @@
150
184
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "studio-toolbar-trailing design-toolbar-trailing", children: [
151
185
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "studio-toolbar-status", children: status }),
152
186
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "studio-toolbar-actions", children: actions })
153
- ] })
187
+ ] }),
188
+ secondaryActions && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "studio-toolbar-secondary", children: secondaryActions })
154
189
  ]
155
190
  }
156
191
  );
@@ -164,49 +199,106 @@
164
199
  onOpenChange
165
200
  }) {
166
201
  const trigger = (0, import_react3.useRef)(null);
167
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(dist_exports5.Root, { modal: false, open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: `studio-menu ${className}`, children: [
168
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(dist_exports5.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(StudioButton, { "aria-label": label, title: label, ...triggerAttributes, ref: trigger, children: [
169
- label,
170
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": "true", children: "⌄" })
171
- ] }) }),
172
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
173
- dist_exports5.Content,
174
- {
175
- className: "studio-menu-content",
176
- align: "end",
177
- sideOffset: 8,
178
- collisionPadding: 8,
179
- onCloseAutoFocus: (event) => {
180
- event.preventDefault();
181
- const content = event.target;
182
- const ownerDocument = content?.ownerDocument;
183
- const active = ownerDocument?.activeElement;
184
- if (active?.isConnected && active !== ownerDocument?.body && active !== ownerDocument?.documentElement && !content?.contains(active))
185
- return;
186
- if (trigger.current?.isConnected) trigger.current.focus();
187
- },
188
- children: items.map((item, index2) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
189
- dist_exports5.Item,
202
+ const mousePosition = (0, import_react3.useRef)(null);
203
+ const keyboardPosition = (0, import_react3.useRef)(null);
204
+ (0, import_react3.useLayoutEffect)(() => {
205
+ const ownerDocument = trigger.current?.ownerDocument;
206
+ if (!ownerDocument) return;
207
+ const move = (event) => {
208
+ if (event.pointerType !== "mouse") return;
209
+ const position = { x: event.clientX, y: event.clientY };
210
+ const previous = keyboardPosition.current;
211
+ if (previous && (previous.x !== position.x || previous.y !== position.y))
212
+ keyboardPosition.current = null;
213
+ mousePosition.current = position;
214
+ };
215
+ const down = (event) => {
216
+ keyboardPosition.current = null;
217
+ if (event.pointerType === "mouse")
218
+ mousePosition.current = { x: event.clientX, y: event.clientY };
219
+ };
220
+ ownerDocument.addEventListener("pointermove", move, true);
221
+ ownerDocument.addEventListener("pointerdown", down, true);
222
+ return () => {
223
+ ownerDocument.removeEventListener("pointermove", move, true);
224
+ ownerDocument.removeEventListener("pointerdown", down, true);
225
+ };
226
+ }, []);
227
+ const retainKeyboardFocus = (event) => {
228
+ const position = keyboardPosition.current;
229
+ if (event.pointerType === "mouse" && position?.x === event.clientX && position.y === event.clientY)
230
+ event.preventDefault();
231
+ };
232
+ const keyboardInput = () => {
233
+ keyboardPosition.current = mousePosition.current;
234
+ };
235
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
236
+ dist_exports5.Root,
237
+ {
238
+ modal: false,
239
+ open,
240
+ onOpenChange: (value) => {
241
+ if (!value) keyboardPosition.current = null;
242
+ onOpenChange?.(value);
243
+ },
244
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: `studio-menu ${className}`, children: [
245
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(dist_exports5.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
246
+ StudioButton,
190
247
  {
191
- asChild: true,
192
- disabled: item.disabled,
193
- onSelect: item.onSelect,
194
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
195
- "button",
248
+ "aria-label": label,
249
+ title: label,
250
+ ...triggerAttributes,
251
+ ref: trigger,
252
+ onKeyDownCapture: keyboardInput,
253
+ children: [
254
+ label,
255
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": "true", children: "⌄" })
256
+ ]
257
+ }
258
+ ) }),
259
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
260
+ dist_exports5.Content,
261
+ {
262
+ className: "studio-menu-content",
263
+ align: "end",
264
+ sideOffset: 8,
265
+ collisionPadding: 8,
266
+ onKeyDownCapture: keyboardInput,
267
+ onCloseAutoFocus: (event) => {
268
+ event.preventDefault();
269
+ const content = event.target;
270
+ const ownerDocument = content?.ownerDocument;
271
+ const active = ownerDocument?.activeElement;
272
+ if (active?.isConnected && active !== ownerDocument?.body && active !== ownerDocument?.documentElement && !content?.contains(active))
273
+ return;
274
+ if (trigger.current?.isConnected) trigger.current.focus();
275
+ },
276
+ children: items.map((item, index2) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
277
+ dist_exports5.Item,
196
278
  {
197
- type: "button",
198
- className: `studio-menu-item${index2 > 0 && item.group !== items[index2 - 1].group ? " studio-menu-group-start" : ""}`,
279
+ asChild: true,
199
280
  disabled: item.disabled,
200
- ...item.attributes,
201
- children: item.label
202
- }
203
- )
204
- },
205
- item.id
206
- ))
207
- }
208
- )
209
- ] }) });
281
+ onSelect: item.onSelect,
282
+ onPointerMove: retainKeyboardFocus,
283
+ onPointerLeave: retainKeyboardFocus,
284
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
285
+ "button",
286
+ {
287
+ type: "button",
288
+ className: `studio-menu-item${index2 > 0 && item.group !== items[index2 - 1].group ? " studio-menu-group-start" : ""}`,
289
+ disabled: item.disabled,
290
+ ...item.attributes,
291
+ children: item.label
292
+ }
293
+ )
294
+ },
295
+ item.id
296
+ ))
297
+ }
298
+ )
299
+ ] })
300
+ }
301
+ );
210
302
  }
211
303
  function StudioPanelDialog({
212
304
  open,
@@ -2,8 +2,8 @@
2
2
  "kind": "openplanr-runtime-asset-sources",
3
3
  "schemaVersion": "1.0.0",
4
4
  "asset": "studio.js",
5
- "bytes": 1142078,
6
- "sha256": "b8688a3102c5028847fc9a1d4a257b096768de1db3b4bfd4656482d318013c71",
5
+ "bytes": 1146075,
6
+ "sha256": "f649b59fe0a31ec9055d6e5bf5b68425c1fe4e996224c35603d84f91021949cf",
7
7
  "scopes": [
8
8
  {
9
9
  "id": "bundle",
@@ -238,8 +238,8 @@
238
238
  "packages/artifact/lib/artifact/ui/studio-shell-components.mjs",
239
239
  "packages/artifact/lib/artifact/ui/studio-shell-mount-impl.mjs"
240
240
  ],
241
- "bytes": 23280,
242
- "sha256": "5306387b1f59d43e1cd0ed2c471b18b0b35d5cc8c573ffe5439ea9315494c01e"
241
+ "bytes": 27277,
242
+ "sha256": "81af29a6a5a15fd4f0ef41fc48e1eca63c30b3745fd1d92830ba83f7cf2ba603"
243
243
  },
244
244
  {
245
245
  "path": "studio.js.sources/17-design-studio.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -115,6 +115,10 @@
115
115
  "./sharing-security-contracts": {
116
116
  "types": "./src/sharing-security-contracts.d.mts",
117
117
  "import": "./src/sharing-security-contracts.mjs"
118
+ },
119
+ "./enterprise-journey-contracts": {
120
+ "types": "./src/enterprise-journey-contracts.d.mts",
121
+ "import": "./src/enterprise-journey-contracts.mjs"
118
122
  }
119
123
  },
120
124
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -115,6 +115,10 @@
115
115
  "./sharing-security-contracts": {
116
116
  "types": "./src/sharing-security-contracts.d.mts",
117
117
  "import": "./src/sharing-security-contracts.mjs"
118
+ },
119
+ "./enterprise-journey-contracts": {
120
+ "types": "./src/enterprise-journey-contracts.d.mts",
121
+ "import": "./src/enterprise-journey-contracts.mjs"
118
122
  }
119
123
  },
120
124
  "files": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openplanr",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "Deterministic OpenPlanr utilities for planning storage, validation, rendering, setup, diagnostics, and GitHub/Linear synchronization",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",
@@ -108,13 +108,13 @@
108
108
  "@napi-rs/keyring": "^1.2.0",
109
109
  "chalk": "^5.3.0",
110
110
  "commander": "^14.0.3",
111
- "handlebars": "^4.7.9",
111
+ "handlebars": "4.7.10",
112
112
  "smol-toml": "1.9.0",
113
113
  "yaml": "^2.8.3",
114
114
  "zod": "^4.3.6"
115
115
  },
116
116
  "optionalDependencies": {
117
- "planr-pipeline": "0.58.0"
117
+ "planr-pipeline": "0.59.0"
118
118
  },
119
119
  "devDependencies": {
120
120
  "@biomejs/biome": "^2.4.9",