ollama_chat 0.0.137 → 0.0.138

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '00825774cef8e349ad7666a4e3046995bfa4803216d75fe688c8479a3bfce6c2'
4
- data.tar.gz: 45f95f47c73c711686b479c49ac6fec3309fe3a68c385fb9d780e28f8f10dd13
3
+ metadata.gz: 170c9e2778ed0d581bda082eebc43d07a6c6e6a6cd99a0d1e0d3634a5281ca9f
4
+ data.tar.gz: e57e2eb4d990f10617e1574ae1f70d22741dd814cf945575cc2cb7fb882dd4be
5
5
  SHA512:
6
- metadata.gz: 157e6951f84674cae4cc74e3423f9569f6cb30efc92109d7b27538ed7424e4d938e03513b9d3d0044b233be9f74b06572218c4ab128b5881d4361424585bf285
7
- data.tar.gz: 98eed217eca3fc4e396110ec20729e9e10bad64e5bf40539df1768ccd70c21ede9896855ba94a4b551ab3133c3e6020f45383de2ef59e7e9e75206c168f685d7
6
+ metadata.gz: b5e6781664a38632da9d7a4f11900864b86b9e0049fcb66d6084777d0f8b4a85e762a57217c23817c77f0fb365592d5d659e3eab874aa270fa97b52a3e727c45
7
+ data.tar.gz: 6aa806be34d04830f4788dd452d6e8a078e848767978d6bf49d6fef39f3dbd92b3f61fd4dc203c9914491c1ab2d8fa432ff75bc3543bf385dffcda2333acbd83
data/CHANGES.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-28 v0.0.138
4
+
5
+ ### Features
6
+
7
+ - Added `OllamaChat::Utils::Redact` module with `redact_password` to mask
8
+ credentials in URLs for user-facing display.
9
+ - `memory_restore` now deduplicates entries by checking existing tags before
10
+ adding records, reporting the number of skipped duplicates.
11
+ - `OllamaChat::Utils::AnalyzeDirectory` now returns a `Hash` with `:height` and
12
+ `:entries` keys instead of a bare `Array`. Entry hashes no longer include
13
+ `:type` or `:name`; directories are identified by a trailing `/` in `:path`.
14
+
15
+ ### Fixes
16
+
17
+ - `use_model` now raises `OllamaChat::UnknownModelError` if the previous model
18
+ is missing or blank after a cancelled pull, preventing stale metadata from
19
+ being returned.
20
+ - Fixed `update_collection` to use `Set` for the `seen` variable, resolving a
21
+ latent `NoMethodError` when upstream yields a `Set`.
22
+ - Corrected the error message in `pull_model_unless_present` to reference the
23
+ `model` parameter instead of the potentially stale `@model` instance
24
+ variable.
25
+
26
+ ### Improvements
27
+
28
+ - Applied password redaction to all user-visible URL displays, including
29
+ `Chat#inspect`, `Dialog#connect_message`, `Information#info_rag`,
30
+ `Information#print_welcome`, `Tools::Browse#execute`,
31
+ `Tools::GenerateImage#execute`, and `Fetcher.get`.
32
+ - Standardized `Set` insertion to use the `<<` idiom across `conversation.rb`,
33
+ `http_handling.rb`, `rag_handling.rb`, `generate_image.rb`, and
34
+ `web_searching.rb`.
35
+ - Added `<<` alias to `LinksSet` to support the standard `Set` insertion idiom.
36
+ - `AnalyzeDirectory` now omits the `:children` key from directory entries when
37
+ the array is empty, both during build and pruning.
38
+
39
+ ### Build & CI
40
+
41
+ - Added `lib/ollama_chat/utils/redact.rb` to the gemspec file list.
42
+
43
+ ### Testing
44
+
45
+ - Updated `analyze_directory_spec.rb`, `parsing_spec.rb`, and
46
+ `list_directory_spec.rb` to assert the new `AnalyzeDirectory` return
47
+ structure.
48
+ - Added specs for `redact_password` covering URI/String inputs, passthrough for
49
+ URLs without passwords, and non-mutation of the original object.
50
+ - Added specs for `memory_restore` deduplication logic, covering partial and
51
+ full skip scenarios.
52
+ - Updated `web_searching_spec.rb` to expect `<<` instead of `add` for link
53
+ insertion.
54
+
55
+ ### Documentation
56
+
57
+ - Updated `execute_grep` tool description to explicitly state that the regex
58
+ runs against file contents.
59
+ - Updated YARD documentation for `AnalyzeDirectory` to reflect the new return
60
+ value structure.
61
+
3
62
  ## 2026-10-23 v0.0.137
4
63
 
5
64
  ### Fixes
@@ -344,7 +344,7 @@ class OllamaChat::Chat
344
344
  #
345
345
  # @return [String] the inspected string
346
346
  def inspect
347
- "#<#{self.class}: #{base_url.to_s}>"
347
+ "#<#{self.class}: #{redact_password(base_url)}>"
348
348
  end
349
349
 
350
350
  # Returns the tool call processor instance.
@@ -86,7 +86,7 @@ module OllamaChat::Conversation
86
86
  selected.merge(remaining)
87
87
  break
88
88
  else
89
- selected.add(choice)
89
+ selected << choice
90
90
  end
91
91
  end
92
92
  end
@@ -142,7 +142,7 @@ module OllamaChat::Dialog
142
142
  # distinguish the connection type, e.g. `"embedding "` for a dedicated
143
143
  # embedding host (default: `""`)
144
144
  def connect_message(base_url:, prefix: '')
145
- feedback green { "Connecting to #{prefix}ollama #{base_url.to_s.inspect}…" }, type: :info
145
+ feedback green { "Connecting to #{prefix}ollama #{redact_password(base_url).inspect}…" }, type: :info
146
146
  end
147
147
 
148
148
  # Displays a success-level feedback message confirming that a
@@ -61,7 +61,7 @@ module OllamaChat::HTTPHandling
61
61
  # @yield [IO] yields a temporary file handle for the caller to consume.
62
62
  # @return [Object] the result of the block or the fetcher.
63
63
  def get_url(url, headers: nil, cache: nil, remember: true, &block)
64
- remember and links.add(url.to_s)
64
+ remember and links << url.to_s
65
65
  headers = config.request_headers?.to_h | headers
