workpeg 0.96.2__tar.gz → 0.96.4__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 (74) hide show
  1. {workpeg-0.96.2/src/workpeg.egg-info → workpeg-0.96.4}/PKG-INFO +1 -1
  2. {workpeg-0.96.2 → workpeg-0.96.4}/pyproject.toml +1 -1
  3. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/ai.js +80 -0
  4. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/scaffold.js +90 -4
  5. {workpeg-0.96.2 → workpeg-0.96.4/src/workpeg.egg-info}/PKG-INFO +1 -1
  6. {workpeg-0.96.2 → workpeg-0.96.4}/LICENSE +0 -0
  7. {workpeg-0.96.2 → workpeg-0.96.4}/MANIFEST.in +0 -0
  8. {workpeg-0.96.2 → workpeg-0.96.4}/README.md +0 -0
  9. {workpeg-0.96.2 → workpeg-0.96.4}/setup.cfg +0 -0
  10. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/__init__.py +0 -0
  11. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/build.py +0 -0
  12. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/cdn.py +0 -0
  13. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/cli.py +0 -0
  14. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/config.py +0 -0
  15. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/context.py +0 -0
  16. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/create_new.py +0 -0
  17. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/run.py +0 -0
  18. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/runtime.py +0 -0
  19. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/submit.py +0 -0
  20. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/__init__.py +0 -0
  21. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/Dockerfile +0 -0
  22. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/LICENSE +0 -0
  23. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/README.md +0 -0
  24. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/app/__init__.py +0 -0
  25. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/app/main.py +0 -0
  26. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/requirements.txt +0 -0
  27. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/__init__.py +0 -0
  28. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/actions.py +0 -0
  29. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/app.py +0 -0
  30. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/build.py +0 -0
  31. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/__init__.py +0 -0
  32. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/ast_parser.py +0 -0
  33. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/ir.py +0 -0
  34. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/js_generator.py +0 -0
  35. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/create.py +0 -0
  36. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/fake_cloud.py +0 -0
  37. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/minify.py +0 -0
  38. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/pegment.css +0 -0
  39. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/workpeg-runtime.js +0 -0
  40. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/scaffold.py +0 -0
  41. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/serve.py +0 -0
  42. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/state.py +0 -0
  43. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/validators.py +0 -0
  44. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/watcher.py +0 -0
  45. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/__init__.py +0 -0
  46. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/base.py +0 -0
  47. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/canvas.py +0 -0
  48. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/display.py +0 -0
  49. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/forms.py +0 -0
  50. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/futures.py +0 -0
  51. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/gestures.py +0 -0
  52. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/interactive.py +0 -0
  53. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/layout.py +0 -0
  54. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/utils.py +0 -0
  55. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/SOURCES.txt +0 -0
  56. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/dependency_links.txt +0 -0
  57. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/entry_points.txt +0 -0
  58. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/requires.txt +0 -0
  59. {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/top_level.txt +0 -0
  60. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_build.py +0 -0
  61. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cdn.py +0 -0
  62. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cdn_publish.py +0 -0
  63. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_changelog.py +0 -0
  64. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_changelog_guard.py +0 -0
  65. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cli.py +0 -0
  66. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_config.py +0 -0
  67. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_context.py +0 -0
  68. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_create_new.py +0 -0
  69. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_release_script.py +0 -0
  70. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_run.py +0 -0
  71. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_runtime.py +0 -0
  72. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_submit.py +0 -0
  73. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_utils.py +0 -0
  74. {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_watch_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workpeg
3
- Version: 0.96.2
3
+ Version: 0.96.4
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.96.2"
7
+ version = "0.96.4"
8
8
  description = "Workpeg function runtime and SDK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1091,6 +1091,81 @@
1091
1091
  }
1092
1092
 
1093
1093
  // ── composer (shared by landing + bottom bar) ──────────────────────────
1094
+ // ── composer message history — ↑/↓ recall the user's past messages ───────
1095
+ // The user's own messages in this conversation, oldest → newest: the recall
1096
+ // history the composer's ↑/↓ walk (like a shell prompt's up-arrow).
1097
+ function userHistory() {
1098
+ var out = [];
1099
+ for (var i = 0; i < S.messages.length; i++) {
1100
+ var m = S.messages[i];
1101
+ if (m && !m.is_agent_response && String(m.content || "").length) {
1102
+ out.push(String(m.content));
1103
+ }
1104
+ }
1105
+ return out;
1106
+ }
1107
+
1108
+ // Step a history: dir -1 = older, +1 = newer. idx === hist.length is the live
1109
+ // draft (past the newest). Returns the new index and the text to show. Pure.
1110
+ function stepHistory(hist, idx, dir, draft) {
1111
+ var next = idx + dir;
1112
+ if (next < 0) return { idx: 0, text: hist[0] };
1113
+ if (next >= hist.length) return { idx: hist.length, text: draft };
1114
+ return { idx: next, text: hist[next] };
1115
+ }
1116
+
1117
+ // Whether the collapsed caret sits on the composer's first / last visual line
1118
+ // — so ↑/↓ recall history only at the edges and otherwise move the caret
1119
+ // within a multi-line message. Fails open (both edges) with no live
1120
+ // selection/layout (e.g. tests).
1121
+ function caretEdges(input) {
1122
+ try {
1123
+ var sel = window.getSelection();
1124
+ var r = sel && sel.rangeCount ? sel.getRangeAt(0) : null;
1125
+ if (!r) return { first: true, last: true };
1126
+ if (!r.collapsed) return { first: false, last: false };
1127
+ var cr = r.getBoundingClientRect();
1128
+ var br = input.getBoundingClientRect();
1129
+ if (!cr || (!cr.top && !cr.bottom && !cr.height)) {
1130
+ return { first: true, last: true };
1131
+ }
1132
+ var line = cr.height || 20;
1133
+ return {
1134
+ first: cr.top - br.top < line * 0.75,
1135
+ last: br.bottom - cr.bottom < line * 0.75
1136
+ };
1137
+ } catch (e) { return { first: true, last: true }; }
1138
+ }
1139
+
1140
+ function setComposerText(input, text) {
1141
+ input.innerText = text || "";
1142
+ input.focus();
1143
+ placeCaretEnd(input);
1144
+ }
1145
+
1146
+ // ↑/↓ handler: walk the user's past messages, saving the in-progress draft so
1147
+ // stepping past the newest restores it. Guarded by caretEdges so multi-line
1148
+ // editing still moves the caret line by line.
1149
+ function recallHistory(input, e) {
1150
+ var dir = e.key === "ArrowUp" ? -1 : 1;
1151
+ var edge = caretEdges(input);
1152
+ if (dir < 0 && !edge.first) return;
1153
+ if (dir > 0 && !edge.last) return;
1154
+ var hist = userHistory();
1155
+ if (!hist.length) return;
1156
+ var idx = input._histIdx;
1157
+ if (idx == null) {
1158
+ if (dir > 0) return; // ↓ with nothing recalled → default
1159
+ input._histDraft = input.innerText || "";
1160
+ idx = hist.length; // start at the draft, one past the newest
1161
+ }
1162
+ var step = stepHistory(hist, idx, dir, input._histDraft || "");
1163
+ if (e.preventDefault) e.preventDefault();
1164
+ if (step.idx === idx) return; // already at the oldest — no-op
1165
+ input._histIdx = step.idx >= hist.length ? null : step.idx;
1166
+ setComposerText(input, step.text);
1167
+ }
1168
+
1094
1169
  function buildComposer(placeholder) {
1095
1170
  var input = el("div", "chat-input", {
1096
1171
  attrs: { contenteditable: "true", "data-placeholder": placeholder,
@@ -1100,8 +1175,12 @@
1100
1175
  if (e.key === "Enter" && !e.shiftKey) {
1101
1176
  e.preventDefault();
1102
1177
  submitFromInput(input);
1178
+ } else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
1179
+ recallHistory(input, e);
1103
1180
  }
1104
1181
  });
1182
+ // Typing exits history-recall (what's in the box becomes the new draft).
1183
+ input.addEventListener("input", function () { input._histIdx = null; });
1105
1184
  enableComposerMarkdown(input);
1106
1185
 
1107
1186
  // Buttons use the SHARED pegment .btn system (so the AI surface and the SDK
@@ -1170,6 +1249,7 @@
1170
1249
  var text = (input.innerText || "").trim();
1171
1250
  if (!text || S.sending) return;
1172
1251
  input.innerHTML = "";
1252
+ input._histIdx = null; // the sent message becomes the newest history
1173
1253
  send(text);
1174
1254
  }
1175
1255
 
@@ -320,6 +320,27 @@
320
320
  });
