workpeg 0.77.0__tar.gz → 0.78.0__tar.gz

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 (72) hide show
  1. {workpeg-0.77.0/src/workpeg.egg-info → workpeg-0.78.0}/PKG-INFO +1 -1
  2. {workpeg-0.77.0 → workpeg-0.78.0}/pyproject.toml +1 -1
  3. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/runtime/ai.js +51 -22
  4. {workpeg-0.77.0 → workpeg-0.78.0/src/workpeg.egg-info}/PKG-INFO +1 -1
  5. {workpeg-0.77.0 → workpeg-0.78.0}/LICENSE +0 -0
  6. {workpeg-0.77.0 → workpeg-0.78.0}/MANIFEST.in +0 -0
  7. {workpeg-0.77.0 → workpeg-0.78.0}/README.md +0 -0
  8. {workpeg-0.77.0 → workpeg-0.78.0}/setup.cfg +0 -0
  9. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/__init__.py +0 -0
  10. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/build.py +0 -0
  11. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/cdn.py +0 -0
  12. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/cli.py +0 -0
  13. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/config.py +0 -0
  14. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/context.py +0 -0
  15. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/create_new.py +0 -0
  16. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/run.py +0 -0
  17. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/runtime.py +0 -0
  18. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/submit.py +0 -0
  19. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/__init__.py +0 -0
  20. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/Dockerfile +0 -0
  21. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/LICENSE +0 -0
  22. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/README.md +0 -0
  23. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/app/__init__.py +0 -0
  24. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/app/main.py +0 -0
  25. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/templates/functions/requirements.txt +0 -0
  26. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/__init__.py +0 -0
  27. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/actions.py +0 -0
  28. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/app.py +0 -0
  29. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/build.py +0 -0
  30. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/compiler/__init__.py +0 -0
  31. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/compiler/ast_parser.py +0 -0
  32. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/compiler/ir.py +0 -0
  33. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/compiler/js_generator.py +0 -0
  34. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/create.py +0 -0
  35. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/fake_cloud.py +0 -0
  36. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/minify.py +0 -0
  37. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/runtime/pegment.css +0 -0
  38. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/runtime/workpeg-runtime.js +0 -0
  39. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/scaffold.py +0 -0
  40. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/serve.py +0 -0
  41. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/state.py +0 -0
  42. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/validators.py +0 -0
  43. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/watcher.py +0 -0
  44. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/__init__.py +0 -0
  45. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/base.py +0 -0
  46. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/canvas.py +0 -0
  47. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/display.py +0 -0
  48. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/forms.py +0 -0
  49. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/futures.py +0 -0
  50. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/gestures.py +0 -0
  51. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/interactive.py +0 -0
  52. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/ui/widgets/layout.py +0 -0
  53. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg/utils.py +0 -0
  54. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg.egg-info/SOURCES.txt +0 -0
  55. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg.egg-info/dependency_links.txt +0 -0
  56. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg.egg-info/entry_points.txt +0 -0
  57. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg.egg-info/requires.txt +0 -0
  58. {workpeg-0.77.0 → workpeg-0.78.0}/src/workpeg.egg-info/top_level.txt +0 -0
  59. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_build.py +0 -0
  60. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_cdn.py +0 -0
  61. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_changelog.py +0 -0
  62. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_changelog_guard.py +0 -0
  63. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_cli.py +0 -0
  64. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_config.py +0 -0
  65. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_context.py +0 -0
  66. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_create_new.py +0 -0
  67. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_release_script.py +0 -0
  68. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_run.py +0 -0
  69. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_runtime.py +0 -0
  70. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_submit.py +0 -0
  71. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_utils.py +0 -0
  72. {workpeg-0.77.0 → workpeg-0.78.0}/tests/test_watch_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workpeg
3
- Version: 0.77.0
3
+ Version: 0.78.0
4
4
  Summary: Workpeg function runtime and SDK
5
5
  Author-email: Workpeg <support@workpeg.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "workpeg"
7
- version = "0.77.0"
7
+ version = "0.78.0"
8
8
  description = "Workpeg function runtime and SDK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -607,6 +607,7 @@
607
607
 
608
608
  // ── conversation view (/chat/<uuid>) ───────────────────────────────────
609
609
  var messagesEl = null;