66
66
  OllamaChat::Utils::Fetcher.get(
67
67
  url,
@@ -16,6 +16,7 @@
16
16
  # chat.usage
17
17
  module OllamaChat::Information
18
18
  extend Tins::Concern
19
+ include OllamaChat::Utils::Redact
19
20
 
20
21
  included do
21
22
  include UserAgent
@@ -190,7 +191,7 @@ module OllamaChat::Information
190
191
  def info_rag(output: STDOUT)
191
192
  if embedding.on?
192
193
  if base_url = OC::OLLAMA::EMBEDDING_URL?
193
- output.puts "🔌 Connected to embedding ollama server on: #{base_url.to_s.inspect}"
194
+ output.puts "🔌 Connected to embedding ollama server on: #{redact_password(base_url)}"
194
195
  end
195
196
  output.puts "🗄️ Current RAG model is #{bold{@embedding_model}}"
196
197
  if @embedding_model_options.present?
@@ -220,7 +221,7 @@ module OllamaChat::Information
220
221
  def print_welcome(output: STDOUT)
221
222
  feedback(<<~EOT, output:)
222
223
  💎 Running ollama_chat version: #{bold{OllamaChat::VERSION}}
223
- 🔌 Connected to ollama server version: #{bold{server_version}} on: #{bold{server_url}}
224
+ 🔌 Connected to ollama server version: #{bold{server_version}} on: #{bold{redact_password(server_url)}}
224
225
  EOT
225
226
  end
226
227
 
@@ -23,6 +23,7 @@ class OllamaChat::LinksSet
23
23
  @set.add(x)
24
24
  sync
25
25
  end
26
+ alias << add
26
27
 
27
28
  # Removes all links from the set and synchronizes it with the session.
28
29
  #
@@ -465,7 +465,7 @@ module OllamaChat::ModelHandling
465
465
  if model_metadata = model_present?(model, ollama:)
466
466
  return model_metadata
467
467
  end
468
- raise OllamaChat::UnknownModelError, "unknown model named #{@model.inspect}"
468
+ raise OllamaChat::UnknownModelError, "unknown model named #{model.inspect}"
469
469
  end
470
470
  end
471
471
 
@@ -587,17 +587,25 @@ module OllamaChat::ModelHandling
587
587
  old_model = @model
588
588
 
589
589
  if model.blank?
590
- @model = choose_model('', @model)
590
+ new_model = choose_model('', old_model)
591
591
  else
592
- @model = choose_model(model, config.model.name)
592
+ new_model = choose_model(model, config.model.name)
593
593
  end
594
594
 
595
- if @model_metadata = model_present?(@model, ollama:)
596
- session.update(current_model: @model)
597
- else
598
- session.update(current_model: nil)
595
+ unless model_metadata = model_present?(new_model, ollama:)
596
+ feedback("Model #{bold{new_model}} not found locally.", type: :warn)
597
+ unless confirm?(prompt: "Pull it from remote? (y/n) ", yes: /\Ay/i)
598
+ feedback("Cancelled.", type: :cancel)
599
+ old_model.full? && model_present?(old_model, ollama:) or
600
+ raise OllamaChat::UnknownModelError, "no usable model after cancel"
601
+ return @model_metadata
602
+ end
603
+ model_metadata = pull_model_unless_present(new_model, ollama:)
599
604
  end
600
605
 
606
+ @model, @model_metadata = new_model, model_metadata
607
+ session.update(current_model: @model)
608
+
601
609
  if old_model != @model
602
610
  reconfigure_model_options(profile:, keep_options:)
603
611
  if @model_metadata&.can?('thinking')
@@ -122,7 +122,7 @@ module OllamaChat::RAGHandling
122
122
  selected.merge(remaining)
123
123
  break
124
124
  else
125
- selected.add(choice)
125
+ selected << choice
126
126
  end
127
127
  end
128
128
  end
@@ -202,7 +202,7 @@ module OllamaChat::RAGHandling
202
202
  selected.merge(remaining)
203
203
  break
204
204
  else
205
- selected.add(choice)
205
+ selected << choice
206
206
  end
207
207
  end
208
208
  end
@@ -213,14 +213,25 @@ module OllamaChat::RAGHandling
213
213
 
214
214
  feedback("Restoring #{selected.size} collection(s): #{selected.join(', ')}")
215
215
 
216
- total = 0
216
+ total = 0
217
+ skipped = 0
217
218
  collections.slice(*selected).sort.each do |col, group|
218
219
  create_memory_collection(col)
219
220
  switch_collection(col) do
221
+ existing_tags = Set.new
222
+ @documents.each_record do |r|
223
+ r.tags.each { |t| existing_tags << t.to_s(link: false) }
224
+ end
225
+
220
226
  group.each do |entry|
227
+ tags = Array(entry['tags'])
228
+ if tags.any? { |t| existing_tags.include?(t) }
229
+ skipped += 1
230
+ next
231
+ end
221
232
  @documents.add(
222
233
  [entry['text']],
223
- tags: Array(entry['tags']),
234
+ tags:,
224
235
  batch_size: 1,
225
236
  source: entry['source']
226
237
  )
@@ -230,9 +241,10 @@ module OllamaChat::RAGHandling
230
241
  end
231
242
 
232
243
  log(:info, 'Memory restored',
233
- data: { file: filename.to_s, collections: selected, records: total })
244
+ data: { file: filename.to_s, collections: selected, records: total, skipped: })
234
245
  feedback(
235
- "Restored #{total} record(s) across #{selected.size} collection(s) from #{filename.to_s.inspect}.",
246
+ "Restored #{total} record(s) across #{selected.size} collection(s) from #{filename.to_s.inspect}." +
247
+ (skipped.zero? ? '' : " (#{skipped} duplicate(s) skipped)."),
236
248
  type: :success
237
249
  )
238
250
  end
@@ -374,7 +386,7 @@ module OllamaChat::RAGHandling
374
386
  source_tags = Hash.new { |h, k| h[k] = Set.new }
375
387
  @documents.records.each do |record|
376
388
  source = record.source.full? or next
377
- sources.add(source)
389
+ sources << source
378
390
  source_tags[source].merge(record.tags)
379
391
  end
380
392
  display_map = {}
@@ -599,12 +611,12 @@ module OllamaChat::RAGHandling
599
611
  end
600
612
 
601
613
  sources = {}
602
- seen = {}
614
+ seen = Set.new
603
615
  @documents.each_record do |record|
604
616
  source = @documents.normalize_source(record.source) or next
605
617
  if matched_sources.nil? || matched_sources.member?(source)
606
- seen.key?(source) and next
607
- seen[source] = true
618
+ seen.member?(source) and next
619
+ seen << source
608
620
  unless @documents.source_modified?(source)
609
621
  infobar.puts "Source #{source.to_s.inspect} is unmodified. => Skipping."
610
622
  next
@@ -615,8 +627,8 @@ module OllamaChat::RAGHandling
615
627
  end
616
628
 
617
629
  if patterns = col.patterns.full?
618
- new_sources = all_file_set(patterns).map(&:to_s).reject { seen.key?(_1) }.to_set
619
- new_sources.each { seen[_1] = true }
630
+ new_sources = all_file_set(patterns).map(&:to_s).reject { seen.member?(_1) }.to_set
631
+ new_sources.each { seen << _1 }
620
632
  new_sources.each { sources[_1] = [] }
621
633
  end
622
634
 
@@ -60,10 +60,10 @@ class OllamaChat::Tools::Browse
60
60
  result = browse_url(url)
