openclacky 1.3.4 → 1.3.6
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 +4 -4
- data/CHANGELOG.md +39 -0
- data/lib/clacky/agent/fake_tool_call_detector.rb +52 -0
- data/lib/clacky/agent/message_compressor.rb +32 -8
- data/lib/clacky/agent/message_compressor_helper.rb +113 -12
- data/lib/clacky/agent/session_serializer.rb +3 -2
- data/lib/clacky/agent/tool_executor.rb +0 -12
- data/lib/clacky/agent.rb +74 -12
- data/lib/clacky/api_extension.rb +81 -0
- data/lib/clacky/api_extension_loader.rb +13 -1
- data/lib/clacky/cli.rb +0 -1
- data/lib/clacky/client.rb +14 -17
- data/lib/clacky/default_agents/_panels/time_machine/panel.js +22 -0
- data/lib/clacky/default_agents/base_prompt.md +1 -0
- data/lib/clacky/default_extensions/meeting/handler.rb +331 -0
- data/lib/clacky/default_extensions/meeting/meeting.js +790 -0
- data/lib/clacky/default_extensions/meeting/meta.yml +3 -0
- data/lib/clacky/default_extensions/meeting/skills/meeting-summarizer/SKILL.md +44 -0
- data/lib/clacky/default_skills/media-gen/SKILL.md +63 -0
- data/lib/clacky/default_skills/media-gen/scripts/video_seq.sh +114 -0
- data/lib/clacky/json_ui_controller.rb +1 -1
- data/lib/clacky/media/base.rb +60 -0
- data/lib/clacky/media/dashscope.rb +385 -21
- data/lib/clacky/media/gemini.rb +9 -0
- data/lib/clacky/media/generator.rb +52 -0
- data/lib/clacky/media/openai_compat.rb +166 -0
- data/lib/clacky/null_ui_controller.rb +13 -0
- data/lib/clacky/plain_ui_controller.rb +1 -1
- data/lib/clacky/providers.rb +50 -2
- data/lib/clacky/rich_ui/rich_ui_controller.rb +1 -1
- data/lib/clacky/server/channel/channel_ui_controller.rb +1 -1
- data/lib/clacky/server/http_server.rb +260 -122
- data/lib/clacky/server/session_registry.rb +54 -3
- data/lib/clacky/server/web_ui_controller.rb +3 -2
- data/lib/clacky/session_manager.rb +35 -4
- data/lib/clacky/skill_loader.rb +14 -2
- data/lib/clacky/tools/terminal/output_cleaner.rb +1 -3
- data/lib/clacky/tools/terminal.rb +0 -43
- data/lib/clacky/ui2/components/modal_component.rb +1 -1
- data/lib/clacky/ui2/layout_manager.rb +0 -5
- data/lib/clacky/ui2/progress_handle.rb +0 -3
- data/lib/clacky/ui2/ui_controller.rb +140 -40
- data/lib/clacky/ui_interface.rb +10 -1
- data/lib/clacky/utils/encoding.rb +25 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +199 -23
- data/lib/clacky/web/components/onboard.js +1 -14
- data/lib/clacky/web/components/sidebar.js +1 -3
- data/lib/clacky/web/features/backup/store.js +23 -0
- data/lib/clacky/web/features/backup/view.js +49 -22
- data/lib/clacky/web/features/brand/view.js +8 -5
- data/lib/clacky/web/features/channels/store.js +1 -20
- data/lib/clacky/web/features/mcp/store.js +1 -20
- data/lib/clacky/web/features/profile/store.js +1 -13
- data/lib/clacky/web/features/profile/view.js +16 -4
- data/lib/clacky/web/features/skills/store.js +6 -21
- data/lib/clacky/web/features/tasks/view.js +77 -28
- data/lib/clacky/web/features/version/store.js +2 -0
- data/lib/clacky/web/i18n.js +46 -3
- data/lib/clacky/web/index.html +67 -26
- data/lib/clacky/web/sessions.js +177 -87
- data/lib/clacky/web/settings.js +34 -2
- data/lib/clacky/web/ws-dispatcher.js +12 -4
- data/lib/clacky.rb +12 -5
- metadata +8 -1
|
@@ -44,10 +44,12 @@ module Clacky
|
|
|
44
44
|
error: nil,
|
|
45
45
|
error_code: nil,
|
|
46
46
|
top_up_url: nil,
|
|
47
|
+
raw_message: nil,
|
|
47
48
|
updated_at: nil,
|
|
48
49
|
agent: nil,
|
|
49
50
|
ui: nil,
|
|
50
51
|
thread: nil,
|
|
52
|
+
epoch: 0,
|
|
51
53
|
idle_timer: nil,
|
|
52
54
|
pending_task: nil,
|
|
53
55
|
pending_working_dir: nil
|
|
@@ -137,6 +139,40 @@ module Clacky
|
|
|
137
139
|
end
|
|
138
140
|
end
|
|
139
141
|
|
|
142
|
+
# Atomically bump the session's task epoch and return the new value.
|
|
143
|
+
# Each user message that starts a task claims a fresh epoch; a stale task
|
|
144
|
+
# thread (interrupted but not yet dead) compares its epoch against the
|
|
145
|
+
# current one and discards any side effects (status writes, broadcasts)
|
|
146
|
+
# once it has been superseded.
|
|
147
|
+
def claim_epoch(session_id)
|
|
148
|
+
@mutex.synchronize do
|
|
149
|
+
session = @sessions[session_id]
|
|
150
|
+
return nil unless session
|
|
151
|
+
|
|
152
|
+
session[:epoch] = session[:epoch].to_i + 1
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Current task epoch for a session (0 if none / unknown).
|
|
157
|
+
def current_epoch(session_id)
|
|
158
|
+
@mutex.synchronize { @sessions[session_id]&.fetch(:epoch, 0).to_i }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Update fields only if the caller still owns the current epoch. Returns
|
|
162
|
+
# true if the update was applied, false if the epoch was stale (a newer
|
|
163
|
+
# task has taken over) or the session is gone.
|
|
164
|
+
def update_if_epoch(session_id, epoch, **fields)
|
|
165
|
+
@mutex.synchronize do
|
|
166
|
+
session = @sessions[session_id]
|
|
167
|
+
return false unless session
|
|
168
|
+
return false unless session[:epoch].to_i == epoch.to_i
|
|
169
|
+
|
|
170
|
+
fields[:updated_at] = Time.now
|
|
171
|
+
session.merge!(fields)
|
|
172
|
+
true
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
140
176
|
# Return a session list from disk enriched with live registry status.
|
|
141
177
|
# Sorted by created_at descending (newest first).
|
|
142
178
|
#
|
|
@@ -160,7 +196,7 @@ module Clacky
|
|
|
160
196
|
# [ ...all_pinned_matching (newest-first), ...non_pinned (newest-first, limited) ]
|
|
161
197
|
#
|
|
162
198
|
# source and profile are orthogonal — either can be nil independently.
|
|
163
|
-
def list(limit: nil, before: nil, q: nil, q_scope: "name", date: nil, type: nil, include_pinned: true)
|
|
199
|
+
def list(limit: nil, before: nil, q: nil, q_scope: "name", date: nil, type: nil, exclude_type: nil, include_pinned: true)
|
|
164
200
|
return [] unless @session_manager
|
|
165
201
|
|
|
166
202
|
live = @mutex.synchronize do
|
|
@@ -169,7 +205,7 @@ module Clacky
|
|
|
169
205
|
live_name = s[:agent]&.name
|
|
170
206
|
live_name = nil if live_name&.empty?
|
|
171
207
|
live_cost_source = s[:agent]&.cost_source
|
|
172
|
-
{ status: s[:status], error: s[:error], error_code: s[:error_code], top_up_url: s[:top_up_url],
|
|
208
|
+
{ status: s[:status], error: s[:error], error_code: s[:error_code], top_up_url: s[:top_up_url], raw_message: s[:raw_message],
|
|
173
209
|
updated_at: s[:updated_at]&.iso8601,
|
|
174
210
|
model: model_info&.dig(:model), model_id: model_info&.dig(:id), name: live_name,
|
|
175
211
|
total_tasks: s[:agent]&.total_tasks, total_cost: s[:agent]&.total_cost,
|
|
@@ -195,6 +231,12 @@ module Clacky
|
|
|
195
231
|
end
|
|
196
232
|
end
|
|
197
233
|
|
|
234
|
+
# ── exclude_type filter ───────────────────────────────────────────────
|
|
235
|
+
if exclude_type
|
|
236
|
+
excluded = Array(exclude_type)
|
|
237
|
+
all = all.reject { |s| excluded.include?(s_source(s)) }
|
|
238
|
+
end
|
|
239
|
+
|
|
198
240
|
# ── date filter (YYYY-MM-DD, matches created_at prefix) ──────────────
|
|
199
241
|
all = all.select { |s| s[:created_at].to_s.start_with?(date) } if date
|
|
200
242
|
|
|
@@ -269,7 +311,7 @@ module Clacky
|
|
|
269
311
|
model_info = s[:agent]&.current_model_info
|
|
270
312
|
live_name = s[:agent]&.name
|
|
271
313
|
live_name = nil if live_name&.empty?
|
|
272
|
-
{ status: s[:status], error: s[:error], error_code: s[:error_code], top_up_url: s[:top_up_url],
|
|
314
|
+
{ status: s[:status], error: s[:error], error_code: s[:error_code], top_up_url: s[:top_up_url], raw_message: s[:raw_message],
|
|
273
315
|
updated_at: s[:updated_at]&.iso8601,
|
|
274
316
|
model: model_info&.dig(:model), model_id: model_info&.dig(:id),
|
|
275
317
|
name: live_name, total_tasks: s[:agent]&.total_tasks,
|
|
@@ -296,6 +338,7 @@ module Clacky
|
|
|
296
338
|
error: ls ? ls[:error] : nil,
|
|
297
339
|
error_code: ls&.dig(:error_code),
|
|
298
340
|
top_up_url: ls&.dig(:top_up_url),
|
|
341
|
+
raw_message: ls&.dig(:raw_message),
|
|
299
342
|
model: ls&.dig(:model),
|
|
300
343
|
model_id: ls&.dig(:model_id),
|
|
301
344
|
card_model: ls&.dig(:card_model),
|
|
@@ -347,6 +390,14 @@ module Clacky
|
|
|
347
390
|
@session_manager.all_sessions.count { |s| s_source(s) == "cron" }
|
|
348
391
|
end
|
|
349
392
|
|
|
393
|
+
# Count + latest updated_at for cron sessions (used by sidebar virtual entry).
|
|
394
|
+
def cron_stats
|
|
395
|
+
return { count: 0, latest_updated_at: nil } unless @session_manager
|
|
396
|
+
cron_all = @session_manager.all_sessions.select { |s| s_source(s) == "cron" }
|
|
397
|
+
latest = cron_all.map { |s| s[:updated_at] || s[:created_at] }.compact.max
|
|
398
|
+
{ count: cron_all.size, latest_updated_at: latest }
|
|
399
|
+
end
|
|
400
|
+
|
|
350
401
|
# Delete a session from registry (and interrupt its thread).
|
|
351
402
|
def delete(session_id)
|
|
352
403
|
@mutex.synchronize do
|
|
@@ -230,12 +230,13 @@ module Clacky
|
|
|
230
230
|
@broadcaster.call(@session_id, event)
|
|
231
231
|
end
|
|
232
232
|
|
|
233
|
-
def show_error(message, code: nil, top_up_url: nil)
|
|
233
|
+
def show_error(message, code: nil, top_up_url: nil, raw_message: nil)
|
|
234
234
|
payload = { message: message }
|
|
235
235
|
payload[:code] = code if code
|
|
236
236
|
payload[:top_up_url] = top_up_url if top_up_url
|
|
237
|
+
payload[:raw_message] = raw_message if raw_message
|
|
237
238
|
emit("error", **payload)
|
|
238
|
-
forward_to_subscribers { |sub| sub.show_error(message, code: code, top_up_url: top_up_url) }
|
|
239
|
+
forward_to_subscribers { |sub| sub.show_error(message, code: code, top_up_url: top_up_url, raw_message: raw_message) }
|
|
239
240
|
end
|
|
240
241
|
|
|
241
242
|
def show_success(message)
|
|
@@ -35,7 +35,7 @@ module Clacky
|
|
|
35
35
|
|
|
36
36
|
# Keep only the most recent 200 sessions (best-effort, never block save)
|
|
37
37
|
begin
|
|
38
|
-
cleanup_by_count(keep: 200)
|
|
38
|
+
cleanup_by_count(keep: 200, keep_cron: 200)
|
|
39
39
|
rescue Exception # rubocop:disable Lint/RescueException
|
|
40
40
|
# Cleanup is non-critical; swallow all errors (including AgentInterrupted)
|
|
41
41
|
end
|
|
@@ -163,6 +163,33 @@ module Clacky
|
|
|
163
163
|
chunk_path
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
+
# Read the raw markdown of a chunk file. Returns nil if missing.
|
|
167
|
+
def read_chunk(chunk_path)
|
|
168
|
+
return nil unless chunk_path && File.exist?(chunk_path)
|
|
169
|
+
File.read(chunk_path)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Split raw chunk markdown into [front_matter_hash, body_string].
|
|
173
|
+
# front_matter_hash preserves insertion order; body is everything after
|
|
174
|
+
# the closing "---". Returns [nil, raw] when there is no leading block.
|
|
175
|
+
def split_chunk_md(raw)
|
|
176
|
+
return [nil, raw.to_s] unless raw.to_s.start_with?("---")
|
|
177
|
+
|
|
178
|
+
fm_end = raw.index("\n---\n", 4)
|
|
179
|
+
return [nil, raw] unless fm_end
|
|
180
|
+
|
|
181
|
+
fm_text = raw[4...fm_end]
|
|
182
|
+
body = raw[(fm_end + 5)..] || ""
|
|
183
|
+
|
|
184
|
+
fm = {}
|
|
185
|
+
fm_text.each_line do |line|
|
|
186
|
+
k, _, v = line.chomp.partition(":")
|
|
187
|
+
next if k.strip.empty?
|
|
188
|
+
fm[k.strip] = v.strip
|
|
189
|
+
end
|
|
190
|
+
[fm, body]
|
|
191
|
+
end
|
|
192
|
+
|
|
166
193
|
# All sessions from disk, newest-first (sorted by last activity / updated_at,
|
|
167
194
|
# falling back to created_at for legacy sessions without updated_at).
|
|
168
195
|
# Optional filters:
|
|
@@ -305,11 +332,15 @@ module Clacky
|
|
|
305
332
|
# are soft-deleted (moved to the session trash, recoverable). Pinned
|
|
306
333
|
# sessions are never deleted and do not count toward the cap.
|
|
307
334
|
# Returns count of soft-deleted sessions.
|
|
308
|
-
def cleanup_by_count(keep:)
|
|
335
|
+
def cleanup_by_count(keep:, keep_cron: 200)
|
|
309
336
|
non_pinned = all_sessions.reject { |s| s[:pinned] } # already sorted newest-first
|
|
310
|
-
return 0 if non_pinned.size <= keep
|
|
311
337
|
|
|
312
|
-
|
|
338
|
+
cron, regular = non_pinned.partition { |s| s[:source].to_s == "cron" }
|
|
339
|
+
|
|
340
|
+
victims = []
|
|
341
|
+
victims += regular[keep..] if regular.size > keep
|
|
342
|
+
victims += cron[keep_cron..] if cron.size > keep_cron
|
|
343
|
+
|
|
313
344
|
victims.each { |session| soft_delete(session[:session_id]) }
|
|
314
345
|
victims.size
|
|
315
346
|
end
|
data/lib/clacky/skill_loader.rb
CHANGED
|
@@ -441,13 +441,11 @@ module Clacky
|
|
|
441
441
|
|
|
442
442
|
# Load default skills from gem's default_skills directory
|
|
443
443
|
private def load_default_skills
|
|
444
|
-
# Get the gem's lib directory
|
|
445
444
|
gem_lib_dir = File.expand_path("../", __dir__)
|
|
446
445
|
default_skills_dir = File.join(gem_lib_dir, "clacky", "default_skills")
|
|
447
446
|
|
|
448
447
|
return unless Dir.exist?(default_skills_dir)
|
|
449
448
|
|
|
450
|
-
# Load each skill directory
|
|
451
449
|
Dir.glob(File.join(default_skills_dir, "*/SKILL.md")).each do |skill_file|
|
|
452
450
|
skill_dir = File.dirname(skill_file)
|
|
453
451
|
skill_name = File.basename(skill_dir)
|
|
@@ -459,6 +457,20 @@ module Clacky
|
|
|
459
457
|
@errors << "Failed to load default skill #{skill_name}: #{e.message}"
|
|
460
458
|
end
|
|
461
459
|
end
|
|
460
|
+
|
|
461
|
+
# Also load skills bundled inside default_extensions/*/skills/
|
|
462
|
+
ext_skills_dir = File.join(gem_lib_dir, "clacky", "default_extensions")
|
|
463
|
+
Dir.glob(File.join(ext_skills_dir, "*/skills/*/SKILL.md")).each do |skill_file|
|
|
464
|
+
skill_dir = File.dirname(skill_file)
|
|
465
|
+
skill_name = File.basename(skill_dir)
|
|
466
|
+
|
|
467
|
+
begin
|
|
468
|
+
skill = Skill.new(Pathname.new(skill_dir))
|
|
469
|
+
register_skill(skill, source: :default)
|
|
470
|
+
rescue StandardError => e
|
|
471
|
+
@errors << "Failed to load default skill #{skill_name}: #{e.message}"
|
|
472
|
+
end
|
|
473
|
+
end
|
|
462
474
|
end
|
|
463
475
|
end
|
|
464
476
|
end
|
|
@@ -35,9 +35,7 @@ module Clacky
|
|
|
35
35
|
def clean(raw)
|
|
36
36
|
return "" if raw.nil? || raw.empty?
|
|
37
37
|
|
|
38
|
-
s = raw
|
|
39
|
-
s.force_encoding(Encoding::UTF_8)
|
|
40
|
-
s = s.scrub("?") unless s.valid_encoding?
|
|
38
|
+
s = Clacky::Utils::Encoding.pty_to_utf8(raw)
|
|
41
39
|
|
|
42
40
|
s = s.gsub(CSI_REGEX, "")
|
|
43
41
|
s = s.gsub(OSC_REGEX, "")
|
|
@@ -340,10 +340,6 @@ module Clacky
|
|
|
340
340
|
project_root: cwd || Dir.pwd
|
|
341
341
|
)
|
|
342
342
|
|
|
343
|
-
# PowerShell 5 on Chinese Windows emits CP936/GBK by default; force
|
|
344
|
-
# UTF-8 so our PTY (which decodes as UTF-8) doesn't see ??? bytes.
|
|
345
|
-
safe_command = force_powershell_utf8(safe_command)
|
|
346
|
-
|
|
347
343
|
# Background / dedicated path — never reuse the persistent shell,
|
|
348
344
|
# because these commands stay running and would occupy the slot.
|
|
349
345
|
if background
|
|
@@ -1522,45 +1518,6 @@ module Clacky
|
|
|
1522
1518
|
return "" if lines.empty?
|
|
1523
1519
|
lines.last(DISPLAY_TAIL_LINES).join("\n")
|
|
1524
1520
|
end
|
|
1525
|
-
|
|
1526
|
-
# PowerShell 5 on Chinese Windows defaults [Console]::OutputEncoding
|
|
1527
|
-
# to CP936/GBK; our PTY decodes as UTF-8 so non-ASCII output becomes
|
|
1528
|
-
# `???`. Inject UTF-8 setup into the user's PowerShell command so the
|
|
1529
|
-
# shell emits UTF-8 bytes regardless of host locale.
|
|
1530
|
-
POWERSHELL_PREAMBLE =
|
|
1531
|
-
"[Console]::OutputEncoding=[Text.Encoding]::UTF8;"
|
|
1532
|
-
|
|
1533
|
-
# Only rewrites simple `powershell[.exe]` / `pwsh[.exe]` invocations.
|
|
1534
|
-
# Skips -File / -EncodedCommand / commands already handling encoding /
|
|
1535
|
-
# pipelines (anything risky to splice).
|
|
1536
|
-
private def force_powershell_utf8(command)
|
|
1537
|
-
cmd = command.to_s
|
|
1538
|
-
return command unless cmd =~ /\A\s*(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\b/i
|
|
1539
|
-
return command if cmd =~ /OutputEncoding/i
|
|
1540
|
-
return command if cmd =~ /\s-(?:File|EncodedCommand|enc|f)\b/i
|
|
1541
|
-
|
|
1542
|
-
# `-Command "..."` form: pipeline / chain characters inside the
|
|
1543
|
-
# quoted body are PowerShell-internal, not shell-level, so we splice
|
|
1544
|
-
# safely into the quoted string.
|
|
1545
|
-
if (m = cmd.match(/\A(\s*(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\s+(?:[^"'\s]+\s+)*?-(?:Command|c)\s+)(["'])(.*)\2(\s*(?:<\s*\S+\s*)?)\z/i))
|
|
1546
|
-
head, quote, body, tail = m[1], m[2], m[3], m[4].to_s
|
|
1547
|
-
return "#{head}#{quote}#{POWERSHELL_PREAMBLE}#{body}#{quote}#{tail}"
|
|
1548
|
-
end
|
|
1549
|
-
|
|
1550
|
-
# Outside the quoted-Command form, refuse to splice if there's any
|
|
1551
|
-
# shell-level pipe / chain — too risky to get the boundaries right.
|
|
1552
|
-
return command if cmd =~ /[|&;]/
|
|
1553
|
-
|
|
1554
|
-
if (m = cmd.match(/\A(\s*(?:powershell(?:\.exe)?|pwsh(?:\.exe)?))(.*)\z/i))
|
|
1555
|
-
exe, rest = m[1], m[2].to_s.strip
|
|
1556
|
-
return command if rest.start_with?("-") && rest !~ /\A-(?:Command|c)\b/i
|
|
1557
|
-
rest = rest.sub(/\A-(?:Command|c)\b\s*/i, "")
|
|
1558
|
-
inner = rest.empty? ? POWERSHELL_PREAMBLE.chomp(";") : "#{POWERSHELL_PREAMBLE}#{rest}"
|
|
1559
|
-
return %Q{#{exe} -Command "#{inner}"}
|
|
1560
|
-
end
|
|
1561
|
-
|
|
1562
|
-
command
|
|
1563
|
-
end
|
|
1564
1521
|
end
|
|
1565
1522
|
end
|
|
1566
1523
|
end
|
|
@@ -120,28 +120,23 @@ module Clacky
|
|
|
120
120
|
@render_mutex.synchronize do
|
|
121
121
|
entry = @buffer.entry_by_id(id)
|
|
122
122
|
if entry.nil?
|
|
123
|
-
Clacky::Logger.warn("[ph_debug] replace_entry_nil", id: id, content: content.to_s[0, 120])
|
|
124
123
|
return
|
|
125
124
|
end
|
|
126
125
|
if entry.committed
|
|
127
|
-
Clacky::Logger.warn("[ph_debug] replace_entry_committed", id: id, content: content.to_s[0, 120])
|
|
128
126
|
return
|
|
129
127
|
end
|
|
130
128
|
if (entry.committed_line_offset || 0) > 0
|
|
131
|
-
Clacky::Logger.warn("[ph_debug] replace_entry_partial", id: id, offset: entry.committed_line_offset, content: content.to_s[0, 120])
|
|
132
129
|
return
|
|
133
130
|
end
|
|
134
131
|
|
|
135
132
|
old_lines = entry.lines.dup
|
|
136
133
|
new_lines = wrap_content_to_lines(content)
|
|
137
134
|
if old_lines == new_lines
|
|
138
|
-
Clacky::Logger.warn("[ph_debug] replace_entry_same", id: id)
|
|
139
135
|
screen.flush
|
|
140
136
|
return
|
|
141
137
|
end
|
|
142
138
|
@buffer.replace(id, new_lines)
|
|
143
139
|
is_tail = @buffer.live_entries.last&.id == id
|
|
144
|
-
Clacky::Logger.warn("[ph_debug] replace_entry_paint", id: id, is_tail: is_tail, old_n: old_lines.length, new_n: new_lines.length, content: content.to_s[0, 120])
|
|
145
140
|
|
|
146
141
|
unless @fullscreen_mode
|
|
147
142
|
# repaint_entry_in_place relies on the entry being the tail of
|
|
@@ -182,7 +182,6 @@ module Clacky
|
|
|
182
182
|
# @param final_message [String, nil] Optional override for the last
|
|
183
183
|
# frame. If nil, the handle composes "<message>… (<elapsed>s)".
|
|
184
184
|
def finish(final_message: nil)
|
|
185
|
-
Clacky::Logger.warn("[ph_debug] finish_entry", oid: object_id, state: @state, unreg: @unregistered, msg: @message, eid: @entry_id)
|
|
186
185
|
snapshot = @monitor.synchronize do
|
|
187
186
|
return if @unregistered
|
|
188
187
|
first_close = @state == :running
|
|
@@ -201,10 +200,8 @@ module Clacky
|
|
|
201
200
|
else
|
|
202
201
|
compose_final_frame(snapshot[:message], snapshot[:elapsed])
|
|
203
202
|
end
|
|
204
|
-
Clacky::Logger.warn("[ph_debug] finish_unregister", oid: object_id, eid: @entry_id, first_close: snapshot[:first_close], final_frame: final_frame.to_s[0, 200])
|
|
205
203
|
@owner.unregister_progress(self, final_frame: final_frame)
|
|
206
204
|
@monitor.synchronize { @unregistered = true }
|
|
207
|
-
Clacky::Logger.warn("[ph_debug] finish_done", oid: object_id)
|
|
208
205
|
end
|
|
209
206
|
alias_method :cancel, :finish
|
|
210
207
|
|