slidemind 0.3.20 → 0.4.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 (185) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/AGENTS.md +591 -15
  4. package/README.md +202 -7
  5. package/bin/slidemind.mjs +50 -2
  6. package/package.json +2 -2
  7. package/skills/create-slides/SKILL.md +484 -886
  8. package/skills/search/SKILL.md +46 -23
  9. package/src/bridge/build-and-push.mjs +548 -73
  10. package/src/bridge/bundle.mjs +100 -31
  11. package/src/bridge/capture.mjs +14 -17
  12. package/src/bridge/client/brands.mjs +157 -18
  13. package/src/bridge/client/engine-routing.mjs +48 -13
  14. package/src/bridge/client/engine-search.mjs +24 -1
  15. package/src/bridge/client/render.mjs +27 -1
  16. package/src/bridge/client/transport.mjs +499 -23
  17. package/src/bridge/client.mjs +10 -0
  18. package/src/bridge/config.mjs +67 -6
  19. package/src/bridge/engine-download.mjs +0 -10
  20. package/src/bridge/graph-auth.mjs +55 -3
  21. package/src/bridge/image-intent-envelope.mjs +239 -0
  22. package/src/bridge/package-preview.mjs +67 -0
  23. package/src/bridge/sharepoint.mjs +914 -0
  24. package/src/builders/asset-fetch.mjs +203 -0
  25. package/src/builders/block-dividers.mjs +83 -0
  26. package/src/builders/build.mjs +171 -87
  27. package/src/builders/card-height.mjs +294 -0
  28. package/src/builders/chart-hole.mjs +183 -0
  29. package/src/builders/chart-jsx.mjs +410 -0
  30. package/src/builders/chart-labels.mjs +326 -0
  31. package/src/builders/concept-geometry.mjs +370 -0
  32. package/src/builders/concept-intent.mjs +200 -0
  33. package/src/builders/concept-layout.mjs +79 -0
  34. package/src/builders/concept-lines.mjs +509 -0
  35. package/src/builders/concept-lists.mjs +270 -0
  36. package/src/builders/concept-marks.mjs +84 -0
  37. package/src/builders/concept-relationships.mjs +12 -0
  38. package/src/builders/concept-spec.mjs +645 -0
  39. package/src/builders/concept-text.mjs +140 -0
  40. package/src/builders/concept-waves.mjs +57 -0
  41. package/src/builders/copy-fit.mjs +139 -0
  42. package/src/builders/design-tokens.mjs +347 -0
  43. package/src/builders/draft-check.mjs +552 -340
  44. package/src/builders/draft-lines.mjs +369 -0
  45. package/src/builders/edit-route.mjs +29 -0
  46. package/src/builders/figure-sketch.mjs +375 -0
  47. package/src/builders/fold-sets.mjs +639 -0
  48. package/src/builders/gate-server.mjs +9 -4
  49. package/src/builders/gate-session.js +273 -12
  50. package/src/builders/gate-shell.js +1494 -0
  51. package/src/builders/image-intent-check.mjs +308 -0
  52. package/src/builders/image-use-reconcile.mjs +107 -0
  53. package/src/builders/kit-helpers.mjs +121 -0
  54. package/src/builders/layout-names.mjs +32 -0
  55. package/src/builders/legacy-reference-uses.mjs +179 -0
  56. package/src/builders/line-fit.mjs +224 -0
  57. package/src/builders/line-native.mjs +895 -0
  58. package/src/builders/line-relations.mjs +230 -0
  59. package/src/builders/lint-fix.mjs +117 -9
  60. package/src/builders/lint.mjs +25 -20
  61. package/src/builders/list-jsx.mjs +88 -0
  62. package/src/builders/placement.mjs +133 -0
  63. package/src/builders/plan-checks.mjs +135 -0
  64. package/src/builders/plan-comments.mjs +19 -0
  65. package/src/builders/plan-handlers.mjs +95 -0
  66. package/src/builders/plan-markdown-edit.mjs +3 -3
  67. package/src/builders/plan-overlay.js +1530 -1608
  68. package/src/builders/plan.mjs +689 -186
  69. package/src/builders/preset-definitions.json +1 -0
  70. package/src/builders/preset-eval.mjs +244 -0
  71. package/src/builders/preview.html +51 -120
  72. package/src/builders/red-thread-backbone.mjs +135 -36
  73. package/src/builders/repair.mjs +205 -0
  74. package/src/builders/repeat-groups.mjs +540 -0
  75. package/src/builders/resolve-skill.mjs +5 -4
  76. package/src/builders/review-overlay.js +296 -293
  77. package/src/builders/review.mjs +305 -84
  78. package/src/builders/rule-shift.mjs +96 -0
  79. package/src/builders/seat.mjs +354 -0
  80. package/src/builders/settle-driver.mjs +236 -0
  81. package/src/builders/settle.mjs +1448 -0
  82. package/src/builders/slide-prep.mjs +67 -0
  83. package/src/builders/spec-assets.mjs +236 -0
  84. package/src/builders/spec-match.mjs +56 -0
  85. package/src/builders/stack.mjs +413 -0
  86. package/src/builders/storyboard-markdown.mjs +70 -27
  87. package/src/builders/storyboard-schema.mjs +54 -114
  88. package/src/builders/text-blocks.mjs +212 -0
  89. package/src/builders/text-card-fit.mjs +552 -0
  90. package/src/builders/text-stack.mjs +276 -0
  91. package/src/builders/transcribe.mjs +1069 -0
  92. package/src/cli/assets.mjs +164 -0
  93. package/src/cli/common.mjs +173 -12
  94. package/src/cli/concept-spec-support.mjs +76 -0
  95. package/src/cli/concepts.mjs +1002 -103
  96. package/src/cli/deck.mjs +401 -65
  97. package/src/cli/diagnose.mjs +4 -2
  98. package/src/cli/engine-helpers.mjs +17 -10
  99. package/src/cli/engine-results.mjs +76 -3
  100. package/src/cli/help.mjs +232 -28
  101. package/src/cli/install.mjs +9 -0
  102. package/src/cli/maintenance.mjs +104 -0
  103. package/src/cli/read.mjs +2 -1
  104. package/src/cli/ready.mjs +6 -3
  105. package/src/cli/record.mjs +522 -0
  106. package/src/cli/remote.mjs +818 -0
  107. package/src/cli/revision.mjs +686 -0
  108. package/src/cli/search.mjs +30 -11
  109. package/src/cli/session.mjs +56 -13
  110. package/src/cli/setup.mjs +46 -2
  111. package/src/cli/status.mjs +142 -33
  112. package/src/cli/tasks.mjs +246 -0
  113. package/src/cli/transcribe.mjs +854 -0
  114. package/src/cli/workspace-ui.mjs +260 -0
  115. package/src/cli/workspace.mjs +212 -34
  116. package/src/install-channel.mjs +64 -7
  117. package/src/lib/adopt.mjs +346 -25
  118. package/src/lib/concept-spec-binding.mjs +96 -0
  119. package/src/lib/conversions.mjs +70 -6
  120. package/src/lib/convert-folded.mjs +107 -0
  121. package/src/lib/deck-paths.mjs +418 -0
  122. package/src/lib/durable-ids.mjs +47 -0
  123. package/src/lib/edit-operations.mjs +316 -0
  124. package/src/lib/edit-state.mjs +1244 -0
  125. package/src/lib/edit-transitions.mjs +120 -0
  126. package/src/lib/extensions.mjs +501 -0
  127. package/src/lib/image-assets.mjs +465 -0
  128. package/src/lib/image-derivatives.mjs +234 -0
  129. package/src/lib/image-intent-fingerprint.mjs +70 -0
  130. package/src/lib/image-intent-tags.mjs +176 -0
  131. package/src/lib/image-intent.mjs +802 -0
  132. package/src/lib/image-use-overrides.mjs +279 -0
  133. package/src/lib/inline-components.mjs +613 -0
  134. package/src/lib/lint-converted.mjs +68 -4
  135. package/src/lib/merge-json.mjs +163 -0
  136. package/src/lib/overwrite-guard.mjs +3 -3
  137. package/src/lib/presentation-context.mjs +531 -0
  138. package/src/lib/preservation-tags.mjs +157 -0
  139. package/src/lib/preservation-verdict.mjs +1342 -0
  140. package/src/lib/publish.mjs +1557 -0
  141. package/src/lib/rebase.mjs +945 -0
  142. package/src/lib/reconcile-ack.mjs +4 -6
  143. package/src/lib/reconcile.mjs +62 -24
  144. package/src/lib/record-client.mjs +175 -0
  145. package/src/lib/record-state.mjs +151 -0
  146. package/src/lib/remote.mjs +661 -0
  147. package/src/lib/revision.mjs +1210 -0
  148. package/src/lib/slide-guids.mjs +4 -6
  149. package/src/lib/slide-preservation.mjs +423 -0
  150. package/src/lib/slide-selection.mjs +9 -0
  151. package/src/lib/workspace-transaction.mjs +117 -0
  152. package/src/pptx/content-digest.mjs +334 -0
  153. package/src/pptx/deck-assemble.mjs +1278 -0
  154. package/src/pptx/fill/engine.mjs +2 -3
  155. package/src/pptx/fill/freeform.mjs +6 -3
  156. package/src/pptx/ooxml.mjs +20 -0
  157. package/src/pptx/package-evidence.mjs +383 -0
  158. package/src/pptx/tags.mjs +163 -11
  159. package/src/update-check.mjs +22 -4
  160. package/src/workspace/adapters.mjs +222 -0
  161. package/src/workspace/auth.mjs +256 -0
  162. package/src/workspace/autostart.mjs +204 -0
  163. package/src/workspace/daemon.mjs +360 -0
  164. package/src/workspace/discovery.mjs +180 -0
  165. package/src/workspace/edit.mjs +167 -0
  166. package/src/workspace/events.mjs +52 -0
  167. package/src/workspace/gate-client.mjs +290 -0
  168. package/src/workspace/handback.mjs +73 -0
  169. package/src/workspace/lifecycle.mjs +635 -0
  170. package/src/workspace/operations.mjs +200 -0
  171. package/src/workspace/pick-folder.mjs +152 -0
  172. package/src/workspace/registry.mjs +359 -0
  173. package/src/workspace/remote-links.mjs +397 -0
  174. package/src/workspace/remote-status.mjs +359 -0
  175. package/src/workspace/routes.mjs +1331 -0
  176. package/src/workspace/server.mjs +159 -0
  177. package/src/workspace/sync.mjs +1119 -0
  178. package/src/workspace/task-actions.mjs +215 -0
  179. package/src/workspace/tasks.mjs +507 -0
  180. package/src/workspace/ui/app.js +1886 -0
  181. package/src/workspace/ui/index.html +141 -0
  182. package/src/workspace/ui/plan-bridge.js +120 -0
  183. package/src/workspace/ui/sharepoint.svg +59 -0
  184. package/src/workspace/ui/styles.css +423 -0
  185. package/src/builders/visual-families.mjs +0 -46