61
61
 
62
62
  message = if result.success?
63
- "Opened #{url.to_s.inspect} in browser."
64
- else
65
- "Could not open #{url.to_s.inspect} in browser."
66
- end
63
+ "Opened #{redact_password(url).inspect} in browser."
64
+ else
65
+ "Could not open #{redact_password(url).inspect} in browser."
66
+ end
67
67
 
68
68
  {
69
69
  success: result.success?,
@@ -7,6 +7,7 @@
7
7
  module OllamaChat::Tools::Concern
8
8
  extend Tins::Concern
9
9
  include OllamaChat::Utils::ValueFormatter
10
+ include OllamaChat::Utils::Redact
10
11
  include OllamaChat::Utils::Backup
11
12
  include OllamaChat::Feedback
12
13
 
@@ -21,9 +21,9 @@ class OllamaChat::Tools::ExecuteGrep
21
21
  function: Tool::Function.new(
22
22
  name:,
23
23
  description: <<~EOT,
24
- Pattern searcher – Runs a regex against all files at path, optionally
25
- case‑insensitive, returning matches (up to max_results). Useful for
26
- quick codebase queries or finding config values.
24
+ Pattern searcher – Runs a regex against all files' contents at path,
25
+ optionally case‑insensitive, returning matches (up to max_results).
26
+ Useful for quick codebase queries or finding config values.
27
27
  EOT
28
28
  parameters: Tool::Function::Parameters.new(
29
29
  type: 'object',
@@ -92,10 +92,10 @@ class OllamaChat::Tools::GenerateImage
92
92
  filename:, subfolder: '', type: 'output', rand:
93
93
  )
94
94
 
95
- chat.links.add(view_url.to_s)
95
+ chat.links << view_url.to_s
96
96
 
97
97
  message = "Image successfully generated! The user can view it here,"\
98
- " give this URL to the user: #{view_url}"
98
+ " give this URL to the user: #{redact_password(view_url)}"
99
99
  {
100
100
  status: 'success',
101
101
  message: ,
@@ -44,13 +44,13 @@ module OllamaChat::Utils::AnalyzeDirectory
44
44
  # directories are included in the tree. Defaults to `false`, which
45
45
  # skips any entry whose base name starts with a dot.
46
46
  #
47
- # @return [Array<Hash>] An array of entry hashes. Each hash contains:
48
- # * `:type` – "file" or "directory"
49
- # * `:name` – Base name of the file/directory
50
- # * `:path` – Absolute path
51
- # * `:depth` – Depth relative to the root (root = 0)
52
- # * `:height` – The maximum depth found in the entire tree
53
- # * `:children` – Array of child entry hashes (only for directories)
47
+ # @return [Hash] A hash with two keys:
48
+ # * `:height` – The maximum depth found in the entire tree.
49
+ # * `:entries` – Array of entry hashes. Each hash contains:
50
+ # * `:path` – Absolute path (directories end with `/`)
51
+ # * `:depth` – Depth relative to the root (root = 0)
52
+ # * `:children` – Array of child entry hashes (directories only,
53
+ # omitted when empty)
54
54
  #
55
55
  # @raise [StandardError] Any exception raised during traversal is
56
56
  # rescued and returned as a hash with `:error` and `:message`
@@ -72,15 +72,16 @@ module OllamaChat::Utils::AnalyzeDirectory
72
72
  height = e[:depth] if e[:depth] > height
73
73
  end
74
74
 
75
- structure_each_entry(entries) { |e| e[:height] = height }
76
-
77
75
  if max_depth && max_depth <= height
78
76
  structure_each_entry(entries) do |e|
79
- e[:children]&.reject! { |c| c[:depth] >= max_depth }
77
+ if children = e[:children].full?
78
+ children.reject! { |c| c[:depth] >= max_depth }
79
+ e.delete(:children) if children.empty?
80
+ end
80
81
  end
81
82
  end
82
83
 
83
- entries
84
+ { height:, entries: }
84
85
  rescue => e
85
86
  { error: e.class, message: e.message }
86
87
  end
@@ -116,19 +117,18 @@ module OllamaChat::Utils::AnalyzeDirectory
116
117
  next if exclude.any? { |e| child.basename.fnmatch?(e.to_s, File::FNM_PATHNAME) }
117
118
 
118
119
  if child.directory?
120
+ children = recurse_generate_structure(
121
+ child, exclude:, suffix:, depth: depth + 1, include_hidden:
122
+ ).full?
119
123
  entries << {
120
- type: 'directory',
121
- name: child.basename.to_s,
122
- path: child.expand_path.to_s,
123
- children: recurse_generate_structure(child, exclude:, suffix:, depth: depth + 1, include_hidden:),
124
- depth:
125
- }
124
+ path: child.expand_path.to_s << ?/,
125
+ depth: ,
126
+ children: ,
127
+ }.compact
126
128
  elsif child.file?
127
129
  # Skip unless suffix matches
128
130
  next if extname.present? && child.extname != extname
129
131
  entries << {
130
- type: 'file',
131
- name: child.basename.to_s,
132
132
  path: child.expand_path.to_s,
133
133
  depth:
134
134
  }
@@ -19,6 +19,7 @@ require 'ollama_chat/utils/cache_fetcher'
19
19
  # # Process the fetched content
20
20
  # end
21
21
  class OllamaChat::Utils::Fetcher
22
+ include OllamaChat::Utils::Redact
22
23
  # A module that extends IO objects with content type metadata and expiration
23
24
  # tracking.
24
25
  #
@@ -154,7 +155,7 @@ class OllamaChat::Utils::Fetcher
154
155
  def self.get(url, headers: {}, **options, &block)
155
156
  cache = options.delete(:cache) and
156
157
  cache = OllamaChat::Utils::CacheFetcher.new(cache)
157
- cache and infobar.puts "Getting #{url.to_s.inspect} via cache…"
158
+ cache and infobar.puts "Getting #{OllamaChat::Utils::Redact.redact_password(url).inspect} via cache…"
158
159
  if result = cache&.get(url, &block)
159
160
  content_type = result&.content_type || 'unknown'
160
161
  infobar.puts "…hit, found #{content_type} content in cache."
@@ -0,0 +1,32 @@
1
+ require 'uri'
2
+
3
+ # Redacts credentials from URLs for safe, user-facing display.
4
+ #
5
+ # Whenever a URL that may carry a password (e.g.
6
+ # `http://user:secret@host`) is about to be printed to the terminal or
7
+ # echoed back to the model, run it through {#redact_password} so the
8
+ # secret is masked as `***`.
9
+ #
10
+ # @example
11
+ # OllamaChat::Utils::Redact.redact_password('http://u:secret@example.com')
12
+ # # => "http://u:***@example.com"
13
+ #
14
+ # The module can also be +include+d to gain {#redact_password} as a
15
+ # private helper on the host class.
16
+ module OllamaChat::Utils::Redact
17
+ module_function
18
+
19
+ # Returns the URL as a string with its password component replaced by
20
+ # `***`. Accepts a +URI+ or a plain +String+ (parsed on the fly). The
21
+ # original object is never mutated: a duplicate is redacted and the
22
+ # result returned as a string. URLs without a password are returned
23
+ # unchanged.
24
+ #
25
+ # @param url [URI, String] the URL whose password should be hidden
26
+ # @return [String] the URL with its password redacted
27
+ def redact_password(url)
28
+ uri = url.is_a?(String) ? URI.parse(url) : url.dup
29
+ uri.password = '***' if uri.password
30
+ uri.to_s
31
+ end
32
+ end
@@ -9,6 +9,7 @@
9
9
  module OllamaChat::Utils
10
10
  end
11
11
 
12
+ require 'ollama_chat/utils/redact'
12
13
  require 'ollama_chat/utils/analyze_directory'
13
14
  require 'ollama_chat/utils/audio_player'
14
15
  require 'ollama_chat/utils/backup'
@@ -5,7 +5,7 @@
5
5
  # by hand; it is rewritten on every `rake version` invocation.
6
6
  module OllamaChat
7
7
  # The current version of the OllamaChat gem as a String.
8
- VERSION = '0.0.137'
8
+ VERSION = '0.0.138'
9
9
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
10
10
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
11
11
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -31,7 +31,7 @@ module OllamaChat::WebSearching
31
31
  log(:info, "Web search performed", data: {
32
32
  search_engine: engine, query:, results: results.size
33
33
  })
34
- results.each { |url| links.add(url) }
34
+ results.each { |url| links << url }
35
35
  end
36
36
  else
37
37
  feedback("Search engine #{bold{engine}} not implemented!", type: :warn)
data/ollama_chat.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama_chat 0.0.137 ruby lib
2
+ # stub: ollama_chat 0.0.138 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama_chat".freeze
6
- s.version = "0.0.137".freeze
6
+ s.version = "0.0.138".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.description = "The app provides a command-line interface (CLI) to an Ollama AI model,\nallowing users to engage in text-based conversations and generate\nhuman-like responses. Users can import data from local files or web pages,\nwhich are then processed through three different modes: fully importing the\ncontent into the conversation context, summarizing the information for\nconcise reference, or storing it in an embedding vector database for later\nretrieval based on the conversation.\n".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["ollama_chat".freeze, "ollama_chat_send".freeze, "ollama_chat_log".freeze]
15
- s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/asr.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/collection_search.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/compaction.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/context_usage.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/migrations/008_drop_think_mode_constraint.rb".freeze, "lib/ollama_chat/database/migrations/009_add_app_states_table.rb".freeze, "lib/ollama_chat/database/migrations/010_add_enabled_to_collections.rb".freeze, "lib/ollama_chat/database/migrations/011_add_trigger_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/012_add_context_manifest_enabled_to_sessions.rb".freeze, "lib/ollama_chat/database/models/app_state.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/row_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/feedback.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/invidious.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/model_handling/model_cache.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/speaker.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_call_processor.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_jira_twg.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/execute_shell.rb".freeze, "lib/ollama_chat/tools/forget.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/list_directory.rb".freeze, "lib/ollama_chat/tools/lookup_gem_path.rb".freeze, "lib/ollama_chat/tools/lookup_group.rb".freeze, "lib/ollama_chat/tools/memorize.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/tts.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/audio_player.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/excon_logger.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_rotation.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/ordered_queue.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/strip_ansi.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
16
- s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_log".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "config/sherlock.md".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/asr.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/collection_search.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/compaction.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/context_usage.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/migrations/008_drop_think_mode_constraint.rb".freeze, "lib/ollama_chat/database/migrations/009_add_app_states_table.rb".freeze, "lib/ollama_chat/database/migrations/010_add_enabled_to_collections.rb".freeze, "lib/ollama_chat/database/migrations/011_add_trigger_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/012_add_context_manifest_enabled_to_sessions.rb".freeze, "lib/ollama_chat/database/models/app_state.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/row_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/feedback.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/invidious.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/model_handling/model_cache.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/ollama_chat_config/fastfetch-profile.jsonc".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/speaker.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_call_processor.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_jira_twg.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/execute_shell.rb".freeze, "lib/ollama_chat/tools/forget.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/list_directory.rb".freeze, "lib/ollama_chat/tools/lookup_gem_path.rb".freeze, "lib/ollama_chat/tools/lookup_group.rb".freeze, "lib/ollama_chat/tools/memorize.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/tts.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/audio_player.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/excon_logger.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_rotation.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/ordered_queue.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/strip_ansi.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_ps.json".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/conversation.jsonl".freeze, "spec/assets/deep/deeper/empty.txt".freeze, "spec/assets/deep/deeper/not-empty.txt".freeze, "spec/assets/deep/empty.txt".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.epub".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/example_with_quote.html".freeze, "spec/assets/fluffy.png".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/linux.oga".freeze, "spec/assets/miyu.png".freeze, "spec/assets/pirateweather.json".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/asr_spec.rb".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/collection_search_spec.rb".freeze, "spec/ollama_chat/command_concern_spec.rb".freeze, "spec/ollama_chat/commands_spec.rb".freeze, "spec/ollama_chat/compaction_spec.rb".freeze, "spec/ollama_chat/config_handling_spec.rb".freeze, "spec/ollama_chat/context_usage_spec.rb".freeze, "spec/ollama_chat/conversation_spec.rb".freeze, "spec/ollama_chat/database/models/favourite_spec.rb".freeze, "spec/ollama_chat/favourites_management_spec.rb".freeze, "spec/ollama_chat/file_editing_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/history_spec.rb".freeze, "spec/ollama_chat/http_handling_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/input_content_spec.rb".freeze, "spec/ollama_chat/invidious_spec.rb".freeze, "spec/ollama_chat/kramdown_ansi_spec.rb".freeze, "spec/ollama_chat/message_editing_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/message_spec.rb".freeze, "spec/ollama_chat/model_handling/model_cache_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/personae_management_spec.rb".freeze, "spec/ollama_chat/prompt_handling_spec.rb".freeze, "spec/ollama_chat/prompt_management_spec.rb".freeze, "spec/ollama_chat/rag_handling_spec.rb".freeze, "spec/ollama_chat/redis_cache_spec.rb".freeze, "spec/ollama_chat/server_socket_spec.rb".freeze, "spec/ollama_chat/session_management_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/speaker_spec.rb".freeze, "spec/ollama_chat/state_selectors_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/system_prompt_management_spec.rb".freeze, "spec/ollama_chat/think_control_spec.rb".freeze, "spec/ollama_chat/token_estimator_spec.rb".freeze, "spec/ollama_chat/tool_call_processor_spec.rb".freeze, "spec/ollama_chat/tool_calling_spec.rb".freeze, "spec/ollama_chat/tools/browse_spec.rb".freeze, "spec/ollama_chat/tools/compute_bmi_spec.rb".freeze, "spec/ollama_chat/tools/concern_spec.rb".freeze, "spec/ollama_chat/tools/copy_to_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/delete_file_spec.rb".freeze, "spec/ollama_chat/tools/execute_grep_spec.rb".freeze, "spec/ollama_chat/tools/execute_jira_twg_spec.rb".freeze, "spec/ollama_chat/tools/execute_ri_spec.rb".freeze, "spec/ollama_chat/tools/execute_shell_spec.rb".freeze, "spec/ollama_chat/tools/forget_spec.rb".freeze, "spec/ollama_chat/tools/generate_image_spec.rb".freeze, "spec/ollama_chat/tools/generate_password_spec.rb".freeze, "spec/ollama_chat/tools/get_current_weather_spec.rb".freeze, "spec/ollama_chat/tools/get_cve_spec.rb".freeze, "spec/ollama_chat/tools/get_endoflife_spec.rb".freeze, "spec/ollama_chat/tools/get_ghr_spec.rb".freeze, "spec/ollama_chat/tools/get_jira_issue_spec.rb".freeze, "spec/ollama_chat/tools/get_location_spec.rb".freeze, "spec/ollama_chat/tools/get_rfc_spec.rb".freeze, "spec/ollama_chat/tools/get_time_spec.rb".freeze, "spec/ollama_chat/tools/get_url_spec.rb".freeze, "spec/ollama_chat/tools/list_directory_spec.rb".freeze, "spec/ollama_chat/tools/lookup_gem_path_spec.rb".freeze, "spec/ollama_chat/tools/lookup_group_spec.rb".freeze, "spec/ollama_chat/tools/memorize_spec.rb".freeze, "spec/ollama_chat/tools/move_file_spec.rb".freeze, "spec/ollama_chat/tools/open_file_in_editor_spec.rb".freeze, "spec/ollama_chat/tools/paste_from_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/paste_into_editor_spec.rb".freeze, "spec/ollama_chat/tools/patch_file_spec.rb".freeze, "spec/ollama_chat/tools/read_file_spec.rb".freeze, "spec/ollama_chat/tools/resolve_tag_spec.rb".freeze, "spec/ollama_chat/tools/roll_dice_spec.rb".freeze, "spec/ollama_chat/tools/run_tests_spec.rb".freeze, "spec/ollama_chat/tools/search_knowledge_spec.rb".freeze, "spec/ollama_chat/tools/search_web_spec.rb".freeze, "spec/ollama_chat/tools/write_file_spec.rb".freeze, "spec/ollama_chat/tts_spec.rb".freeze, "spec/ollama_chat/utils/analyze_directory_spec.rb".freeze, "spec/ollama_chat/utils/audio_player_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/excon_logger_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/log_rotation_spec.rb".freeze, "spec/ollama_chat/utils/log_viewer_spec.rb".freeze, "spec/ollama_chat/utils/ordered_queue_spec.rb".freeze, "spec/ollama_chat/utils/path_completer_spec.rb".freeze, "spec/ollama_chat/utils/png_metadata_extractor_spec.rb".freeze, "spec/ollama_chat/vim_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
15
+ s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/asr.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/collection_search.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/compaction.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/context_usage.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/migrations/008_drop_think_mode_constraint.rb".freeze, "lib/ollama_chat/database/migrations/009_add_app_states_table.rb".freeze, "lib/ollama_chat/database/migrations/010_add_enabled_to_collections.rb".freeze, "lib/ollama_chat/database/migrations/011_add_trigger_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/012_add_context_manifest_enabled_to_sessions.rb".freeze, "lib/ollama_chat/database/models/app_state.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/row_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/feedback.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/invidious.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/model_handling/model_cache.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/speaker.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_call_processor.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_jira_twg.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/execute_shell.rb".freeze, "lib/ollama_chat/tools/forget.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/list_directory.rb".freeze, "lib/ollama_chat/tools/lookup_gem_path.rb".freeze, "lib/ollama_chat/tools/lookup_group.rb".freeze, "lib/ollama_chat/tools/memorize.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/tts.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/audio_player.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/excon_logger.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_rotation.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/ordered_queue.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/redact.rb".freeze, "lib/ollama_chat/utils/strip_ansi.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
16
+ s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_log".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "config/sherlock.md".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/asr.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/collection_search.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/compaction.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/context_usage.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/migrations/008_drop_think_mode_constraint.rb".freeze, "lib/ollama_chat/database/migrations/009_add_app_states_table.rb".freeze, "lib/ollama_chat/database/migrations/010_add_enabled_to_collections.rb".freeze, "lib/ollama_chat/database/migrations/011_add_trigger_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/012_add_context_manifest_enabled_to_sessions.rb".freeze, "lib/ollama_chat/database/models/app_state.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/row_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/feedback.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/invidious.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/model_handling/model_cache.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/ollama_chat_config/fastfetch-profile.jsonc".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/speaker.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_call_processor.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_jira_twg.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/execute_shell.rb".freeze, "lib/ollama_chat/tools/forget.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/list_directory.rb".freeze, "lib/ollama_chat/tools/lookup_gem_path.rb".freeze, "lib/ollama_chat/tools/lookup_group.rb".freeze, "lib/ollama_chat/tools/memorize.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/tts.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/audio_player.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/excon_logger.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_rotation.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/ordered_queue.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/redact.rb".freeze, "lib/ollama_chat/utils/strip_ansi.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_ps.json".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/conversation.jsonl".freeze, "spec/assets/deep/deeper/empty.txt".freeze, "spec/assets/deep/deeper/not-empty.txt".freeze, "spec/assets/deep/empty.txt".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.epub".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/example_with_quote.html".freeze, "spec/assets/fluffy.png".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/linux.oga".freeze, "spec/assets/miyu.png".freeze, "spec/assets/pirateweather.json".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/asr_spec.rb".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/collection_search_spec.rb".freeze, "spec/ollama_chat/command_concern_spec.rb".freeze, "spec/ollama_chat/commands_spec.rb".freeze, "spec/ollama_chat/compaction_spec.rb".freeze, "spec/ollama_chat/config_handling_spec.rb".freeze, "spec/ollama_chat/context_usage_spec.rb".freeze, "spec/ollama_chat/conversation_spec.rb".freeze, "spec/ollama_chat/database/models/favourite_spec.rb".freeze, "spec/ollama_chat/favourites_management_spec.rb".freeze, "spec/ollama_chat/file_editing_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/history_spec.rb".freeze, "spec/ollama_chat/http_handling_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/input_content_spec.rb".freeze, "spec/ollama_chat/invidious_spec.rb".freeze, "spec/ollama_chat/kramdown_ansi_spec.rb".freeze, "spec/ollama_chat/message_editing_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/message_spec.rb".freeze, "spec/ollama_chat/model_handling/model_cache_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/personae_management_spec.rb".freeze, "spec/ollama_chat/prompt_handling_spec.rb".freeze, "spec/ollama_chat/prompt_management_spec.rb".freeze, "spec/ollama_chat/rag_handling_spec.rb".freeze, "spec/ollama_chat/redis_cache_spec.rb".freeze, "spec/ollama_chat/server_socket_spec.rb".freeze, "spec/ollama_chat/session_management_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/speaker_spec.rb".freeze, "spec/ollama_chat/state_selectors_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/system_prompt_management_spec.rb".freeze, "spec/ollama_chat/think_control_spec.rb".freeze, "spec/ollama_chat/token_estimator_spec.rb".freeze, "spec/ollama_chat/tool_call_processor_spec.rb".freeze, "spec/ollama_chat/tool_calling_spec.rb".freeze, "spec/ollama_chat/tools/browse_spec.rb".freeze, "spec/ollama_chat/tools/compute_bmi_spec.rb".freeze, "spec/ollama_chat/tools/concern_spec.rb".freeze, "spec/ollama_chat/tools/copy_to_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/delete_file_spec.rb".freeze, "spec/ollama_chat/tools/execute_grep_spec.rb".freeze, "spec/ollama_chat/tools/execute_jira_twg_spec.rb".freeze, "spec/ollama_chat/tools/execute_ri_spec.rb".freeze, "spec/ollama_chat/tools/execute_shell_spec.rb".freeze, "spec/ollama_chat/tools/forget_spec.rb".freeze, "spec/ollama_chat/tools/generate_image_spec.rb".freeze, "spec/ollama_chat/tools/generate_password_spec.rb".freeze, "spec/ollama_chat/tools/get_current_weather_spec.rb".freeze, "spec/ollama_chat/tools/get_cve_spec.rb".freeze, "spec/ollama_chat/tools/get_endoflife_spec.rb".freeze, "spec/ollama_chat/tools/get_ghr_spec.rb".freeze, "spec/ollama_chat/tools/get_jira_issue_spec.rb".freeze, "spec/ollama_chat/tools/get_location_spec.rb".freeze, "spec/ollama_chat/tools/get_rfc_spec.rb".freeze, "spec/ollama_chat/tools/get_time_spec.rb".freeze, "spec/ollama_chat/tools/get_url_spec.rb".freeze, "spec/ollama_chat/tools/list_directory_spec.rb".freeze, "spec/ollama_chat/tools/lookup_gem_path_spec.rb".freeze, "spec/ollama_chat/tools/lookup_group_spec.rb".freeze, "spec/ollama_chat/tools/memorize_spec.rb".freeze, "spec/ollama_chat/tools/move_file_spec.rb".freeze, "spec/ollama_chat/tools/open_file_in_editor_spec.rb".freeze, "spec/ollama_chat/tools/paste_from_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/paste_into_editor_spec.rb".freeze, "spec/ollama_chat/tools/patch_file_spec.rb".freeze, "spec/ollama_chat/tools/read_file_spec.rb".freeze, "spec/ollama_chat/tools/resolve_tag_spec.rb".freeze, "spec/ollama_chat/tools/roll_dice_spec.rb".freeze, "spec/ollama_chat/tools/run_tests_spec.rb".freeze, "spec/ollama_chat/tools/search_knowledge_spec.rb".freeze, "spec/ollama_chat/tools/search_web_spec.rb".freeze, "spec/ollama_chat/tools/write_file_spec.rb".freeze, "spec/ollama_chat/tts_spec.rb".freeze, "spec/ollama_chat/utils/analyze_directory_spec.rb".freeze, "spec/ollama_chat/utils/audio_player_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/excon_logger_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/log_rotation_spec.rb".freeze, "spec/ollama_chat/utils/log_viewer_spec.rb".freeze, "spec/ollama_chat/utils/ordered_queue_spec.rb".freeze, "spec/ollama_chat/utils/path_completer_spec.rb".freeze, "spec/ollama_chat/utils/png_metadata_extractor_spec.rb".freeze, "spec/ollama_chat/vim_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
17
17
  s.homepage = "https://github.com/flori/ollama_chat".freeze
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "OllamaChat - A command-line interface (CLI) for interacting with an Ollama AI model.".freeze, "--main".freeze, "README.md".freeze]
@@ -103,4 +103,27 @@ describe OllamaChat::Information do
103
103
  expect(chat.infobar_message).to be_a(Hash)
104
104
  end
105
105
  end
106
+
107
+ describe '#redact_password' do
108
+ it 'redacts the password from a URI with credentials' do
109
+ uri = URI.parse('http://flori:s3cret@host:11434')
110
+ expect(chat.redact_password(uri)).to eq('http://flori:***@host:11434')
111
+ end
112
+
113
+ it 'leaves the original URI untouched' do
114
+ uri = URI.parse('http://flori:s3cret@host:11434')
115
+ chat.redact_password(uri)
116
+ expect(uri.password).to eq('s3cret')
117
+ end
118
+
119
+ it 'parses a String argument' do
120
+ expect(chat.redact_password('http://flori:s3cret@host:11434')).
121
+ to eq('http://flori:***@host:11434')
122
+ end
123
+
124
+ it 'returns URLs without a password unchanged' do
125
+ expect(chat.redact_password(URI.parse('http://host:11434'))).
126
+ to eq('http://host:11434')
127
+ end
128
+ end
106
129
  end
@@ -345,8 +345,8 @@ describe OllamaChat::Parsing do
345
345
  it 'generates a readable directory‑structure string for directories' do
346
346
  content, = chat.parse_content("look at #{asset}", [])
347
347
  json_data = content.lines[2..-1].join('')
348
- json = JSON(json_data)
349
- expect(json.map { _1['name'] }.sort).to eq(
348
+ json = json_object(json_data)
349
+ expect(json.entries.map { |e| File.basename(e.path) }.sort).to eq(
350
350
  [
351
351
  "api_show.json", "api_tags.json", "api_version.json", "api_ps.json",
352
352
  "conversation.json", "conversation.jsonl", "deep", "duckduckgo.html",
@@ -365,8 +365,9 @@ describe OllamaChat::Parsing do
365
365
  (hidden_dir + 'visible.txt').write('v')
366
366
  content, = chat.parse_content("look at ./#{hidden_dir}", [])
367
367
  json_data = content.lines[2..-1].join('')
368
- json = JSON(json_data)
369
- expect(json.map { _1['name'] }).to contain_exactly('.secret', 'visible.txt')
368
+ json = json_object(json_data)
369
+ expect(json.entries.map { |e| File.basename(e.path) })
370
+ .to contain_exactly('.secret', 'visible.txt')
370
371
  ensure
371
372
  FileUtils.remove_entry(hidden_dir) if hidden_dir && File.directory?(hidden_dir)
372
373
  end
@@ -822,7 +822,7 @@ describe OllamaChat::RAGHandling do
822
822
  expect(chat).to receive(:create_memory_collection).with('memory-b')
823
823
  expect(chat).to receive(:switch_collection).with('memory-a').and_yield
824
824
  expect(chat).to receive(:switch_collection).with('memory-b').and_yield
825
-
825
+ expect(docs).to receive(:each_record).at_least(:twice)
826
826
  expect(docs).to receive(:add)
827
827
  .with(['hello'], tags: [ '2026-01-01T00:00:00+02:00' ],
828
828
  batch_size: 1, source: nil)
@@ -858,8 +858,7 @@ describe OllamaChat::RAGHandling do
858
858
  expect(chat).to receive(:create_memory_collection).with('memory-a')
859
859
  expect(chat).not_to receive(:create_memory_collection).with('memory-b')
860
860
  expect(chat).to receive(:switch_collection).with('memory-a').and_yield
861
- expect(chat).not_to receive(:switch_collection).with('memory-b')
862
-
861
+ expect(docs).to receive(:each_record)
863
862
  expect(docs).to receive(:add)
864
863
  .with(['hello'], tags: [ '2026-01-01T00:00:00+02:00' ],
865
864
  batch_size: 1, source: nil)
@@ -875,6 +874,66 @@ describe OllamaChat::RAGHandling do
875
874
  chat.memory_restore(target.to_s)
876
875
  end
877
876
 
877
+ context 'with existing records (dedup)' do
878
+ it 'skips entries whose tags already exist, adds the rest' do
879
+ tag = double('Tag')
880
+ allow(tag).to receive(:to_s).with(link: false).
881
+ and_return('2026-01-01T00:00:00+02:00')
882
+ rec = double('Record', tags: [ tag ])
883
+
884
+ expect(chat).to receive(:choose_with_state).and_yield
885
+ expect(chat).to receive(:choose_entry)
886
+ .and_return('memory-a', '[DONE]')
887
+ expect(chat).to receive(:create_memory_collection).with('memory-a')
888
+ expect(chat).to receive(:switch_collection).with('memory-a').and_yield
889
+ expect(docs).to receive(:each_record).and_yield(rec)
890
+
891
+ # 'hello' (tag 2026-01-01) is a duplicate -> skipped
892
+ # 'world' (tag 2026-01-02) is new -> added
893
+ expect(docs).not_to receive(:add)
894
+ .with(['hello'], tags: [ '2026-01-01T00:00:00+02:00' ],
895
+ batch_size: 1, source: nil)
896
+ expect(docs).to receive(:add)
897
+ .with(['world'], tags: [ '2026-01-02T00:00:00+02:00' ],
898
+ batch_size: 1, source: nil)
899
+
900
+ allow(chat).to receive(:feedback)
901
+ expect(chat).to receive(:log)
902
+ expect(chat).to receive(:feedback)
903
+ .with(/Restored 1 record.*1 duplicate\(s\) skipped/,
904
+ type: :success)
905
+
906
+ chat.memory_restore(target.to_s)
907
+ end
908
+
909
+ it 'skips all entries when every tag is a duplicate' do
910
+ tag1 = double('Tag1')
911
+ allow(tag1).to receive(:to_s).with(link: false).
912
+ and_return('2026-01-01T00:00:00+02:00')
913
+ tag2 = double('Tag2')
914
+ allow(tag2).to receive(:to_s).with(link: false).
915
+ and_return('2026-01-02T00:00:00+02:00')
916
+ rec = double('Record', tags: [ tag1, tag2 ])
917
+
918
+ expect(chat).to receive(:choose_with_state).and_yield
919
+ expect(chat).to receive(:choose_entry)
920
+ .and_return('memory-a', '[DONE]')
921
+ expect(chat).to receive(:create_memory_collection).with('memory-a')
922
+ expect(chat).to receive(:switch_collection).with('memory-a').and_yield
923
+ expect(docs).to receive(:each_record).and_yield(rec)
924
+
925
+ expect(docs).not_to receive(:add)
926
+
927
+ allow(chat).to receive(:feedback)
928
+ expect(chat).to receive(:log)
929
+ expect(chat).to receive(:feedback)
930
+ .with(/Restored 0 record.*2 duplicate\(s\) skipped/,
931
+ type: :success)
932
+
933
+ chat.memory_restore(target.to_s)
934
+ end
935
+ end
936
+
878
937
  it 'warns when the file does not exist' do
879
938
  expect(chat).to receive(:feedback)
880
939
  .with(a_string_including('not found'), type: :warn)
@@ -32,7 +32,10 @@ describe OllamaChat::Tools::ListDirectory do
32
32
  # Should return valid JSON
33
33
  expect(result).to be_a(String)
34
34
  json = json_object(result)
35
- expect(json.size).to eq 25
35
+ expect(json.height).to be_an(Integer)
36
+ expect(json.entries.size).to eq 25
37
+ expect(json.entries.first.path).to be_a(String)
38
+ expect(json.entries.first.name).to be_nil
36
39
  expect(described_class.summary_template(result:)).to eq \
37
40
  'was called.'
38
41
  end
@@ -56,7 +59,8 @@ describe OllamaChat::Tools::ListDirectory do
56
59
  # Should return valid JSON
57
60
  expect(result).to be_a(String)
58
61
  json = json_object(result)
59
- expect(json.size).to be_an Integer
62
+ expect(json.height).to be_an(Integer)
63
+ expect(json.entries.size).to be_an(Integer)
60
64
  end
61
65
 
62
66
  it 'includes hidden files when include_hidden is true' do
@@ -80,7 +84,10 @@ describe OllamaChat::Tools::ListDirectory do
80
84
 
81
85
  result = described_class.new(chat).execute(tool_call)
82
86
  json = json_object(result)
83
- expect(json.map { _1['name'] }).to contain_exactly('.secret', 'visible.txt')
87
+ paths = json.entries.map { |e| e.path }
88
+ expect(paths).to all(include(hidden_dir))
89
+ names = json.entries.map { |e| e.path.split('/').last }
90
+ expect(names).to contain_exactly('.secret', 'visible.txt')
84
91
  ensure
85
92
  FileUtils.remove_entry(hidden_dir) if hidden_dir && File.directory?(hidden_dir)
86
93
  end
@@ -21,32 +21,40 @@ describe OllamaChat::Utils::AnalyzeDirectory do
21
21
 
22
22
  after { FileUtils.remove_entry(@tmp_dir) }
23
23
 
24
- it 'returns an array of hashes describing files and directories' do
24
+ it 'returns a hash with height and entries describing files and directories' do
25
25
  result = generate.call(@tmp_dir)
26
26
 
27
- expect(result).to be_an(Array)
28
- expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'b.rb', 'sub')
27
+ expect(result).to be_a(Hash)
28
+ expect(result[:height]).to eq 1
29
+ entries = result[:entries]
30
+ expect(entries).to be_an(Array)
31
+ expect(entries.map { |e| File.basename(e[:path]) })
32
+ .to contain_exactly('a.txt', 'b.rb', 'sub')
29
33
 
30
- sub = result.find { |e| e[:name] == 'sub' }
34
+ sub = entries.find { |e| e[:path] == "#{@sub_dir}/" }
31
35
  expect(sub[:depth]).to eq 0
32
- expect(sub[:type]).to eq('directory')
36
+ expect(sub[:path]).to end_with('/')
33
37
  expect(sub[:children]).to be_an(Array)
34
- expect(sub[:children].map { |e| e[:name] }).to contain_exactly('c.md')
38
+ expect(sub[:children].map { |e| File.basename(e[:path]) })
39
+ .to contain_exactly('c.md')
35
40
  expect(sub[:children].map { |e| e[:depth] }).to eq [ 1 ]
36
41
  end
37
42
 
38
43
  it 'max_depth 1 prunes all children from directories' do
39
44
  result = generate.call(@tmp_dir, max_depth: 1)
45
+ entries = result[:entries]
40
46
 
41
- expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'b.rb', 'sub')
42
- sub = result.find { |e| e[:name] == 'sub' }
43
- expect(sub[:children]).to be_empty
47
+ expect(entries.map { |e| File.basename(e[:path]) })
48
+ .to contain_exactly('a.txt', 'b.rb', 'sub')
49
+ sub = entries.find { |e| e[:path] == "#{@sub_dir}/" }
50
+ expect(sub[:children]).to be_nil
44
51
  end
45
52
 
46
53
  it 'filters by suffix' do
47
54
  result = generate.call(asset, suffix: 'rb')
55
+ entries = result[:entries]
48
56
 
49
- names = result.map { |e| e[:name] }
57
+ names = entries.map { |e| File.basename(e[:path]) }
50
58
  expect(names).to include('example.rb')
51
59
  expect(names).not_to include('examplle.json', 'example.md')
52
60
  end
@@ -69,22 +77,26 @@ describe OllamaChat::Utils::AnalyzeDirectory do
69
77
 
70
78
  it 'max_depth 1 shows only immediate children' do
71
79
  result = generate.call(@tmp_dir, max_depth: 1)
80
+ entries = result[:entries]
72
81
 
73
- expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'sub')
74
- sub = result.find { |e| e[:name] == 'sub' }
75
- expect(sub[:children]).to be_empty
82
+ expect(entries.map { |e| File.basename(e[:path]) })
83
+ .to contain_exactly('a.txt', 'sub')
84
+ sub = entries.find { |e| e[:path] == "#{@sub_dir}/" }
85
+ expect(sub[:children]).to be_nil
76
86
  end
77
87
 
78
88
  it 'max_depth 2 shows children and grandchildren' do
79
89
  result = generate.call(@tmp_dir, max_depth: 2)
90
+ entries = result[:entries]
80
91
 
81
- expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'sub')
82
- sub = result.find { |e| e[:name] == 'sub' }
83
- deep = sub[:children].find { |e| e[:name] == 'deep' }
92
+ expect(entries.map { |e| File.basename(e[:path]) })
93
+ .to contain_exactly('a.txt', 'sub')
94
+ sub = entries.find { |e| e[:path] == "#{@sub_dir}/" }
95
+ deep = sub[:children].find { |e| e[:path] == "#{@deep_dir}/" }
84
96
 
