samagotchi 0.145.0 → 0.146.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.
@@ -433,6 +433,8 @@ const questionCards = createQuestionCards({
433
433
  renderMarkdown,
434
434
  linkRefs: linkRefsIn,
435
435
  pairRefs: pairRefsIn,
436
+ // The bar's chip reads questionCards.pendingQuestion() (sessionWaits).
437
+ onPending: () => store.touch("infoBar"),
436
438
  });
437
439
  // The history's bubbles (bubbles.js): output, end lines, every client's
438
440
  // prompts, the recap, warnings and notices, command and note bubbles.
@@ -1508,9 +1510,11 @@ async function restartWorker() {
1508
1510
 
1509
1511
  // The session bar (info_bar_model.js sessionBar): its buttons, and the
1510
1512
  // info line rendered by info_bar.js.
1511
- // The open session waits on the user: its summary says so, or its card is up.
1513
+ // The open session waits on the user: its card is up, or its summary says so
1514
+ // (not for a question answered here: the summary is a refresh behind).
1512
1515
  function sessionWaits() {
1513
- return !!(waitingOn(store.sessions.find((s) => s.id === store.selected)) || questionCards.pendingQuestion());
1516
+ const summary = waitingOn(store.sessions.find((s) => s.id === store.selected));
1517
+ return !!((summary && !questionCards.isResolved(summary.id)) || questionCards.pendingQuestion());
1514
1518
  }
1515
1519
  function updateInfoBar() {
1516
1520
  annotateBar?.refresh();
@@ -18,6 +18,7 @@
18
18
  // blank the page.
19
19
 
20
20
  import { quoteBlock } from "./annotations.js";
21
+ import { isParticipantAuthor } from "./participant_model.js";
21
22
 
22
23
  // Where a node on the participant page came from: { kind, root, … } where
23
24
  // root is the element a selection is clipped to, or null.
@@ -69,7 +70,7 @@ export function participantQuote(text, source) {
69
70
  // participant route's: mine, author, author_name, automatic).
70
71
  export function messageAuthorData(message) {
71
72
  if (message?.mine) return { by: "me" };
72
- if (message?.author) return { by: "participant", name: message.author_name || "" };
73
+ if (isParticipantAuthor(message?.author)) return { by: "participant", name: message.author_name || "" };
73
74
  if (message?.automatic) return { by: "automatic" };
74
75
  return { by: "owner" };
75
76
  }
@@ -41,13 +41,18 @@ import { plainText } from "./plain_line.js";
41
41
  // own text; markdown_place.js pairRefsIn)
42
42
  // @param api {sendAnswer, dismissQuestion, sendCommand} (data.js)
43
43
  // @param doc the page's document
44
+ // @param onPending (pending|null) called whenever the open question changes:
45
+ // the page touches the redraws that read pendingQuestion() (the session
46
+ // bar's waiting chip, docs/internals/web-frontend.md write -> redraw)
44
47
  // @return {renderQuestion(pq, {said}), resolveQuestion(id, opts), removeQuestion(),
45
48
  // questionCard() (the live card or null), pendingQuestion() (or null),
49
+ // isResolved(id) (this page already saw that question answered),
46
50
  // renderContinue(offer), resolveContinue(data), forgetContinue()}
47
51
  export function createQuestionCards({
48
52
  sessionId, clientId, place, isNearBottom, scrollToEnd, removeHintIfEmpty, askingText = () => "",
49
53
  renderMarkdown = () => Promise.resolve(null), linkRefs = () => {}, pairRefs = () => {},
50
54
  api = { sendAnswer, dismissQuestion, sendCommand }, doc = globalThis.document,
55
+ onPending = () => {},
51
56
  }) {
52
57
  // Live ask_user_question card, keyed by pending question id. Re-rendered from
53
58
  // pending_question on session select so a reload mid-question restores it.
@@ -57,6 +62,16 @@ export function createQuestionCards({
57
62
  let continueEl = null;
58
63
  // card → the reply that asked it, drawn under the summary once resolved.
59
64
  const saidOf = new WeakMap();
65
+ // The question last answered here: a session summary fetched earlier still
66
+ // names it as pending until the next refresh (isResolved).
67
+ let resolvedId = null;
68
+
69
+ // The one way the open question changes: +onPending+ is the page's hook for
70
+ // the redraws that read it (the session bar's waiting chip).
71
+ function setPending(next) {
72
+ pending = next;
73
+ onPending(pending);
74
+ }
60
75
 
61
76
  // +said+: the asking reply when the caller knows it (a reloaded card: its
62
77
  // step's text, "" for none); else the running turn's (askingText).
@@ -65,8 +80,8 @@ export function createQuestionCards({
65
80
  if (action === "same") return;
66
81
  // A resolved card stays where it was; only a pending one is replaced.
67
82
  if (action === "keep") questionEl = null;
68
- else removeQuestionCard();
69
- pending = pq;
83
+ else replaceQuestionCard();
84
+ setPending(pq);
70
85
  removeHintIfEmpty();
71
86
 
72
87
  const approval = approvalView(pq);
@@ -424,7 +439,7 @@ export function createQuestionCards({
424
439
  // The parent relayed the open question, or no longer does (question_relay).
425
440
  function markRelayed(id, relayedTo) {
426
441
  if (!questionEl || !pending || String(pending.id) !== String(id)) return;
427
- pending = { ...pending, relayed_to: relayedTo || null };
442
+ setPending({ ...pending, relayed_to: relayedTo || null });
428
443
  questionEl.querySelector(".question-relayed")?.replaceWith(renderRelayedTo(pending));
429
444
  }
430
445
 
@@ -491,7 +506,8 @@ export function createQuestionCards({
491
506
  if (!questionEl.dataset.toggled) questionEl.open = false;
492
507
  // After the collapse: a card left open by hand renders at once.
493
508
  if (full) renderSaidOnOpen(questionEl, full, asked, refs);
494
- pending = null;
509
+ resolvedId = pending.id;
510
+ setPending(null);
495
511
  }
496
512
 
497
513
  // The body's copy as markdown, from the card's first open on (a reload
@@ -546,11 +562,18 @@ export function createQuestionCards({
546
562
  }
547
563
 
548
564
  function removeQuestionCard() {
549
- if (questionEl) {
550
- questionEl.remove();
551
- questionEl = null;
552
- }
553
- pending = null;
565
+ replaceQuestionCard();
566
+ setPending(null);
567
+ }
568
+
569
+ // The live card taken off the history because a new one takes its place:
570
+ // the question itself changes in the same step, so the hook is not touched
571
+ // for the in-between null.
572
+ function replaceQuestionCard() {
573
+ if (!questionEl) return;
574
+
575
+ questionEl.remove();
576
+ questionEl = null;
554
577
  }
555
578
 
556
579
  // ── continue card ──────────────────────────────────────────────────────────
@@ -653,6 +676,7 @@ export function createQuestionCards({
653
676
  removeQuestion: removeQuestionCard,
654
677
  questionCard: () => questionEl,
655
678
  pendingQuestion: () => pending,
679
+ isResolved: (id) => resolvedId !== null && String(resolvedId) === String(id),
656
680
  renderContinue: renderContinueCard,
657
681
  resolveContinue: resolveContinueCard,
658
682
  // The running turn's DOM was reset: a later offer draws a new card.
@@ -30,6 +30,7 @@ import { bubbleCopyText } from "./copy.js";
30
30
  import { foldLabel, keepRowInView, lineCount, readFolded, writeFold } from "./answer_fold.js";
31
31
  import { clip } from "./format.js";
32
32
  import { NOTE_BOUNDARY } from "./turn_range.js";
33
+ import { workerPredates } from "./worker_features.js";
33
34
  import { SWAPPED_CLASS, VIEW_CLASS, stepVersion, switcherTemplate, viewOf } from "./revise_switch.js";
34
35
 
35
36
  // The classes and attributes this module puts on the history.
@@ -113,12 +114,12 @@ export function versionChipText(count, at = count - 1) {
113
114
  // the worker predates Revise turns).
114
115
  export const REVISE_UNAVAILABLE = "restart this session to use Revise";
115
116
 
116
- // The feature gate (app.js featureGates): a live worker without the
117
- // "revise" feature predates Revise turns (chi web would answer 409
118
- // revise_unavailable). A worker that isn't up isn't asked: the send wakes a
119
- // new one, which has it (as Verify's gate, verify_preset.js).
117
+ // The feature gate (app.js featureGates): a live worker without the "revise"
118
+ // feature predates Revise turns (chi web would answer 409 revise_unavailable).
119
+ // A worker that isn't up isn't asked: the send wakes a new one, which has it
120
+ // (worker_features.js's rule, the same as Verify's gate).
120
121
  export function reviseWorkerUnavailable(workerFeatures, bridgeUp) {
121
- return bridgeUp === true && Array.isArray(workerFeatures) && !workerFeatures.includes("revise");
122
+ return workerPredates(workerFeatures, bridgeUp, "revise");
122
123
  }
123
124
  export function reviseChipText(label, { unavailable = false } = {}) {
124
125
  if (unavailable) return `Revise: ${REVISE_UNAVAILABLE}`;
@@ -6,6 +6,8 @@
6
6
  // module of its own: static JS is cached at unversioned URLs, and a new
7
7
  // export on an old module would blank the page.
8
8
 
9
+ import { workerPredates } from "./worker_features.js";
10
+
9
11
  export const VERIFY_PRESET = Object.freeze({
10
12
  label: "Verify",
11
13
  text: "Verify this claim against the code. If this session's context doesn't settle it, say so. "
@@ -14,8 +16,10 @@ export const VERIFY_PRESET = Object.freeze({
14
16
 
15
17
  export const VERIFY_UNAVAILABLE = "restart this session to use Verify";
16
18
 
19
+ // The Verify gate (app.js featureGates): a live worker without "verify"
20
+ // predates Verify turns (worker_features.js's rule).
17
21
  export function verifyWorkerUnavailable(workerFeatures, bridgeUp) {
18
- return bridgeUp === true && Array.isArray(workerFeatures) && !workerFeatures.includes("verify");
22
+ return workerPredates(workerFeatures, bridgeUp, "verify");
19
23
  }
20
24
 
21
25
  // +presets+ (annotate_presets.js parsePresets) with Verify after them.
@@ -0,0 +1,14 @@
1
+ // One rule for the worker-side feature gates: a worker that is up and whose
2
+ // features lack +feature+ predates it (chi web would answer 409
3
+ // <feature>_unavailable), so the page says so instead of offering the action.
4
+ // A worker that isn't up isn't asked: the send wakes a new one that has it.
5
+ // Used by Verify's gate (verify_preset.js) and Revise's (revise_stack.js).
6
+ //
7
+ // A new module: the page's modules are cached at unversioned URLs, and a new
8
+ // export of an old one (docs/internals/web-frontend.md) leaves a cached copy
9
+ // without it.
10
+
11
+ // @return [bool] true only for a live worker without the feature.
12
+ export function workerPredates(workerFeatures, bridgeUp, feature) {
13
+ return bridgeUp === true && Array.isArray(workerFeatures) && !workerFeatures.includes(feature);
14
+ }
@@ -235,7 +235,8 @@ module Samagotchi
235
235
  def shared_with(touch, key) = touch.share > 1 ? found_names(touch.run) - [key] : []
236
236
 
237
237
  # A memory_read's names (Tools::MemoryRead.parse_names: none for the
238
- # index listing), less the ones its output says weren't found.
238
+ # index listing), less the ones its output says weren't found. Public:
239
+ # `chi memory usage` counts reads the same way (MemoryUsage).
239
240
  def found_names(run)
240
241
  names = Tools::MemoryRead.parse_names(run.call[:content].to_s)
241
242
  last = run.text.split(ToolResponse::SEPARATOR).last.to_s
@@ -308,6 +309,6 @@ module Samagotchi
308
309
 
309
310
  def field(hash, key) = hash.key?(key) ? hash[key] : hash[key.to_s]
310
311
 
311
- private_class_method :all_touches, :touches, :failed?, :found_names, :shared_with, :item, :still_sent?, :dropped?, :with_id, :changed?, :stamp_of, :field
312
+ private_class_method :all_touches, :touches, :failed?, :shared_with, :item, :still_sent?, :dropped?, :with_id, :changed?, :stamp_of, :field
312
313
  end
313
314
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: samagotchi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.145.0
4
+ version: 0.146.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dedov
@@ -487,6 +487,7 @@ files:
487
487
  - lib/samagotchi/memory_command.rb
488
488
  - lib/samagotchi/memory_orphans.rb
489
489
  - lib/samagotchi/memory_paths.rb
490
+ - lib/samagotchi/memory_usage.rb
490
491
  - lib/samagotchi/message_parts.rb
491
492
  - lib/samagotchi/message_time.rb
492
493
  - lib/samagotchi/model_binding.rb
@@ -958,6 +959,7 @@ files:
958
959
  - lib/samagotchi/web/public/verify_card.css
959
960
  - lib/samagotchi/web/public/verify_preset.js
960
961
  - lib/samagotchi/web/public/verify_target.js
962
+ - lib/samagotchi/web/public/worker_features.js
961
963
  - lib/samagotchi/web/public/working_set.js
962
964
  - lib/samagotchi/web/public/working_set_rail.js
963
965
  - lib/samagotchi/web/public/working_set_view.js