samagotchi 0.146.0 → 0.148.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -1
  3. data/README.md +2 -2
  4. data/docs/architecture.md +14 -5
  5. data/docs/bundles.md +26 -16
  6. data/docs/cli.md +6 -2
  7. data/docs/configuration.md +19 -4
  8. data/docs/guardrails.md +25 -4
  9. data/docs/sessions.md +2 -2
  10. data/docs/system-one.md +1 -1
  11. data/lib/samagotchi/answer_tail.rb +1 -1
  12. data/lib/samagotchi/bundles/coordinator/guardrails/merge.yml +21 -0
  13. data/lib/samagotchi/bundles/coordinator/manifest.yml +7 -5
  14. data/lib/samagotchi/bundles/coordinator/plugin.rb +2 -1
  15. data/lib/samagotchi/bundles/coordinator/skill_coordinator.md +35 -13
  16. data/lib/samagotchi/bundles/system/manifest.yml +1 -1
  17. data/lib/samagotchi/config.rb +5 -0
  18. data/lib/samagotchi/guardrail_wiring.rb +11 -6
  19. data/lib/samagotchi/guardrails/approvals.rb +3 -1
  20. data/lib/samagotchi/guardrails/rules.rb +6 -1
  21. data/lib/samagotchi/guardrails/verdict.rb +21 -1
  22. data/lib/samagotchi/guardrails_command.rb +47 -3
  23. data/lib/samagotchi/run_options.rb +1 -0
  24. data/lib/samagotchi/send_command.rb +2 -1
  25. data/lib/samagotchi/session_chain.rb +91 -8
  26. data/lib/samagotchi/session_commands.rb +1 -1
  27. data/lib/samagotchi/session_continue.rb +3 -2
  28. data/lib/samagotchi/system_one/record.rb +17 -3
  29. data/lib/samagotchi/version.rb +1 -1
  30. data/lib/samagotchi/web/app.rb +1 -1
  31. data/lib/samagotchi/web/auto_update.rb +60 -5
  32. data/lib/samagotchi/web/public/app.js +5 -16
  33. data/lib/samagotchi/web/public/update_notice.js +22 -11
  34. data/lib/samagotchi/web/public/update_sheet.js +4 -1
  35. data/lib/samagotchi/web/session_access_routes.rb +1 -1
  36. data/lib/samagotchi/web/session_hub.rb +17 -4
  37. metadata +2 -1
@@ -17,12 +17,7 @@ export function mergeVersionState(current = {}, frame = {}) {
17
17
  if (has(frame, "update_blocked")) next.updateBlocked = known(frame.update_blocked) ? frame.update_blocked : null;
18
18
  if (has(frame, "auto")) next.auto = frame.auto === "install" ? "install" : "off";
19
19
  if (has(frame, "restart")) next.restart = frame.restart === "never" ? "never" : "idle";
20
- // The last install's chi_update state (a snapshot's, or a frame's): the
21
- // version an automatic one installs, while it hasn't failed.
22
- const run = frame.chi_update;
23
- if (run && run.operation === "install" && known(run.version)) {
24
- next.autoInstall = run.auto === true && run.state !== "failed" ? run.version : null;
25
- }
20
+ if (has(frame, "auto_offers")) next.autoOffers = known(frame.auto_offers) ? frame.auto_offers : null;
26
21
  return next;
27
22
  }
28
23
 