321
321
  }
322
322
 
323
+ // Fade a scrollable list's bottom edge while it overflows (a "more below"
324
+ // hint), lifting the fade once scrolled to the end — the .has-overflow /
325
+ // .at-bottom classes the STYLES rules key off. The first check runs after
326
+ // the next frame, so it measures once the popup is in the DOM.
327
+ function attachListFade(list) {
328
+ function update() {
329
+ var overflow = list.scrollHeight > list.clientHeight + 1;
330
+ list.classList.toggle("has-overflow", overflow);
331
+ var atBottom =
332
+ list.scrollTop + list.clientHeight >= list.scrollHeight - 1;
333
+ list.classList.toggle("at-bottom", atBottom);
334
+ }
335
+ list.addEventListener("scroll", update);
336
+ if (typeof requestAnimationFrame === "function") {
337
+ requestAnimationFrame(update);
338
+ } else {
339
+ setTimeout(update, 0);
340
+ }
341
+ return update;
342
+ }
343
+
323
344
  // ── the business switcher (rail foot) ────────────────────────────────────
324
345
  function avatarEl(size, email, initials) {
325
346
  var box = el("span", "wps-avatar", { attrs: { role: "img" } });
@@ -374,11 +395,65 @@
374
395
  (opts.chevron ? el("span", "wps-dd-chevron", { children: [
375
396
  icon("chevron-right", 14, "thin")] }) : null)
376
397
  ],