610
+ var scrollDownEl = null; // the "scroll to latest" button (when scrolled up)
610
611
  function renderConversation() {
611
612
  S.host.innerHTML = "";
612
613
  closePlusMenu();
@@ -614,7 +615,17 @@
614
615
  var conversation = el("div", "chat-conversation", { children: [messagesEl] });
615
616
 
616
617
  var composer = buildComposer("Message Workpeg AI…");
618
+ // A "scroll to latest" affordance — floats just above the (sticky) composer,
619
+ // shown only when the thread isn't scrolled to the bottom.
620
+ var scrollDown = el("button", "wpai-scroll-down", {
621
+ attrs: { type: "button", "aria-label": "Scroll to latest",
622
+ title: "Scroll to latest" },
623
+ children: [icon("arrow-down", 20)]
624
+ });
625
+ scrollDown.addEventListener("click", function () { scrollToBottom(true); });
626
+ scrollDownEl = scrollDown;
617
627
  var bar = el("div", "chat-input-bar", { children: [
628
+ scrollDown,
618
629
  el("div", "chat-input-wrap-holder", { children: [composer] })
619
630
  ] });
620
631
 
@@ -623,7 +634,13 @@
623
634
  S.host.appendChild(center);
624
635
 
625
636
  S.messages.forEach(function (m) { messagesEl.appendChild(renderMessage(m)); });
626
- messagesEl.addEventListener("scroll", updateFade);
637
+ // The surface (#workpeg-ai-root) scrolls — toggle the scroll-to-latest
638
+ // button from there. Rebind (remove+add) so re-renders/re-attaches keep
639
+ // exactly one listener on the current host.
640
+ if (S.host) {
641
+ S.host.removeEventListener("scroll", updateScrollDown);
642
+ S.host.addEventListener("scroll", updateScrollDown);
643
+ }
627
644
  // Delegated copy for code blocks (their markup is set via innerHTML, so we
628
645
  // can't bind per-button). Copies the block's source text.
629
646
  messagesEl.addEventListener("click", function (e) {
@@ -637,7 +654,7 @@
637
654
  setTimeout(function () { btn.textContent = "Copy"; }, 1200);
638
655
  });
639
656
  scrollToBottom();
640
- updateFade();
657
+ updateScrollDown();
641
658
  }
642
659
 