@@ -53,22 +48,23 @@ export function newerVersion(a, b) {
53
48
  // The toast for the versions as the page knows them, or null:
54
49
  // - loaded ≠ served: chi web restarted on another version; reload the page;
55
50
  // - installed newer than served: chi web runs an older chi than installed;
56
- // restart its workers or chi web; not for the version an automatic install
57
- // (+autoInstall+) brought with update.restart: idle, whose run restarts
58
- // them by itself (and pushes how it went);
51
+ // restart its workers or chi web; not with update.auto: install and
52
+ // update.restart: idle (and not blocked), where chi web restarts them by
53
+ // itself and pushes how it went, however that chi got installed, unless
54
+ // chi web says it won't or has been held for long (+autoOffers+);
59
55
  // - available newer than served: install it, unless the install is blocked;
60
56
  // with update.auto: install (and not blocked) chi web installs it by itself
61
57
  // once no turn runs: the notice says so, with no Update button.
62
58
  // Each has a key; one in +shown+ (a Set: what this tab already showed, as
63
59
  // every reconnect's snapshot says it again) is not shown twice.
64
60
  // @return {{key, text, reload: boolean} | null}
65
- export function versionNotice({ loaded, served, installed, available, updateBlocked, auto, restart, autoInstall,
61
+ export function versionNotice({ loaded, served, installed, available, updateBlocked, auto, restart, autoOffers,
66
62
  shown = new Set() } = {}) {
67
63
  let notice = null;
68
64
  if (known(loaded) && known(served) && loaded !== served) {
69
65
  notice = { key: `reload:${served}`, text: `chi was updated to ${served}`, reload: true };
70
66
  } else if (newerVersion(installed, served)) {
71
- const restartsByItself = auto === "install" && restart !== "never" && autoInstall === installed;
67
+ const restartsByItself = auto === "install" && restart !== "never" && !updateBlocked && autoOffers !== installed;
72
68
  if (!restartsByItself) {
73
69
  notice = {
74
70
  key: `installed:${installed}`,
@@ -101,6 +97,21 @@ export function versionNotice({ loaded, served, installed, available, updateBloc
101
97
  return notice && !shown.has(notice.key) ? notice : null;
102
98
  }
103
99
 
100
+ // The toast's words for an update operation's frame, or null: what runs and how
101
+ // it ended, for a tab whose sheet isn't open. An automatic run's worker passes
102
+ // say something only when one fails (the run ends in the Reload toast); a done
103
+ // install leaves it to the version toast; a snapshot repeats no ending.
104
+ export function updateFrameToast(data, { wasOpen = false, snapshot = false } = {}) {
105
+ if (wasOpen) return null;
106
+ if (data.auto && data.operation === "workers" && data.state !== "failed") return null;
107
+ const label = `${data.auto ? "Automatic " : ""}${data.operation === "install" ? "chi update" : "worker restart"}`
108
+ .replace(/^./, (c) => c.toUpperCase());
109
+ if (data.state === "running") return `${label} in progress`;
110
+ if (snapshot || !["done", "failed"].includes(data.state)) return null;
111
+ if (data.operation === "install" && data.state === "done") return null;
112
+ return `${label} ${data.state}`;
113
+ }
114
+
104
115
  // The info bar's badge for the open session's worker when it runs an older
105
116
  // chi than the newest installed (or than chi web, while that is unknown),
106
117
  // else null. A worker with the "restart" feature offers Restart; an older
@@ -45,9 +45,10 @@ function statusText(model) {
45
45
 
46
46
  // Both restarts, once a newer chi is installed (an install done here, or the
47
47
  // installed notice's toast) and nothing runs: either result keeps the other in reach.
48
+ // Not on an automatic run: it restarts them by itself.
48
49
  function restartActions(model) {
49
50
  const busy = ["starting", "running", "restarting"].includes(model.state);
50
- if (!model.restartable || busy) return nothing;
51
+ if (!model.restartable || model.auto || busy) return nothing;
51
52
  return html`<button type="button" class="ghost" data-act="restart-workers">Restart workers</button>
52
53
  <button type="button" class="ghost" data-act="restart-web">Restart chi web</button>`;
53
54
  }
@@ -125,6 +126,8 @@ export function createUpdateSheet({ dialog, update, restartWorkers, restartWeb }
125
126
  model = {
126
127
  ...model,
127
128
  ...data,
129
+ // A frame names auto only when it is true: this run's word, not the last one's.
130
+ auto: data.auto === true,
128
131
  rows: Array.isArray(data.rows) ? data.rows : [],
129
132
  };
130
133
  if (data.operation === "install" && data.state === "done") restartable = true;
@@ -274,7 +274,7 @@ module Samagotchi
274
274
  model_name: session_access.show(id).model_name,
275
275
  default_model: ModelProfile.default_model_name,
276
276
  parent_strategy: strategy_json(session_access.parent_strategy(id)),
277
- **(@hub&.chi_state || { version: VERSION, installed: nil, available: nil, update_blocked: nil, auto: "off", restart: "idle" }) })
277
+ **(@hub&.chi_state || { version: VERSION, installed: nil, available: nil, update_blocked: nil, auto: "off", restart: "idle", auto_offers: nil }) })
278
278
  rescue SessionManager::OwnedByTUI => e
279
279
  owned_by_tui(e)
280
280
  rescue SessionAccess::Refused => e
@@ -41,8 +41,7 @@ module Samagotchi
41
41
 
42
42
  # What a subscriber gets: `session` with {session: summary} for an
43
43
  # upsert, `session_gone` with {id:} for a removal, `chi` with
44
- # {version:, installed:, available:, update_blocked:} when chi version
45
- # state changes. seq is monotonic per
44
+ # the #chi_state fields when chi version state changes. seq is monotonic per
46
45
  # hub, for the log's sake: there is no replay.
47
46
  Event = Struct.new(:type, :seq, :data, keyword_init: true)
48
47
 
@@ -76,7 +75,7 @@ module Samagotchi
76
75
  # @param installed_versions [#newest] what is installed (InstalledVersions)
77
76
  # @param update_auto [String] update.auto, said in the chi state (the page's wording)
78
77
  # @param update_restart [String] update.restart, said beside it (whether
79
- # an automatic install's run restarts by itself: no Restart toast)
78
+ # a newer installed chi restarts by itself: no Restart toast)
80
79
  def initialize(state_dir:, manager: SessionManager, now: nil, scan_interval: SCAN_INTERVAL,
81
80
  full_probe_interval: FULL_PROBE_INTERVAL, installed_versions: InstalledVersions.new,
82
81
  update_auto: Config.get("update.auto"), update_restart: Config.get("update.restart"))
@@ -87,6 +86,7 @@ module Samagotchi
87
86
  @installed = nil
88
87
  @available = nil
89
88
  @update_blocked = nil
89
+ @auto_offers = nil
90
90
  @update_state = nil
91
91
  @manager = manager
92
92
  @now = now || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
@@ -164,7 +164,7 @@ module Samagotchi
164
164
  def chi_state
165
165
  @monitor.synchronize do
166
166
  { version: VERSION, installed: @installed, available: @available, update_blocked: @update_blocked,
167
- auto: @update_auto, restart: @update_restart }
167
+ auto: @update_auto, restart: @update_restart, auto_offers: @auto_offers }
168
168
  end
169
169
  end
170
170
 
@@ -180,6 +180,19 @@ module Samagotchi
180
180
  nil
181
181
  end
182
182
 
183
+ # AutoUpdate won't (or hasn't, for long) restart onto +version+ by itself:
184
+ # the page offers the restarts for it, in spite of update.auto. In memory:
185
+ # AutoUpdate says it again after a chi web restart.
186
+ def auto_offer_restart(version)
187
+ @monitor.synchronize do
188
+ next if @auto_offers == version
189
+
190
+ @auto_offers = version
191
+ emit("chi", chi_state)
192
+ end
193
+ nil
194
+ end
195
+
183
196
  # Publish the owner-triggered update's progress or result for current
184
197
  # tabs, and retain the latest state for a reconnect's snapshot.
185
198
  def publish_update(state:, rows:, progress: nil, operation: nil, version: nil, auto: false)
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.146.0
4
+ version: 0.148.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dedov
@@ -241,6 +241,7 @@ files:
241
241
  - lib/samagotchi/bundles/codex-peer/scripts/chi-peer-SKILL.md
242
242
  - lib/samagotchi/bundles/codex-peer/scripts/pair
243
243
  - lib/samagotchi/bundles/codex-peer/skill_codex_peer.md
244
+ - lib/samagotchi/bundles/coordinator/guardrails/merge.yml
244
245
  - lib/samagotchi/bundles/coordinator/manifest.yml
245
246
  - lib/samagotchi/bundles/coordinator/plugin.rb
246
247
  - lib/samagotchi/bundles/coordinator/skill_coordinator.md