377
- on: { click: function () { closePanel(); } }
398
+ on: { click: function (e) {
399
+ closePanel();
400
+ // An action row (e.g. Log out) supersedes its href: preventDefault so
401
+ // neither the browser nor the runtime's link router navigates the
402
+ // fallback href, then run the handler.
403
+ if (opts.onClick) {
404
+ if (e && e.preventDefault) e.preventDefault();
405
+ opts.onClick(e);
406
+ }
407
+ } }
378
408
  });
379
409
  return row;
380
410
  }
381
411
 
412
+ // Log out — mirrors space's handlelogOut: DELETE the token (the server drops
413
+ // the HttpOnly access/refresh cookies), wipe the readable auth cookies, then
414
+ // bounce to the accounts login (the same redirect the auth gate uses). A
415
+ // direct credentialed fetch — the workpeg.* client's allowlist (tables /
416
+ // rows / CDN) intentionally won't reach /users/token/.
417
+ function logout() {
418
+ var api = String(WP().apiBase || "https://api.workpeg.com")
419
+ .replace(/\/+$/, "");
420
+ var finish = function () {
421
+ clearAuthCookies();
422
+ if (typeof WP()._redirectToLogin === "function") {
423
+ WP()._redirectToLogin();
424
+ } else {
425
+ var base = String(WP().accountsBase || "https://accounts.workpeg.com")
426
+ .replace(/\/+$/, "");
427
+ var ns = (WP()._pegNamespace && WP()._pegNamespace()) || "";
428
+ var ep = (window.location && window.location.pathname) || "/";
429
+ window.location.href = base + "/login?peg=" +
430
+ encodeURIComponent(ns) + "&ep=" + encodeURIComponent(ep);
431
+ }
432
+ };
433
+ try {
434
+ fetch(api + "/v1/users/token/", {
435
+ method: "DELETE", credentials: "include"
436
+ }).then(finish, finish); // log out client-side even if the call fails
437
+ } catch (e) {
438
+ finish();
439
+ }
440
+ }
441
+
442
+ // Expire the readable auth cookies (the HttpOnly access/refresh are dropped
443
+ // by the DELETE). setCookie scopes them to the parent .workpeg.* domain, so
444
+ // clear them there too; on a non-Workpeg host just clear the current host.
445
+ function clearAuthCookies() {
446
+ if (typeof document === "undefined") return;
447
+ var host = (window.location && window.location.hostname) || "";
448
+ var at = host.indexOf("workpeg");
449
+ var domainAttr = at >= 0 ? "; domain=." + host.slice(at) : "";
450
+ var past = "; expires=Thu, 01 Jan 1970 00:00:00 GMT";
451
+ ["access_ttl", "cachedBusiness"].forEach(function (name) {
452
+ document.cookie = name + "=; path=/" + past;
453
+ if (domainAttr) document.cookie = name + "=; path=/" + domainAttr + past;
454
+ });
455
+ }
456
+
382
457
  function workspacePopup() {
383
458
  var listKids = (S.businesses || []).map(workspaceRow);
384
459
  var help = el("div", "wps-dd-row", {
@@ -396,15 +471,17 @@
396
471
  ] }));