85
- expect(sub[:children].map { |e| e[:name] })
97
+ expect(sub[:children].map { |e| File.basename(e[:path]) })
86
98
  .to contain_exactly('b.txt', 'deep')
87
- expect(deep[:children]).to be_empty
99
+ expect(deep[:children]).to be_nil
88
100
  end
89
101
 
90
102
  it 'max_depth exceeding height returns the full tree' do
@@ -111,7 +123,7 @@ describe OllamaChat::Utils::AnalyzeDirectory do
111
123
 
112
124
  it 'does not include hidden files or symlinks' do
113
125
  result = generate.call(@tmp_dir)
114
- names = result.map { |e| e[:name] }
126
+ names = result[:entries].map { |e| File.basename(e[:path]) }
115
127
 
116
128
  expect(names).not_to include('.hidden')
117
129
  expect(names).not_to include('link')
@@ -120,7 +132,7 @@ describe OllamaChat::Utils::AnalyzeDirectory do
120
132
 
121
133
  it 'includes hidden files when include_hidden is true' do
122
134
  result = generate.call(@tmp_dir, include_hidden: true)
123
- names = result.map { |e| e[:name] }
135
+ names = result[:entries].map { |e| File.basename(e[:path]) }
124
136
 
125
137
  expect(names).to include('.hidden', 'visible.txt')