@@ -0,0 +1,141 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>slidemind workspace</title>
7
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%2310131b'/%3E%3Crect x='6.5' y='9.5' width='19' height='13' rx='3' fill='none' stroke='%23a9c2ff' stroke-width='2'/%3E%3C/svg%3E">
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&family=Urbanist:wght@300;400&display=swap">
11
+ <link rel="stylesheet" href="/ui/styles.css">
12
+ </head>
13
+ <body>
14
+ <header class="top">
15
+ <button type="button" class="icon" id="side-toggle" data-tip="Menu" aria-label="Show the navigation" aria-controls="side" aria-expanded="false">
16
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
17
+ </button>
18
+ <a href="/" data-nav class="brand" data-tip="Inbox">
19
+ <span class="logo"><!-- the add-in's embossed slide mark, as in the review and plan gates -->
20
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="160 160 960 540" preserveAspectRatio="none"><defs><linearGradient id="rimTop" gradientUnits="userSpaceOnUse" x1="160" y1="0" x2="1120" y2="0"><stop offset="0%" stop-color="#d0e4ff" stop-opacity="0.85"/><stop offset="35%" stop-color="#fff" stop-opacity="0.5"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="rimLeft" gradientUnits="userSpaceOnUse" x1="0" y1="160" x2="0" y2="700"><stop offset="0%" stop-color="#d0e4ff" stop-opacity="0.6"/><stop offset="40%" stop-color="#fff" stop-opacity="0.28"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="rimBottom" gradientUnits="userSpaceOnUse" x1="1120" y1="0" x2="160" y2="0"><stop offset="0%" stop-color="#000" stop-opacity="0.55"/><stop offset="60%" stop-color="#000" stop-opacity="0.2"/><stop offset="100%" stop-color="#000" stop-opacity="0"/></linearGradient><linearGradient id="rimRight" gradientUnits="userSpaceOnUse" x1="0" y1="700" x2="0" y2="160"><stop offset="0%" stop-color="#000" stop-opacity="0.45"/><stop offset="60%" stop-color="#000" stop-opacity="0.16"/><stop offset="100%" stop-color="#000" stop-opacity="0"/></linearGradient><linearGradient id="faceFill" gradientUnits="userSpaceOnUse" x1="160" y1="160" x2="1120" y2="700"><stop offset="0%" stop-color="#fff" stop-opacity="0.08"/><stop offset="50%" stop-color="#808080" stop-opacity="0.02"/><stop offset="100%" stop-color="#000" stop-opacity="0.10"/></linearGradient></defs><rect x="160" y="160" width="960" height="540" rx="40" ry="40" fill="url(#faceFill)"/><path d="M 160,200 A 40,40 0 0 1 200,160 L 1080,160 A 40,40 0 0 1 1120,200" fill="none" stroke="url(#rimTop)" stroke-width="3" stroke-linecap="round"/><path d="M 160,200 L 160,660 A 40,40 0 0 0 200,700" fill="none" stroke="url(#rimLeft)" stroke-width="2.4" stroke-linecap="round"/><path d="M 1120,660 A 40,40 0 0 1 1080,700 L 200,700 A 40,40 0 0 1 160,660" fill="none" stroke="url(#rimBottom)" stroke-width="3" stroke-linecap="round"/><path d="M 1120,660 L 1120,200 A 40,40 0 0 0 1080,160" fill="none" stroke="url(#rimRight)" stroke-width="2.4" stroke-linecap="round"/><rect x="160" y="160" width="960" height="540" rx="40" ry="40" fill="none" stroke="#fff" stroke-opacity="0.14" stroke-width="1.4"/></svg>
21
+ </span>
22
+ <span class="word"><b class="t">slide</b><b class="b">mind</b></span>
23
+ </a>
24
+ <span class="sep"></span>
25
+ <!-- the page's one header: its name, the line under it, its own buttons and chips (app.js setMeta) -->
26
+ <span class="meta"><span class="t" id="meta-title">Workspace</span><span class="h" id="meta-sub">Your decks, plans and open questions</span></span>
27
+ <span class="top-actions" id="top-actions"></span>
28
+ <span class="grow"></span>
29
+ <nav>
30
+ <span id="conn" class="chip">Connecting…</span>
31
+ </nav>
32
+ </header>
33
+ <div id="conn-banner" class="conn-banner" role="status" aria-live="polite" hidden></div>
34
+ <div class="shell">
35
+ <aside id="side" aria-label="Workspace navigation">
36
+ <div class="side-search">
37
+ <svg class="side-search-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
38
+ <input type="search" id="library-search" placeholder="Search decks" autocomplete="off" aria-label="Search decks" aria-keyshortcuts="Meta+K Control+K /">
39
+ <kbd class="side-kbd" aria-hidden="true">⌘K</kbd>
40
+ </div>
41
+ <div class="side-nav">
42
+ <a href="/" data-nav class="side-link" id="inbox-link" data-side-item>
43
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
44
+ <span class="side-link-txt">Inbox</span><span class="badge" id="inbox-count" data-tip="Questions your agent is waiting on"></span>
45
+ </a>
46
+ </div>
47
+ <div class="side-sec">
48
+ <h2 id="library-heading">Decks</h2>
49
+ <div class="side-filter seg" id="library-filter" role="group" aria-label="Show"><button type="button" data-filter="all" aria-pressed="true">All</button><button type="button" data-filter="unfinished" aria-pressed="false" data-tip="Decks without a .pptx yet">Unfinished</button></div>
50
+ </div>
51
+ <div class="side-body"><ul class="list" id="library" aria-labelledby="library-heading"></ul><button id="more" hidden>Load more</button></div>
52
+ <div class="side-foot"><button type="button" class="btn" id="add-folder">
53
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/><path d="M12 10v6"/><path d="M9 13h6"/></svg>
54
+ Add local folder
55
+ </button></div>
56
+ <div id="side-grip" data-tip="Drag to resize · double-click to reset"></div>
57
+ </aside>
58
+ <main id="app"><div class="page"><p class="muted">Signing in…</p></div></main>
59
+ </div>
60
+ <script>
61
+ // The shell is served without a credential; everything under /ui/ needs one.
62
+ // A browser that already holds this workspace's session (the cookie survives
63
+ // daemon restarts) is simply signed in; otherwise the one-time fragment token
64
+ // is exchanged for it. The token leaves the address bar first, whatever
65
+ // happens next: it is spent (or dead) either way.
66
+ (function () {
67
+ const $app = document.getElementById("app");
68
+ const $conn = document.getElementById("conn");
69
+ // A browser signs in through a link the CLI made: the agent's, or the tab it opens.
70
+ const ASK = "Ask your agent to open the slidemind workspace, or open the workspace link it gave you — either signs this browser in.";
71
+ const m = location.hash.match(/[#&]bootstrap=([^&]+)/);
72
+ const token = m ? decodeURIComponent(m[1]) : null;
73
+ if (m) history.replaceState(null, "", location.pathname + location.search);
74
+ const say = (cls, msg, sub) => {
75
+ const page = document.createElement("div");
76
+ page.className = "page";
77
+ const p = document.createElement("p");
78
+ p.className = cls;
79
+ p.id = "signed-out";
80
+ p.textContent = msg;
81
+ page.append(p);
82
+ if (sub) {
83
+ const q = document.createElement("p");
84
+ q.className = "muted";
85
+ q.textContent = sub;
86
+ page.append(q);
87
+ }
88
+ $app.replaceChildren(page);
89
+ };
90
+ // a sign-in in another tab of this browser sets the same cookie: pick it up
91
+ const signedOut = (msg) => {
92
+ say("error", msg, ASK);
93
+ $conn.textContent = "Signed out";
94
+ $conn.className = "chip bad";
95
+ const tick = () => fetch("/api/v1/session", { credentials: "same-origin", cache: "no-store" }).then((r) => (r.ok ? signIn() : setTimeout(tick, 6000)), () => setTimeout(tick, 6000));
96
+ setTimeout(tick, 6000);
97
+ };
98
+ // Not up (yet): say so once, poll /health, sign in again when it answers.
99
+ const offline = () => {
100
+ say("banner", "The workspace stopped. This page reconnects by itself.");
101
+ $conn.textContent = "Workspace offline — reconnecting…";
102
+ $conn.className = "chip warn";
103
+ const tick = () => fetch("/health", { cache: "no-store" }).then((r) => r.json()).then((h) => (h && !h.draining ? signIn() : setTimeout(tick, 3000)), () => setTimeout(tick, 3000));
104
+ setTimeout(tick, 3000);
105
+ };
106
+ async function signIn() {
107
+ let csrf = null;
108
+ let r;
109
+ try {
110
+ r = await fetch("/api/v1/session", { credentials: "same-origin", cache: "no-store" });
111
+ } catch {
112
+ return offline();
113
+ }
114
+ if (r.ok) csrf = (await r.json().catch(() => null))?.csrfToken ?? null;
115
+ else if (r.status !== 401) return offline(); // a workspace on its way out
116
+ else if (!token) return signedOut("You're not signed in to this workspace yet.");
117
+ else {
118
+ let x;
119
+ try {
120
+ x = await fetch("/api/v1/session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ bootstrap: token }) });
121
+ } catch {
122
+ return offline();
123
+ }
124
+ const j = await x.json().catch(() => null);
125
+ // a link signs in every time it is clicked; only one from a reset workspace (a new session.key) fails
126
+ if (!x.ok || !j?.csrfToken) return signedOut("This link is not from this workspace — it was reset since the link was made.");
127
+ csrf = j.csrfToken;
128
+ }
129
+ window.SLIDEMIND_CSRF = csrf ?? undefined;
130
+ try {
131
+ if (csrf) sessionStorage.setItem("slidemind.csrf", csrf);
132
+ } catch {}
133
+ const load = (src) => new Promise((ok, no) => { const s = document.createElement("script"); s.src = src; s.onload = ok; s.onerror = no; document.body.append(s); });
134
+ await load("/ui/plan-bridge.js").catch(() => {}); // optional: the plan transport lane ships it
135
+ await load("/ui/app.js").catch(() => offline());
136
+ }
137
+ signIn();
138
+ })();
139
+ </script>
140
+ </body>
141
+ </html>
@@ -0,0 +1,120 @@
1
+ // Parent side of the plan-view transport (contracts §7).
2
+ //
3
+ // The plan page runs in a sandboxed iframe without allow-same-origin, so it has
4
+ // an opaque origin and no credentials. After the frame has loaded, the parent
5
+ // hands it exactly one MessagePort; from then on every request the child makes
6
+ // is `{id, method, payload}` on that port and every answer `{id, ok, result?,
7
+ // error?}`. Which deck, view and task those requests touch is bound HERE, from
8
+ // the options `connect` was given — ids inside the child's payload are ignored.
9
+ //
10
+ // PlanBridge.connect(iframe, { viewId, deckId, taskId?, api, allow?, loaded?, onChrome? })
11
+ // → { close(), notify(message) }
12
+ // PlanBridge.notify(iframe, { type: "invalidate" }) — an advisory nudge on the
13
+ // port (the page re-reads; it ignores types it does not know). Any other
14
+ // field of the message rides along: `{ type: "chrome-event", event }`.
15
+ //
16
+ // The page keeps its own navigation but says nothing to the user itself. Its
17
+ // status line, its notices and its one dialog it posts on the port as
18
+ // `{ type: "slidemind-view-chrome", chrome }`, and the parent's
19
+ // `onChrome(chrome)` renders them (every post replaces the last). A click on
20
+ // any of it comes back as `{ type: "slidemind-view-chrome-event", event: { kind:
21
+ // "action" | "dismiss", id } }`. While the page holds an edit it has not saved
22
+ // yet (its own debounce) it posts `{ type: "slidemind-view-dirty", dirty }`, and
23
+ // the parent's `onDirty(dirty)` shows the save state accordingly.
24
+ //
25
+ // `api` is the parent's own, already-authenticated client:
26
+ // read(scope) · save({base, value}, scope) · validate(payload, scope)
27
+ // action(name, payload, scope) · respondTask(taskId, {action, payload}, scope)
28
+ // Anything an api call throws with `.code` / `.details` reaches the child as
29
+ // `{code, message, details}`; a `local_conflict` with its details is how the
30
+ // page shows both sides.
31
+ (function (global) {
32
+ "use strict";
33
+ var METHODS = ["read", "save", "validate", "workbook.open", "workbook.import", "task.respond"];
34
+ var live = new WeakMap();
35
+
36
+ function connect(iframe, options) {
37
+ options = options || {};
38
+ var api = options.api || {};
39
+ var allow = METHODS.filter(function (m) { return !options.allow || options.allow.indexOf(m) >= 0; });
40
+ var previous = live.get(iframe);
41
+ if (previous) previous.close();
42
+ var channel = new MessageChannel();
43
+ var closed = false;
44
+ var scope = { deckId: options.deckId, viewId: options.viewId, taskId: options.taskId || null };
45
+ var session = { close: close, notify: notify };
46
+ live.set(iframe, session);
47
+ function notify(message) {
48
+ if (closed || !message || typeof message.type !== "string") return false;
49
+ var out = {};
50
+ for (var k in message) if (Object.prototype.hasOwnProperty.call(message, k) && k !== "type") out[k] = message[k];
51
+ out.type = "slidemind-view-" + message.type;
52
+ channel.port1.postMessage(out);
53
+ return true;
54
+ }
55
+
56
+ function reply(id, ok, body) {
57
+ if (closed) return;
58
+ channel.port1.postMessage(ok ? { id: id, ok: true, result: body === undefined ? null : body } : { id: id, ok: false, error: body });
59
+ }
60
+ function refuse(code, message) { var e = new Error(message); e.code = code; return e; }
61
+ function run(method, payload) {
62
+ switch (method) {
63
+ case "read": return api.read(scope);
64
+ case "save": return api.save({ base: payload.base, value: payload.value }, scope);
65
+ case "validate": return api.validate(payload, scope);
66
+ case "workbook.open":
67
+ case "workbook.import": return api.action(method, payload, scope);
68
+ case "task.respond":
69
+ if (!scope.taskId) throw refuse("stale_subject", "no task is bound to this view");
70
+ return api.respondTask(scope.taskId, { action: payload.action, payload: payload.payload }, scope);
71
+ }
72
+ }
73
+ function dispatch(msg) {
74
+ if (msg && msg.type === "slidemind-view-chrome") {
75
+ if (typeof options.onChrome === "function") options.onChrome(msg.chrome && typeof msg.chrome === "object" ? msg.chrome : null);
76
+ return;
77
+ }
78
+ if (msg && msg.type === "slidemind-view-dirty") {
79
+ if (typeof options.onDirty === "function") options.onDirty(!!msg.dirty);
80
+ return;
81
+ }
82
+ if (!msg || typeof msg.id !== "string" || typeof msg.method !== "string") return;
83
+ var payload = msg.payload && typeof msg.payload === "object" ? msg.payload : {};
84
+ if (allow.indexOf(msg.method) < 0) { reply(msg.id, false, { code: "method_not_allowed", message: msg.method + " is not granted to this view" }); return; }
85
+ if (typeof api[{ "workbook.open": "action", "workbook.import": "action", "task.respond": "respondTask" }[msg.method] || msg.method] !== "function") { reply(msg.id, false, { code: "not_implemented", message: msg.method + " is not available here" }); return; }
86
+ Promise.resolve().then(function () { return run(msg.method, payload); }).then(
87
+ function (result) { reply(msg.id, true, result); },
88
+ function (error) { reply(msg.id, false, { code: (error && error.code) || "error", message: (error && error.message) || String(error), details: (error && error.details) || null }); }
89
+ );
90
+ }
91
+ channel.port1.onmessage = function (event) { dispatch(event.data); };
92
+
93
+ function start() {
94
+ if (closed) return;
95
+ // targetOrigin must be "*": a sandboxed frame has an opaque origin that no
96
+ // string can name. This is the only message that crosses the window
97
+ // boundary, and it carries nothing but the port — all trust afterwards
98
+ // is bound to that port, which only the frame it was transferred to holds.
99
+ // The parent must only ever connect a frame whose content it wrote itself.
100
+ iframe.contentWindow.postMessage({ type: "slidemind-view-connect", version: 1, viewId: options.viewId }, "*", [channel.port2]);
101
+ }
102
+ if (options.loaded) start(); else iframe.addEventListener("load", start, { once: true });
103
+
104
+ function close() {
105
+ if (closed) return;
106
+ closed = true;
107
+ try { channel.port1.postMessage({ type: "slidemind-view-close" }); } catch (_) {}
108
+ channel.port1.close();
109
+ if (live.get(iframe) === session) live.delete(iframe);
110
+ }
111
+ return session;
112
+ }
113
+
114
+ function notify(iframe, message) {
115
+ var session = live.get(iframe);
116
+ return session ? session.notify(message) : false;
117
+ }
118
+
119
+ global.PlanBridge = { connect: connect, notify: notify, METHODS: METHODS.slice() };
120
+ })(typeof window !== "undefined" ? window : globalThis);
@@ -0,0 +1,59 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
4
+ <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
5
+ <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
6
+ <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
7
+ <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
8
+ <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
9
+ <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
10
+ <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
11
+ <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
12
+ ]>
13
+ <svg version="1.1" id="Livello_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
14
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1992.333 1946"
15
+ enable-background="new 0 0 1992.333 1946" xml:space="preserve">
16
+ <metadata>
17
+ <sfw xmlns="&ns_sfw;">
18
+ <slices></slices>
19
+ <sliceSourceBounds bottomLeftOrigin="true" height="1946" width="1992.333" x="-995.333" y="-949"></sliceSourceBounds>
20
+ </sfw>
21
+ </metadata>
22
+ <circle fill="#036C70" cx="1019.333" cy="556" r="556"/>
23
+ <circle fill="#1A9BA1" cx="1482.667" cy="1065.667" r="509.667"/>
24
+ <circle fill="#37C6D0" cx="1088.833" cy="1552.167" r="393.833"/>
25
+ <path opacity="0.1" enable-background="new " d="M1112,501.79v988.753c-0.23,34.357-21.05,65.222-52.82,78.303
26
+ c-10.116,4.279-20.987,6.484-31.97,6.487H695.463c-0.463-7.877-0.463-15.29-0.463-23.167c-0.154-7.734,0.155-15.47,0.927-23.167
27
+ c8.48-148.106,99.721-278.782,235.837-337.77v-86.18c-302.932-48.005-509.592-332.495-461.587-635.427
28
+ c0.333-2.098,0.677-4.195,1.034-6.289c2.306-15.626,5.556-31.099,9.73-46.333h546.27C1073.964,417.178,1111.822,455.036,1112,501.79
29
+ z"/>
30
+ <path opacity="0.2" enable-background="new " d="M980.877,463.333H471.21c-51.486,302.386,151.908,589.256,454.293,640.742
31
+ c9.156,1.559,18.35,2.888,27.573,3.986c-143.633,68.11-248.3,261.552-257.196,420.938c-0.771,7.697-1.081,15.433-0.927,23.167
32
+ c0,7.877,0,15.29,0.463,23.167c0.836,15.574,2.85,31.063,6.023,46.333h279.39c34.357-0.23,65.222-21.05,78.303-52.82
33
+ c4.279-10.115,6.485-20.987,6.487-31.97V548.123C1065.443,501.387,1027.613,463.537,980.877,463.333z"/>
34
+ <path opacity="0.2" enable-background="new " d="M980.877,463.333H471.21c-51.475,302.414,151.95,589.297,454.364,640.773
35
+ c6.186,1.053,12.389,2.001,18.607,2.844c-139,73.021-239.543,266-248.254,422.05h284.95c46.681-0.353,84.437-38.109,84.79-84.79
36
+ V548.123C1065.489,501.369,1027.631,463.511,980.877,463.333z"/>
37
+ <path opacity="0.2" enable-background="new " d="M934.543,463.333H471.21c-48.606,285.482,130.279,560.404,410.977,631.616
38
+ C775.901,1216.384,710.711,1368.301,695.927,1529h238.617c46.754-0.178,84.612-38.036,84.79-84.79V548.123
39
+ C1019.308,501.306,981.361,463.359,934.543,463.333z"/>
40
+ <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="177.0788" y1="1551.0284" x2="842.2545" y2="398.9716" gradientTransform="matrix(1 0 0 -1 0 1948)">
41
+ <stop offset="0" style="stop-color:#058F92"/>
42
+ <stop offset="0.5" style="stop-color:#038489"/>
43
+ <stop offset="1" style="stop-color:#026D71"/>
44
+ </linearGradient>
45
+ <path fill="url(#SVGID_1_)" d="M84.929,463.333h849.475c46.905,0,84.929,38.024,84.929,84.929v849.475
46
+ c0,46.905-38.024,84.929-84.929,84.929H84.929c-46.905,0-84.929-38.024-84.929-84.929V548.262
47
+ C0,501.357,38.024,463.333,84.929,463.333z"/>
48
+ <path fill="#FFFFFF" d="M379.331,962.621c-19.903-13.202-36.528-30.777-48.604-51.384c-11.701-21.542-17.533-45.781-16.912-70.288
49
+ c-1.042-33.181,10.155-65.586,31.46-91.045c22.388-25.49,51.326-44.366,83.678-54.581c36.871-12.136,75.49-18.116,114.304-17.699
50
+ c51.043-1.865,102.015,5.272,150.583,21.082v106.567c-21.103-12.784-44.088-22.166-68.11-27.8
51
+ c-26.065-6.392-52.81-9.597-79.647-9.545c-28.3-1.039-56.419,4.913-81.871,17.329c-19.65,8.475-32.392,27.807-32.433,49.206
52
+ c-0.08,12.981,4.907,25.481,13.9,34.843c10.622,11.037,23.187,20.021,37.067,26.503c15.444,7.691,38.611,17.916,69.5,30.673
53
+ c3.401,1.075,6.716,2.407,9.915,3.985c30.401,11.881,59.729,26.344,87.663,43.229c21.154,13.043,38.908,30.924,51.801,52.171
54
+ c13.218,24.085,19.625,51.315,18.533,78.767c1.509,34.066-8.913,67.591-29.468,94.798c-20.488,25.012-47.88,43.446-78.767,53.005
55
+ c-36.329,11.387-74.245,16.892-112.312,16.309c-34.154,0.155-68.258-2.635-101.933-8.34c-28.434-4.653-56.182-12.807-82.612-24.279
56
+ v-112.358c25.264,18.043,53.489,31.529,83.4,39.847c29.81,9.289,60.798,14.251,92.018,14.734c28.895,1.83,57.739-4.291,83.4-17.699
57
+ c17.976-10.144,28.909-29.358,28.449-49.994c0.12-14.359-5.56-28.158-15.753-38.271c-12.676-12.444-27.352-22.671-43.414-30.256
58
+ c-18.533-9.267-45.824-21.483-81.871-36.65C432.618,993.951,405.161,979.594,379.331,962.621z"/>
59
+ </svg>