397
472
  } }
398
473
  });
474
+ var wsList = el("div", "wps-ws-list", { children: listKids });
475
+ attachListFade(wsList);
399
476
  return el("div", "wps-ws-popup", { children: [
400
- el("div", "wps-ws-list", { children: listKids }),
477
+ wsList,
401
478
  popupLink("Add new business", "plus", bizHref("/new")),
402
479
  el("div", "wps-dd-hr"),
403
480
  popupLink("Profile", "user", bizHref("/profile")),
404
481
  popupLink("Settings", "settings", bizHref("/settings")),
405
482
  el("div", "wps-dd-hr"),
406
483
  help,
407
- popupLink("Log out", "logout", "/login")
484
+ popupLink("Log out", "logout", "/login", { onClick: logout })
408
485
  ] });
409
486
  }
410
487
 
@@ -779,7 +856,7 @@
779
856
  "align-items:stretch}",
780
857
  ".wps-header{position:sticky;top:0;display:flex;align-items:center;",
781
858
  "width:100%;box-sizing:border-box;z-index:5;margin-bottom:18px;",
782
- "padding:0 2px 0 var(--pg-collapse-pl-hdr);",
859
+ "padding:4px 2px 0 var(--pg-collapse-pl-hdr);",
783
860
  "transition:padding-left 0.18s " + EASE + "}",
784
861
  ".wps-logo-wrap{flex-grow:var(--pg-collapse-flex);flex-shrink:1;",
785
862
  "flex-basis:0;min-width:0;overflow:hidden;",
@@ -872,7 +949,16 @@
872
949
  ".wps-ws-list{max-height:calc(3.5 * 40px + 3 * 8px);overflow-y:auto;",
873
950
  "scrollbar-width:thin;",
874
951
  "scrollbar-color:rgba(128, 128, 128, 0.15) transparent;",
952
+ "--fade-size:24px;",
875
953
  "display:flex;flex-direction:column;gap:8px;margin-bottom:1px}",
954
+ /* Fade the list's bottom edge while it overflows (a "more below" hint);
955
+ drop the fade at the end. has-overflow / at-bottom are toggled by
956
+ attachListFade — mirrors the static-scaffold reference. */
957
+ ".wps-ws-list.has-overflow{-webkit-mask-image:linear-gradient(to bottom,",
958
+ "#000 calc(100% - var(--fade-size)),transparent);mask-image:linear-",
959
+ "gradient(to bottom,#000 calc(100% - var(--fade-size)),transparent)}",
960
+ ".wps-ws-list.has-overflow.at-bottom{-webkit-mask-image:none;",
961
+ "mask-image:none}",
876
962
  ".wps-ws-row{display:flex;align-items:center;gap:8px;padding:6px;",
877
963
  "border-radius:8px;cursor:pointer;width:100%;box-sizing:border-box;",
878
964
  "transition:background 0.18s " + EASE + "}",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workpeg
3
- Version: 0.96.2
3
+ Version: 0.96.4
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