126
138
  expect(names).not_to include('link')
@@ -140,7 +152,7 @@ describe OllamaChat::Utils::AnalyzeDirectory do
140
152
 
141
153
  it 'skips directories listed in the exclude list' do
142
154
  result = generate.call(@tmp_dir, exclude: %w[ exclude_me ])
143
- names = result.map { |e| e[:name] }
155
+ names = result[:entries].map { |e| File.basename(e[:path]) }
144
156
 
145
157
  expect(names).not_to include('exclude_me')
146
158
  end
@@ -22,7 +22,7 @@ describe OllamaChat::WebSearching do
22
22
  expect(chat).to receive(:search_web_with_duckduckgo)
23
23
  .with(/ruby/, 2).and_return(urls)
24
24
  expect(chat).to receive(:log).at_least(:once)
25
- expect(chat.links).to receive(:add).twice
25
+ expect(chat.links).to receive(:<<).twice
26
26
  expect(chat.search_web('ruby', 2)).to eq(urls)
27
27
  end
28
28
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama_chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.137
4
+ version: 0.0.138
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -611,6 +611,7 @@ extra_rdoc_files:
611
611
  - lib/ollama_chat/utils/path_completer.rb
612
612
  - lib/ollama_chat/utils/path_validator.rb
613
613
  - lib/ollama_chat/utils/png_metadata_extractor.rb
614
+ - lib/ollama_chat/utils/redact.rb
614
615
  - lib/ollama_chat/utils/strip_ansi.rb
615
616
  - lib/ollama_chat/utils/tag_resolver.rb
616
617
  - lib/ollama_chat/utils/utf8_converter.rb
@@ -766,6 +767,7 @@ files:
766
767
  - lib/ollama_chat/utils/path_completer.rb
767
768
  - lib/ollama_chat/utils/path_validator.rb
768
769
  - lib/ollama_chat/utils/png_metadata_extractor.rb
770
+ - lib/ollama_chat/utils/redact.rb
769
771
  - lib/ollama_chat/utils/strip_ansi.rb
770
772
  - lib/ollama_chat/utils/tag_resolver.rb
771
773
  - lib/ollama_chat/utils/utf8_converter.rb