643
660
  function renderMessage(m) {
@@ -779,7 +796,7 @@
779
796
  if (messagesEl) { messagesEl.appendChild(renderMessage(userMsg)); scrollToBottom(); }
780
797
 
781
798
  var thinking = thinkingNode();
782
- if (messagesEl) { messagesEl.appendChild(thinking); scrollToBottom(); updateFade(); }
799
+ if (messagesEl) { messagesEl.appendChild(thinking); scrollToBottom(); updateScrollDown(); }
783
800
 
784
801
  return json("POST", chatsPath(S.chatId + "/messages/"), { content: text })
785
802
  .then(function (created) {
@@ -983,16 +1000,21 @@
983
1000
  }
984
1001
 
985
1002
  // ── scroll / fade ──────────────────────────────────────────────────────
986
- function scrollToBottom() {
987
- if (messagesEl) messagesEl.scrollTop = messagesEl.scrollHeight;
1003
+ function scrollToBottom(smooth) {
1004
+ // The whole surface scrolls (see mount): pin it to the newest message.
1005
+ if (!S.host) return;
1006
+ if (smooth && S.host.scrollTo) {
1007
+ S.host.scrollTo({ top: S.host.scrollHeight, behavior: "smooth" });
1008
+ } else {
1009
+ S.host.scrollTop = S.host.scrollHeight;
1010
+ }
988
1011
  }
989
- function updateFade() {
990
- if (!messagesEl) return;
991
- var top = messagesEl.scrollTop > 4;
992
- var bottom = messagesEl.scrollTop + messagesEl.clientHeight <
993
- messagesEl.scrollHeight - 4;
994
- messagesEl.classList.toggle("is-fade-top", top);
995
- messagesEl.classList.toggle("is-fade-bottom", bottom);
1012
+ // Show the scroll-to-latest button only when the thread isn't at the bottom.
1013
+ function updateScrollDown() {
1014
+ if (!scrollDownEl || !S.host) return;
1015
+ var atBottom = S.host.scrollTop + S.host.clientHeight >=
1016
+ S.host.scrollHeight - 32;
1017
+ scrollDownEl.classList.toggle("is-visible", !atBottom);
996
1018
  }
997
1019
 
998
1020
  // ── misc helpers ───────────────────────────────────────────────────────
@@ -1077,9 +1099,12 @@
1077
1099
  host.parentNode.style.position = "relative";
1078
1100
  }
1079
1101
  if (host.setAttribute) {
1102
+ // We are the SCROLL container: a conversation scrolls on #workpeg-ai-root
1103
+ // itself (so the scrollbar rides the surface's far-right edge, not an inner
1104
+ // column), and the composer sticks to the bottom inside us.
1080
1105
  host.setAttribute("style",
1081
1106
  "position:absolute;top:0;right:0;bottom:0;left:0;display:block;" +
1082
- "margin:0;padding:0;overflow:hidden;box-sizing:border-box");
1107
+ "margin:0;padding:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box");
1083
1108
  }
1084
1109
  if (reattach) { redraw(chatId); return; }
1085
1110
  S.rendered = null; // force a fresh render on (re)mount
@@ -1124,7 +1149,8 @@
1124
1149
  // The landing centres in the area BELOW the top nav, so it reads a touch low;
1125
1150
  // a bottom pad (~the nav height) lifts it to look centred in the whole panel.
1126
1151
  R + " .chat-center{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:32px;min-height:0;height:100%;overflow:hidden;position:relative;padding-bottom:var(--wpai-nav-h,64px)}",
1127
- R + " .wpai-center--convo{justify-content:flex-start;padding-bottom:0}",
1152
+ // conversation centre: grow with the thread (don't clip) so the host scrolls
1153
+ R + " .wpai-center--convo{justify-content:flex-start;padding-bottom:0;gap:0;height:auto;min-height:100%;overflow:visible}",
1128
1154
  R + " .chat-landing{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:32px;width:100%;padding:40px 24px}",
1129
1155
  R + " .chat-greeting{font-size:var(--text-headline-lg-size,2rem);line-height:40px;font-weight:var(--font-weight-medium,500);color:var(--color-text-primary);text-align:center;margin:0}",
1130
1156
  // the landing card: one subtle border around the composer + suggestions
@@ -1179,13 +1205,9 @@
1179
1205
  R + " .chat-plus-item--chevron{justify-content:space-between}",
1180
1206
  R + " .chat-plus-item--chevron span{display:flex;align-items:center;gap:10px}",
1181
1207
  R + " .chat-plus-divider{height:1px;background:var(--color-border-subtle);margin:4px}",
1182
- // conversation
1183
- R + " .chat-conversation{flex:1;min-height:0;width:100%;max-width:800px;margin:0 auto;display:flex;flex-direction:column;padding:0 24px 100px;overflow:hidden}",
1184
- R + " .chat-messages{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:32px;margin:0 auto 50px auto;width:min(720px,100%);--fade-size:48px}",
1185
- R + " .chat-messages::-webkit-scrollbar{display:none}",
1186
- R + " .chat-messages.is-fade-top{-webkit-mask-image:linear-gradient(to bottom,transparent 0,black var(--fade-size));mask-image:linear-gradient(to bottom,transparent 0,black var(--fade-size))}",
1187
- R + " .chat-messages.is-fade-bottom{-webkit-mask-image:linear-gradient(to bottom,black calc(100% - var(--fade-size)),transparent 100%);mask-image:linear-gradient(to bottom,black calc(100% - var(--fade-size)),transparent 100%)}",
1188
- R + " .chat-messages.is-fade-top.is-fade-bottom{-webkit-mask-image:linear-gradient(to bottom,transparent 0,black var(--fade-size),black calc(100% - var(--fade-size)),transparent 100%);mask-image:linear-gradient(to bottom,transparent 0,black var(--fade-size),black calc(100% - var(--fade-size)),transparent 100%)}",
1208
+ // conversation — the THREAD flows and grows; #workpeg-ai-root scrolls it.
1209
+ R + " .chat-conversation{flex:1 0 auto;width:100%;max-width:800px;margin:0 auto;display:flex;flex-direction:column;padding:24px 24px 32px}",
1210
+ R + " .chat-messages{display:flex;flex-direction:column;gap:32px;width:min(720px,100%);margin:0 auto}",
1189
1211
  R + " .chat-message{display:flex;gap:12px;animation:wpaiMessageIn .3s ease}",
1190
1212
  "@keyframes wpaiMessageIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}",
1191
1213
  R + " .chat-message--user{justify-content:flex-end}",
@@ -1236,7 +1258,14 @@
1236
1258
  R + " .chat-message--thinking .chat-message__thinking{display:flex;align-items:center;gap:8px}",
1237
1259
  R + " .thinking-text{font-size:var(--text-body-sm-size,13px);color:var(--color-text-secondary)}",
1238
1260
  // bottom input bar
1239
- R + " .chat-input-bar{position:absolute;bottom:24px;left:50%;transform:translateX(-50%);width:min(720px,calc(100% - 48px));z-index:50}",
1261
+ // the composer sticks to the bottom of the scrolling surface; its gradient
1262
+ // lets the thread fade into it as messages scroll behind.
1263
+ R + " .chat-input-bar{position:sticky;bottom:0;align-self:center;width:min(720px,calc(100% - 48px));z-index:50;padding:12px 0 24px;background:linear-gradient(to bottom,transparent,var(--color-bg-default) 20px)}",
1264
+ // scroll-to-latest button — floats above the sticky composer, hidden until
1265
+ // the thread is scrolled up.
1266
+ R + " .wpai-scroll-down{position:absolute;left:50%;top:-46px;transform:translateX(-50%) translateY(6px);width:36px;height:36px;border-radius:9999px;display:flex;align-items:center;justify-content:center;background:var(--color-surface-raised,var(--color-surface-default));border:1px solid var(--color-border-subtle);color:var(--color-icon-primary,var(--color-text-primary));cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.28);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .15s ease,transform .15s ease,visibility .15s}",
1267
+ R + " .wpai-scroll-down.is-visible{opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-50%) translateY(0)}",
1268
+ R + " .wpai-scroll-down:hover{background:var(--color-surface-sunken2,var(--color-surface-default))}",
1240
1269
  // banner
1241
1270
  // The announcement floats OVER the top nav (fixed to the viewport, so the
1242
1271
  // host's overflow can't clip it), centred in the content area to the right of
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workpeg
3
- Version: 0.77.0
3
+ Version: 0.78.0
4
4
  Summary: Workpeg function runtime and SDK
5
5
  Author-email: Workpeg <support@workpeg.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes