samagotchi 0.155.0 → 0.157.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 (234) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -1
  3. data/bin/chi +2 -1
  4. data/docs/architecture.md +22 -13
  5. data/docs/bundles.md +3 -1
  6. data/docs/cli.md +9 -8
  7. data/docs/configuration.md +36 -4
  8. data/docs/guardrails.md +9 -5
  9. data/docs/hooks.md +11 -5
  10. data/docs/internals/anthropic.md +1 -1
  11. data/docs/internals/attached-context.md +3 -2
  12. data/docs/internals/background-tasks.md +1 -1
  13. data/docs/internals/bridge.md +83 -6
  14. data/docs/internals/bundles.md +28 -18
  15. data/docs/internals/context-telemetry.md +4 -3
  16. data/docs/internals/engine.md +641 -937
  17. data/docs/internals/llm-context-forget.md +8 -3
  18. data/docs/internals/objectives.md +2 -2
  19. data/docs/internals/participants.md +3 -2
  20. data/docs/internals/prompt-caching.md +4 -1
  21. data/docs/internals/remote-sessions.md +8 -3
  22. data/docs/internals/web-frontend.md +3 -2
  23. data/docs/internals/working-set.md +2 -2
  24. data/docs/memory.md +13 -2
  25. data/docs/plugins.md +35 -2
  26. data/docs/sessions.md +11 -11
  27. data/docs/sub-agent.md +17 -2
  28. data/docs/system-one.md +3 -2
  29. data/docs/testing.md +53 -2
  30. data/lib/samagotchi/answer_command.rb +2 -1
  31. data/lib/samagotchi/archive_store.rb +4 -3
  32. data/lib/samagotchi/bootstrap/config_writer.rb +1 -1
  33. data/lib/samagotchi/bootstrap_command.rb +3 -2
  34. data/lib/samagotchi/bridge/card_places.rb +10 -4
  35. data/lib/samagotchi/bridge/card_store.rb +3 -0
  36. data/lib/samagotchi/bridge/turn_accumulator.rb +109 -9
  37. data/lib/samagotchi/bridge/turn_drawings.rb +265 -0
  38. data/lib/samagotchi/bridge.rb +31 -6
  39. data/lib/samagotchi/broadcast/recipients.rb +8 -8
  40. data/lib/samagotchi/broadcast/triage_model.rb +1 -1
  41. data/lib/samagotchi/broadcast_command.rb +3 -3
  42. data/lib/samagotchi/bundle_command/check.rb +18 -0
  43. data/lib/samagotchi/bundle_command/try/sandbox.rb +2 -2
  44. data/lib/samagotchi/bundle_command/try/trace.rb +1 -1
  45. data/lib/samagotchi/bundle_command.rb +5 -2
  46. data/lib/samagotchi/bundles/known-names/manifest.yml +4 -7
  47. data/lib/samagotchi/bundles/known-names/{hooks/known_names.rb → plugin.rb} +17 -0
  48. data/lib/samagotchi/bundles/source-links/manifest.yml +4 -7
  49. data/lib/samagotchi/bundles/source-links/{hooks/source_links.rb → plugin.rb} +23 -4
  50. data/lib/samagotchi/bundles/system/config_modification_protocol.md +2 -2
  51. data/lib/samagotchi/bundles/system/manifest.yml +3 -3
  52. data/lib/samagotchi/bundles/system/memory_guide.md +1 -1
  53. data/lib/samagotchi/child_move.rb +13 -57
  54. data/lib/samagotchi/child_reports.rb +2 -2
  55. data/lib/samagotchi/children_status.rb +15 -21
  56. data/lib/samagotchi/cli/parent_wait.rb +9 -23
  57. data/lib/samagotchi/config.rb +20 -112
  58. data/lib/samagotchi/context_command.rb +1 -2
  59. data/lib/samagotchi/context_sources.rb +5 -4
  60. data/lib/samagotchi/context_window.rb +9 -12
  61. data/lib/samagotchi/desktop/macos.rb +1 -1
  62. data/lib/samagotchi/effective_model.rb +57 -22
  63. data/lib/samagotchi/engine/context_judge.rb +19 -11
  64. data/lib/samagotchi/engine/messages.rb +1 -1
  65. data/lib/samagotchi/engine/models.rb +5 -2
  66. data/lib/samagotchi/engine/objectives.rb +29 -11
  67. data/lib/samagotchi/engine/plugins.rb +1 -1
  68. data/lib/samagotchi/engine/recap.rb +8 -4
  69. data/lib/samagotchi/engine/side_requests.rb +21 -11
  70. data/lib/samagotchi/engine/toolkit.rb +10 -9
  71. data/lib/samagotchi/engine/turn_end.rb +1 -1
  72. data/lib/samagotchi/engine/turn_helpers.rb +7 -7
  73. data/lib/samagotchi/engine/verify.rb +1 -1
  74. data/lib/samagotchi/engine.rb +43 -12
  75. data/lib/samagotchi/events.rb +3 -2
  76. data/lib/samagotchi/extension_load.rb +6 -3
  77. data/lib/samagotchi/guardrails/targets.rb +24 -9
  78. data/lib/samagotchi/guardrails_command.rb +1 -1
  79. data/lib/samagotchi/host_address.rb +52 -0
  80. data/lib/samagotchi/host_config.rb +72 -1
  81. data/lib/samagotchi/host_model.rb +2 -6
  82. data/lib/samagotchi/host_registry.rb +58 -46
  83. data/lib/samagotchi/kernel_loop.rb +53 -124
  84. data/lib/samagotchi/llm/anthropic_wire.rb +2 -2
  85. data/lib/samagotchi/llm/chat_loop.rb +40 -21
  86. data/lib/samagotchi/llm/native_backend.rb +1 -1
  87. data/lib/samagotchi/llm_context_apply.rb +54 -1
  88. data/lib/samagotchi/llm_context_notice.rb +1 -1
  89. data/lib/samagotchi/llm_context_strategy.rb +29 -67
  90. data/lib/samagotchi/llm_context_view.rb +9 -0
  91. data/lib/samagotchi/memory_bundle/asset_installer.rb +71 -76
  92. data/lib/samagotchi/memory_bundle/builder.rb +2 -1
  93. data/lib/samagotchi/memory_bundle/file_actions.rb +193 -0
  94. data/lib/samagotchi/memory_bundle/file_digest.rb +13 -0
  95. data/lib/samagotchi/memory_bundle/file_state.rb +152 -0
  96. data/lib/samagotchi/memory_bundle/installed_copy.rb +2 -1
  97. data/lib/samagotchi/memory_bundle/installed_manifest.rb +8 -1
  98. data/lib/samagotchi/memory_bundle/installer.rb +185 -169
  99. data/lib/samagotchi/memory_bundle/manifest.rb +14 -4
  100. data/lib/samagotchi/memory_bundle/merger.rb +69 -65
  101. data/lib/samagotchi/memory_bundle/plugin_ref.rb +6 -5
  102. data/lib/samagotchi/memory_bundle/profile.rb +5 -5
  103. data/lib/samagotchi/memory_bundle/provenance.rb +15 -1
  104. data/lib/samagotchi/memory_bundle/remerge.rb +25 -12
  105. data/lib/samagotchi/memory_bundle/shipped_update.rb +51 -6
  106. data/lib/samagotchi/memory_bundle/status.rb +14 -20
  107. data/lib/samagotchi/memory_bundle/system_bundle.rb +24 -6
  108. data/lib/samagotchi/memory_bundle/trash.rb +23 -8
  109. data/lib/samagotchi/memory_bundle/uninstaller.rb +16 -11
  110. data/lib/samagotchi/memory_usage.rb +1 -1
  111. data/lib/samagotchi/model_lookup.rb +75 -0
  112. data/lib/samagotchi/model_price.rb +4 -10
  113. data/lib/samagotchi/model_profile.rb +7 -6
  114. data/lib/samagotchi/model_settings.rb +37 -2
  115. data/lib/samagotchi/models_command.rb +1 -1
  116. data/lib/samagotchi/note_command.rb +2 -3
  117. data/lib/samagotchi/objectives_audit.rb +4 -3
  118. data/lib/samagotchi/participant_mode.rb +2 -1
  119. data/lib/samagotchi/participants.rb +2 -2
  120. data/lib/samagotchi/plugin/api.rb +41 -6
  121. data/lib/samagotchi/plugin/context.rb +1 -1
  122. data/lib/samagotchi/plugin/loader.rb +33 -10
  123. data/lib/samagotchi/plugin/sessions.rb +3 -6
  124. data/lib/samagotchi/plugin/tool_spec.rb +5 -3
  125. data/lib/samagotchi/project_env.rb +1 -1
  126. data/lib/samagotchi/reasoning_history.rb +14 -20
  127. data/lib/samagotchi/recap_place.rb +27 -0
  128. data/lib/samagotchi/reminder_carry.rb +1 -1
  129. data/lib/samagotchi/reply_wait/liveness.rb +38 -0
  130. data/lib/samagotchi/reply_wait/poll.rb +44 -15
  131. data/lib/samagotchi/reply_wait/target.rb +113 -0
  132. data/lib/samagotchi/reply_wait.rb +22 -2
  133. data/lib/samagotchi/reprefill_meter.rb +45 -0
  134. data/lib/samagotchi/review_command.rb +1 -1
  135. data/lib/samagotchi/sampling_settings.rb +9 -16
  136. data/lib/samagotchi/self_report.rb +36 -37
  137. data/lib/samagotchi/send_command.rb +17 -23
  138. data/lib/samagotchi/session.rb +370 -445
  139. data/lib/samagotchi/session_access/local.rb +12 -11
  140. data/lib/samagotchi/session_access/remote.rb +22 -6
  141. data/lib/samagotchi/session_archive_command.rb +2 -2
  142. data/lib/samagotchi/session_chain.rb +7 -6
  143. data/lib/samagotchi/session_continue.rb +6 -5
  144. data/lib/samagotchi/session_delete_command.rb +1 -1
  145. data/lib/samagotchi/session_field.rb +133 -0
  146. data/lib/samagotchi/session_inbox.rb +49 -1
  147. data/lib/samagotchi/session_manager/delivery.rb +254 -0
  148. data/lib/samagotchi/session_manager/emptiness.rb +139 -0
  149. data/lib/samagotchi/session_manager/lifecycle.rb +274 -0
  150. data/lib/samagotchi/session_manager/listing.rb +118 -0
  151. data/lib/samagotchi/session_manager/removal.rb +190 -0
  152. data/lib/samagotchi/session_manager/spawn.rb +242 -0
  153. data/lib/samagotchi/session_manager/worker_command.rb +157 -0
  154. data/lib/samagotchi/session_manager.rb +28 -1541
  155. data/lib/samagotchi/session_metrics.rb +8 -5
  156. data/lib/samagotchi/session_paths.rb +57 -0
  157. data/lib/samagotchi/session_retention.rb +2 -2
  158. data/lib/samagotchi/session_row.rb +200 -0
  159. data/lib/samagotchi/session_setup.rb +15 -12
  160. data/lib/samagotchi/sessions_command.rb +11 -129
  161. data/lib/samagotchi/share_command.rb +1 -1
  162. data/lib/samagotchi/starting_marker.rb +65 -0
  163. data/lib/samagotchi/steer_cut_after.rb +7 -14
  164. data/lib/samagotchi/system_one/recorder.rb +49 -0
  165. data/lib/samagotchi/terminal_ui/attached_loop.rb +6 -26
  166. data/lib/samagotchi/terminal_ui/exit_lines.rb +1 -1
  167. data/lib/samagotchi/terminal_ui/join_replay.rb +86 -8
  168. data/lib/samagotchi/terminal_ui/local_link.rb +2 -2
  169. data/lib/samagotchi/terminal_ui.rb +5 -7
  170. data/lib/samagotchi/testing/install.rb +2 -1
  171. data/lib/samagotchi/testing/sessions.rb +1 -1
  172. data/lib/samagotchi/thinking.rb +16 -21
  173. data/lib/samagotchi/token_usage.rb +1 -1
  174. data/lib/samagotchi/tool_activity.rb +10 -4
  175. data/lib/samagotchi/tool_declarations.rb +2 -2
  176. data/lib/samagotchi/tool_output_cut.rb +17 -0
  177. data/lib/samagotchi/tool_response.rb +5 -3
  178. data/lib/samagotchi/tool_runner.rb +25 -5
  179. data/lib/samagotchi/toolkit_command.rb +1 -1
  180. data/lib/samagotchi/tools/delegate.rb +55 -45
  181. data/lib/samagotchi/tools/delegate_relay.rb +5 -5
  182. data/lib/samagotchi/tools/delegate_result.rb +5 -5
  183. data/lib/samagotchi/tools/delegate_wait.rb +41 -17
  184. data/lib/samagotchi/tools/index_hint.rb +14 -0
  185. data/lib/samagotchi/tools/list_sessions.rb +7 -7
  186. data/lib/samagotchi/tools/registry.rb +28 -11
  187. data/lib/samagotchi/tools/send_note.rb +4 -6
  188. data/lib/samagotchi/tools/tool_index.rb +52 -51
  189. data/lib/samagotchi/tools/tool_surface.rb +22 -8
  190. data/lib/samagotchi/turn_context.rb +2 -1
  191. data/lib/samagotchi/turn_stages/context_judge.rb +38 -36
  192. data/lib/samagotchi/turn_stages/objectives.rb +56 -52
  193. data/lib/samagotchi/turn_stages/toolkit_suggestion.rb +13 -17
  194. data/lib/samagotchi/turn_stages/verify_anchors.rb +9 -10
  195. data/lib/samagotchi/turn_stages/warmup.rb +14 -15
  196. data/lib/samagotchi/update_command.rb +11 -7
  197. data/lib/samagotchi/verify_fresh.rb +7 -11
  198. data/lib/samagotchi/version.rb +1 -1
  199. data/lib/samagotchi/vision_support.rb +11 -14
  200. data/lib/samagotchi/web/app.rb +45 -28
  201. data/lib/samagotchi/web/message_display.rb +57 -7
  202. data/lib/samagotchi/web/participant_access.rb +3 -3
  203. data/lib/samagotchi/web/public/activity.js +16 -7
  204. data/lib/samagotchi/web/public/app.js +29 -8
  205. data/lib/samagotchi/web/public/bubbles.js +8 -3
  206. data/lib/samagotchi/web/public/cards_place.js +15 -0
  207. data/lib/samagotchi/web/public/commands.js +5 -1
  208. data/lib/samagotchi/web/public/data.js +4 -2
  209. data/lib/samagotchi/web/public/history_shape.js +220 -0
  210. data/lib/samagotchi/web/public/recap_stamp.js +17 -0
  211. data/lib/samagotchi/web/public/reload_check.js +71 -0
  212. data/lib/samagotchi/web/public/stage_model.js +7 -5
  213. data/lib/samagotchi/web/public/stage_view.js +7 -3
  214. data/lib/samagotchi/web/public/stream_handlers.js +8 -2
  215. data/lib/samagotchi/web/public/timing.js +43 -2
  216. data/lib/samagotchi/web/public/turn_block.js +215 -30
  217. data/lib/samagotchi/web/public/turn_drawing.js +43 -0
  218. data/lib/samagotchi/web/public/turn_events.js +10 -1
  219. data/lib/samagotchi/web/public/turn_pieces.js +29 -0
  220. data/lib/samagotchi/web/reload_check_route.rb +95 -0
  221. data/lib/samagotchi/web/server.rb +4 -2
  222. data/lib/samagotchi/web/session_access_routes.rb +6 -6
  223. data/lib/samagotchi/web/session_control.rb +4 -4
  224. data/lib/samagotchi/web/session_create.rb +3 -3
  225. data/lib/samagotchi/web/session_hub.rb +9 -17
  226. data/lib/samagotchi/web/session_show.rb +67 -5
  227. data/lib/samagotchi/web/session_summary.rb +39 -28
  228. data/lib/samagotchi/worker.rb +83 -32
  229. data/lib/samagotchi/worker_boot.rb +184 -0
  230. data/lib/samagotchi/worker_link.rb +3 -0
  231. data/lib/samagotchi/worker_signals.rb +1 -1
  232. data/lib/samagotchi/worker_task_wakes.rb +2 -2
  233. metadata +32 -4
  234. data/lib/samagotchi/send_command/wait_target.rb +0 -85
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "file_digest"
4
+ require_relative "installed_bundle"
5
+ require_relative "provenance"
6
+
7
+ module Samagotchi
8
+ module MemoryBundle
9
+ # One bundle memory as a command meets it: which of a few states it is in,
10
+ # computed once from the file (D), its base (B), the bundle's text (I) and
11
+ # the record's entry (R). Derived, never stored. FileActions says what each
12
+ # acting command does in each state.
13
+ #
14
+ # kind, with a source (install, upgrade, remerge, restore, plan):
15
+ # :new not the bundle's, not on disk
16
+ # :user_same not the bundle's, on disk with I's bytes
17
+ # :user_file not the bundle's, other bytes (the user's own file)
18
+ # :missing the bundle's, not on disk
19
+ # :level the bundle's, D == I
20
+ # :pristine never edited (#edited?: D == R's checksum, or with
21
+ # none D == B): the bundle's text as installed
22
+ # :edited edited, D != B, I == B: the user changed it, the
23
+ # bundle didn't
24
+ # :diverged edited, D != B, I != B: both changed it
25
+ # :pristine_no_base no B, never edited (D == R's checksum)
26
+ # :edited_no_base no B, edited (or no checksum to tell); or a B equal
27
+ # to D that the checksum calls edited: no base to
28
+ # merge from
29
+ # :dropped_pristine / :dropped_edited / :dropped_missing the bundle no
30
+ # longer ships it (no I): unedited, edited, gone
31
+ # :unreadable on disk, but it can't be read
32
+ # Edited or not is always the one rule (#edited?, the checksum first);
33
+ # the base then says what the user changed.
34
+ #
35
+ # kind, with no source (status, uninstall, diff): I is unknown, so only
36
+ # :pristine :edited :pristine_no_base :edited_no_base :missing :unreadable,
37
+ # from #edited? alone.
38
+ #
39
+ # mark: :none, :current (a mark this chi wrote) or :legacy (an older
40
+ # chi's, InstalledBundle.legacy_mark?).
41
+ FileState = Data.define(:key, :kind, :mark, :digests, :entry, :paths, :claimants) do
42
+ # Provenance.unchanged?'s answer negated: the one edited rule (checksum
43
+ # first, then the base). A file it can't read counts as edited.
44
+ def edited?
45
+ return false if entry.nil?
46
+
47
+ !Provenance.unchanged?(paths[:current], entry, paths[:base])
48
+ rescue SystemCallError
49
+ true
50
+ end
51
+
52
+ def marked? = mark != :none
53
+
54
+ # A marked file whose source moved since the mark: the mark speaks of
55
+ # other text than the bundle ships now (Remerge's first question). A mark
56
+ # that names no text (an older chi's) never moved.
57
+ def source_moved?
58
+ marked? && !digests.marked_incoming.nil? && !digests.incoming.nil? && digests.marked_incoming != digests.incoming
59
+ end
60
+
61
+ # The other installed bundles that list the file too. Asked lazily: only
62
+ # a dropped file and an uninstall need it (Provenance.claimants reads
63
+ # every record).
64
+ def shared_with = claimants.call
65
+ end
66
+
67
+ # The digests of the file's texts, each read once: disk (:unreadable when
68
+ # it can't be read), base, incoming (nil with no source), the record's
69
+ # checksum, and the text a mark speaks of (nil without a mark or for an
70
+ # older chi's mark).
71
+ FileState::Digests = Data.define(:disk, :base, :incoming, :recorded, :marked_incoming)
72
+
73
+ class << FileState
74
+ # @param record [InstalledBundle, nil] the bundle's record
75
+ # @param provenance [Provenance] the record's (for the base path)
76
+ # @param source_dir [String, nil] the bundle's incoming dir; nil: the
77
+ # source-less kinds
78
+ # @param claimants [#call, nil] key => other bundles listing it
79
+ # (Provenance.claimants), called at most once
80
+ # @param shipped [Boolean] false: the bundle no longer ships the key
81
+ # (a dropped kind), whatever its source dir holds by that name
82
+ # @return [FileState]
83
+ def of(key, record:, provenance:, target_dir:, source_dir:, claimants: nil, shipped: true)
84
+ entry = record&.files&.fetch(key, nil)
85
+ paths = { base: provenance.base_path(key), current: File.join(target_dir, key),
86
+ incoming: source_dir && File.join(source_dir, key) }
87
+ mark = mark_of(entry)
88
+ digests = FileState::Digests.new(
89
+ disk: digest(paths[:current]), base: entry ? digest(paths[:base]) : nil,
90
+ incoming: source_dir && shipped ? digest(paths[:incoming]) : nil, recorded: entry && Provenance.recorded_sha(entry[:checksum]),
91
+ marked_incoming: mark == :none ? nil : entry[:incoming_sha]
92
+ )
93
+ shared = nil
94
+ lookup = -> { shared ||= claimants ? claimants.call(key) : [] }
95
+ state = FileState.new(key: key, kind: nil, mark: mark, digests: digests, entry: entry, paths: paths, claimants: lookup)
96
+ state.with(kind: source_dir ? kind_with_source(state) : kind_without_source(state))
97
+ end
98
+
99
+ private
100
+
101
+ def mark_of(entry)
102
+ return :none unless entry && entry[:conflict]
103
+
104
+ InstalledBundle.legacy_mark?(entry) ? :legacy : :current
105
+ end
106
+
107
+ def digest(path)
108
+ FileDigest.hex(path)
109
+ rescue SystemCallError
110
+ :unreadable
111
+ end
112
+
113
+ def kind_with_source(state)
114
+ d = state.digests
115
+ return not_owned(d) unless state.entry
116
+ return :unreadable if d.disk == :unreadable
117
+ return dropped(state) if d.incoming.nil?
118
+ return :missing if d.disk.nil?
119
+ return :level if d.disk == d.incoming
120
+ return state.edited? ? :edited_no_base : :pristine_no_base if d.base.nil?
121
+ return :pristine unless state.edited?
122
+ # Edited by the one rule, yet equal to its base: the base can't say
123
+ # what the user changed (it isn't the text the record vouches for),
124
+ # so there is none to merge from.
125
+ return :edited_no_base if d.disk == d.base
126
+
127
+ d.incoming == d.base ? :edited : :diverged
128
+ end
129
+
130
+ def kind_without_source(state)
131
+ d = state.digests
132
+ return :unreadable if d.disk == :unreadable
133
+ return :missing if d.disk.nil?
134
+ return state.edited? ? :edited_no_base : :pristine_no_base if d.base.nil?
135
+
136
+ state.edited? ? :edited : :pristine
137
+ end
138
+
139
+ def not_owned(digests)
140
+ return :new if digests.disk.nil?
141
+
142
+ digests.disk == digests.incoming ? :user_same : :user_file
143
+ end
144
+
145
+ def dropped(state)
146
+ return :dropped_missing if state.digests.disk.nil?
147
+
148
+ state.edited? ? :dropped_edited : :dropped_pristine
149
+ end
150
+ end
151
+ end
152
+ end
@@ -93,7 +93,8 @@ module Samagotchi
93
93
  return nil unless bundle.plugin
94
94
 
95
95
  file = bundle.plugin.file
96
- { file: file, sha256: copy(provenance.plugin_path(bundle), File.join(dir, file), bundle.plugin.sha256) }
96
+ { file: file, sha256: copy(provenance.plugin_path(bundle), File.join(dir, file), bundle.plugin.sha256),
97
+ required: bundle.manifest.plugin_required }
97
98
  end
98
99
  private_class_method :plugin
99
100
 
@@ -50,6 +50,11 @@ module Samagotchi
50
50
  # as Manifest reads them (settings nil when
51
51
  # the manifest said nothing of them)
52
52
  # file_descriptions file key => the memory's description
53
+ # plugin_required plugin: required: true (a guardrail plugin:
54
+ # one that fails to load denies every tool
55
+ # call): the record's (PluginRef#required,
56
+ # recorded at install) or the kept manifest's,
57
+ # so a lost or edited kept file keeps it
53
58
  # includes a profile's recorded members (the record's
54
59
  # identity, never the kept file's), nil for a plain bundle
55
60
  # unknown_keys the kept manifest's keys this chi doesn't know
@@ -59,7 +64,7 @@ module Samagotchi
59
64
  class InstalledManifest < Data.define(:name, :version, :requires_chi, :trust_level, :description, :hooks, :needs,
60
65
  :script_names, :context_providers, :block_renderers, :session_settings,
61
66
  :session_setting_types, :settings, :setting_types, :file_descriptions,
62
- :includes, :unknown_keys, :floor_keys, :problems, :origin)
67
+ :plugin_required, :includes, :unknown_keys, :floor_keys, :problems, :origin)
63
68
  # The key problems names the kept file's standing under.
64
69
  KEPT_FILE = "manifest.yml"
65
70
  # How many manifests the cache holds before it starts again.
@@ -133,6 +138,7 @@ module Samagotchi
133
138
  session_settings: session.session_settings, session_setting_types: session.session_setting_types,
134
139
  settings: settings.settings, setting_types: settings.setting_types,
135
140
  file_descriptions: pick.call("files", kept.file_descriptions, mirrored.file_descriptions),
141
+ plugin_required: kept.plugin&.dig(:required) == true || mirrored.plugin_required,
136
142
  includes: bundle.includes,
137
143
  unknown_keys: kept.unknown_keys.map(&:to_s), floor_keys: floors(kept), problems: problems.freeze, origin: :kept)
138
144
  end
@@ -168,6 +174,7 @@ module Samagotchi
168
174
  settings: list(raw["settings"]),
169
175
  setting_types: types(raw["setting_types"]),
170
176
  file_descriptions: file_descriptions(bundle.files),
177
+ plugin_required: bundle.plugin&.required == true,
171
178
  includes: bundle.includes, unknown_keys: [], floor_keys: {}, problems: problems.freeze, origin: :record)
172
179
  end
173
180