openclacky 1.3.7 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/lib/clacky/agent/hook_manager.rb +10 -1
  4. data/lib/clacky/agent/system_prompt_builder.rb +1 -1
  5. data/lib/clacky/agent.rb +9 -2
  6. data/lib/clacky/agent_profile.rb +7 -4
  7. data/lib/clacky/billing/billing_store.rb +3 -2
  8. data/lib/clacky/brand_config.rb +2 -1
  9. data/lib/clacky/default_extensions/coding/agents/coding/avatar.png +0 -0
  10. data/lib/clacky/default_extensions/coding/ext.yml +4 -4
  11. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/avatar.png +0 -0
  12. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +0 -1
  13. data/lib/clacky/default_extensions/ext-studio/api/handler.rb +4 -3
  14. data/lib/clacky/default_extensions/ext-studio/ext.yml +1 -1
  15. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +118 -50
  16. data/lib/clacky/default_extensions/ext-studio/skills/ext-publish/SKILL.md +1 -2
  17. data/lib/clacky/default_extensions/general/agents/general/avatar.png +0 -0
  18. data/lib/clacky/default_extensions/general/ext.yml +4 -4
  19. data/lib/clacky/default_extensions/git/ext.yml +0 -1
  20. data/lib/clacky/default_extensions/git/panels/git/view.js +3 -3
  21. data/lib/clacky/default_extensions/meeting/ext.yml +0 -1
  22. data/lib/clacky/default_extensions/meeting/panels/meeting/view.js +1 -2
  23. data/lib/clacky/default_extensions/time_machine/ext.yml +0 -1
  24. data/lib/clacky/extension/api_extension.rb +11 -2
  25. data/lib/clacky/extension/dispatcher.rb +3 -2
  26. data/lib/clacky/extension/loader.rb +6 -0
  27. data/lib/clacky/extension/packager.rb +0 -6
  28. data/lib/clacky/extension/verifier.rb +1 -1
  29. data/lib/clacky/server/http_server.rb +149 -5
  30. data/lib/clacky/shell_hook_loader.rb +266 -22
  31. data/lib/clacky/ui2/components/welcome_banner.rb +1 -1
  32. data/lib/clacky/utils/workspace_rules.rb +2 -2
  33. data/lib/clacky/version.rb +1 -1
  34. data/lib/clacky/web/app.css +334 -73
  35. data/lib/clacky/web/core/ext.js +130 -24
  36. data/lib/clacky/web/features/extensions/store.js +41 -6
  37. data/lib/clacky/web/features/extensions/view.js +44 -13
  38. data/lib/clacky/web/features/new-session/store.js +13 -0
  39. data/lib/clacky/web/features/new-session/view.js +314 -14
  40. data/lib/clacky/web/features/trash/view.js +4 -5
  41. data/lib/clacky/web/i18n.js +44 -2
  42. data/lib/clacky/web/index.html +54 -16
  43. data/lib/clacky/web/sessions.js +3 -3
  44. data/lib/clacky/web/skills.js +86 -48
  45. data/lib/clacky/web/theme.js +3 -0
  46. data/lib/clacky/web/ws-dispatcher.js +11 -2
  47. metadata +7 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48e94ccf83645b5e18be8d5d33582dc128b06824ab226dd314540658b9cc7e4a
4
- data.tar.gz: 1112ed443505eca99e745838377ebbf4b6f1e96a7c7f83c7bf1cff844b5ddea9
3
+ metadata.gz: d7208295135923baf898665ce973cbd07ec3e218437cf896bf3a6a2644b2d026
4
+ data.tar.gz: ced24c041431be4afde0a6237afe250ca0876091c1b5f0ee3bf28eb4d166c152
5
5
  SHA512:
6
- metadata.gz: b0e4b2664bb7990ec91dd7c5598cfb561ce6f931b1f006a962b6cbf5516ee424b3a6f605fd70c3996ad4d0e0bf1a20dfd626d6466020393cc8cf18832008a68a
7
- data.tar.gz: 2b74eea0a552e5d26545779da2f0a2b1f88812063398ffbf15be913e396d6efe7131d8205bff766939ef252c4ca3b8075ce8e86c855de59774226e3e03bdbfde
6
+ metadata.gz: eab17f40014529d41ab26f6aee158caee98f3d6a78eef6066bff86f65d24cd8cc949f20c4ce31e3a878c11bb0e70ee6210dbe68b2dbfcd2e4840dd041257e506
7
+ data.tar.gz: cfdbd77b8bdd77d8a065fe3eea1222e6d272f792ad116ca511f50becb25f0db5690bb6683cddd8e1f33fe25228bacadaec32582d6d37daa3596d3d6133f19e10
data/CHANGELOG.md CHANGED
@@ -3,8 +3,50 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+
7
+ ## [1.3.9] - 2026-07-08
8
+
9
+ ### Added
10
+ - Installed filter tab in extension marketplace toolbar — quickly view only installed extensions
11
+ - Extension detail page UI improvements with better uninstall behavior
12
+ - `send_data` helper for API extensions to return binary file responses
13
+
14
+ ### Improved
15
+ - Extension marketplace upload flow reworked — `origin` field removed, cleaner package structure
16
+ - Publish modal redesigned with meta block, improved layout, size, and animation
17
+ - Debug panel verify result now shown inline in action bar with auto-hide and friendly hint
18
+
19
+ ### Fixed
20
+ - Zero-byte zip download when exporting extensions — binary responses now handled correctly
21
+ - Filter tab bottom padding adjusted for better underline spacing
22
+ - New-session advanced panel margin-top adjusted
23
+ - Debug panel detail no longer shows origin field
6
24
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
25
 
26
+ ## [1.3.8] - 2026-07-07
27
+
28
+ ### Added
29
+ - Shell hook `type:rewrite` protocol with `updatedInput` support — hooks can now rewrite the command before execution
30
+ - Support for `AGENTS.md` workspace rules — agent reads project-level rules from AGENTS.md automatically
31
+ - Avatar support in Web UI
32
+ - Open first tab automatically on session start
33
+
34
+ ### Improved
35
+ - New-session page UI humanized with improved layout and discoverability
36
+ - Session bar slot support for extension customization
37
+ - Extension description metadata in ext-studio
38
+
39
+ ### Fixed
40
+ - Mobile new-session page layout uses fixed positioning correctly
41
+ - Weekly stats period now starts from Monday instead of a rolling 7-day window
42
+ - i18n translations updated and UI refreshes immediately on language change
43
+ - Extension market toolbar layout and back button styling
44
+ - Skeleton screen rendering in ext-studio and extension market
45
+ - Trash skeleton screen restored on loading state
46
+ - Media usage logging now passes session_id correctly for image/video generation
47
+ - Billing writes in tests isolated via `CLACKY_BILLING_DIR` env var
48
+ - Meeting panel no longer overrides aside-panel container class
49
+
8
50
  ## [1.3.7] - 2026-07-06
9
51
 
10
52
  ### Added
@@ -28,7 +28,16 @@ module Clacky
28
28
  @hooks[event].each do |hook|
29
29
  begin
30
30
  hook_result = hook.call(*args)
31
- result.merge!(hook_result) if hook_result.is_a?(Hash)
31
+ next unless hook_result.is_a?(Hash)
32
+ # First deny wins and stops the chain: a weaker later verdict must
33
+ # never clobber a stronger earlier one, and the first deny's reason
34
+ # is the one that reaches the agent. Rewrite hooks mutate `call` in
35
+ # place (chained rewrite), so for non-deny results there's nothing to
36
+ # merge — we just keep going.
37
+ if hook_result[:action] == :deny
38
+ result = hook_result
39
+ break
40
+ end
32
41
  rescue StandardError => e
33
42
  # Log error but don't fail
34
43
  Clacky::Logger.error("Hook error", event: event, error: e)
@@ -8,7 +8,7 @@ module Clacky
8
8
  # Builds system prompt by composing layers:
9
9
  # 1. Agent-specific system_prompt.md (role & responsibilities)
10
10
  # 2. base_prompt.md (universal rules: todo manager, tool usage, etc.)
11
- # 3. Project rules (.clackyrules / .cursorrules / CLAUDE.md)
11
+ # 3. Project rules (.clackyrules / AGENTS.md / .cursorrules / CLAUDE.md)
12
12
  # 4. SOUL.md (agent personality — user override or built-in default)
13
13
  # 5. USER.md (user profile — user override or built-in default)
14
14
  # 6. Skills context (available skills list)
data/lib/clacky/agent.rb CHANGED
@@ -145,8 +145,15 @@ module Clacky
145
145
  # Register built-in tools
146
146
  register_builtin_tools
147
147
 
148
- # Load declarative shell hooks from ~/.clacky/hooks.yml
149
- ShellHookLoader.load_into(@hooks)
148
+ # Load declarative shell hooks from ~/.clacky/hooks.yml. Entries with
149
+ # `type: rewrite` use the rich JSON protocol (updatedInput rewrite);
150
+ # entries without `type` use the simple exit-code protocol.
151
+ ShellHookLoader.load_into(
152
+ @hooks,
153
+ session_id_fn: -> { @session_id },
154
+ cwd_fn: -> { @working_dir },
155
+ permission_mode_fn: -> { @config.permission_mode.to_s }
156
+ )
150
157
 
151
158
  # Copy ext.yml-contributed hook callbacks (contributes.hooks) onto this
152
159
  # agent's hook manager. The callbacks were registered process-wide at
@@ -53,11 +53,11 @@ module Clacky
53
53
 
54
54
  # List all available agent profiles across user + extension layers.
55
55
  # Precedence on id collision: user override → extension unit.
56
- # @return [Array<Hash>] each: { id:, title:, title_zh:, description:, description_zh:, source:, order:, layer:, author: }
56
+ # @return [Array<Hash>] each: { id:, title:, title_zh:, description:, description_zh:, source:, order:, layer:, author:, avatar: }
57
57
  def self.all
58
58
  out = {}
59
59
 
60
- add = lambda do |id, title, title_zh, description, description_zh, source, order, layer, author|
60
+ add = lambda do |id, title, title_zh, description, description_zh, source, order, layer, author, avatar|
61
61
  next if id.nil? || id.empty?
62
62
  out[id] = {
63
63
  id: id,
@@ -69,6 +69,7 @@ module Clacky
69
69
  order: order,
70
70
  layer: layer,
71
71
  author: author,
72
+ avatar: avatar,
72
73
  }
73
74
  end
74
75
 
@@ -77,11 +78,12 @@ module Clacky
77
78
  spec = unit.spec || {}
78
79
  title = spec["title"].to_s
79
80
  title = unit.id if title.empty?
81
+ avatar = spec["avatar_abs"].to_s.empty? ? nil : "/agent_avatar/#{unit.id}"
80
82
  add.call(
81
83
  unit.id, title, spec["title_zh"].to_s,
82
84
  spec["description"].to_s, spec["description_zh"].to_s,
83
85
  "extension", spec["order"], unit.layer.to_s,
84
- spec["author"].to_s
86
+ spec["author"].to_s, avatar
85
87
  )
86
88
  end
87
89
 
@@ -91,11 +93,12 @@ module Clacky
91
93
  next if id.start_with?("_")
92
94
  next unless File.file?(File.join(path, "profile.yml"))
93
95
  meta = read_profile_yml(File.join(path, "profile.yml"))
96
+ user_avatar = File.file?(File.join(path, "avatar.png")) ? "/agent_avatar/#{id}" : nil
94
97
  add.call(
95
98
  id, meta["title"] || meta["name"] || id, meta["title_zh"].to_s,
96
99
  meta["description"].to_s, meta["description_zh"].to_s,
97
100
  "user", meta["order"], "user",
98
- meta["author"].to_s.empty? ? "You" : meta["author"].to_s
101
+ meta["author"].to_s.empty? ? "You" : meta["author"].to_s, user_avatar
99
102
  )
100
103
  end
101
104
 
@@ -13,7 +13,7 @@ module Clacky
13
13
  BILLING_DIR = File.join(Dir.home, ".clacky", "billing")
14
14
 
15
15
  def initialize(billing_dir: nil)
16
- @billing_dir = billing_dir || BILLING_DIR
16
+ @billing_dir = billing_dir || ENV["CLACKY_BILLING_DIR"] || BILLING_DIR
17
17
  ensure_billing_dir
18
18
  end
19
19
 
@@ -339,7 +339,8 @@ module Clacky
339
339
  when :day
340
340
  Time.new(now.year, now.month, now.day)
341
341
  when :week
342
- now - (7 * 24 * 60 * 60)
342
+ days_since_monday = now.wday == 0 ? 6 : now.wday - 1
343
+ Time.new(now.year, now.month, now.day) - (days_since_monday * 24 * 60 * 60)
343
344
  when :month
344
345
  Time.new(now.year, now.month, 1)
345
346
  when :year
@@ -596,7 +596,7 @@ module Clacky
596
596
  #
597
597
  # Returns { success: true, extension: {...} } or
598
598
  # { success: false, error: "...", already_exists: Boolean }.
599
- def upload_extension!(ext_id, zip_data, force: false, status: nil, changelog: nil)
599
+ def upload_extension!(ext_id, zip_data, force: false, status: nil, changelog: nil, origin: 'marketplace')
600
600
  identity = Clacky::Identity.load
601
601
  return { success: false, error: "Device not bound to a platform account" } unless identity.bound?
602
602
 
@@ -607,6 +607,7 @@ module Clacky
607
607
  end
608
608
 
609
609
  fields = { "device_token" => identity.device_token }
610
+ fields["origin"] = origin.to_s if origin
610
611
  fields["status"] = status.to_s if status
611
612
  fields["changelog"] = changelog.to_s if changelog
612
613
 
@@ -5,14 +5,14 @@ version: "0.1.0"
5
5
  author: OpenClacky
6
6
  homepage: https://www.openclacky.com
7
7
  license: MIT
8
- origin: self
9
8
  contributes:
10
9
  agents:
11
10
  - id: coding
12
11
  title: Coding
13
- title_zh: 编程
14
- description: AI coding assistant and technical co-founder
15
- description_zh: AI 编程助手,你的技术合伙人
12
+ title_zh: 编程开发
13
+ description: Claude Code-grade coding capability, your technical co-founder
14
+ description_zh: 对齐 Claude Code 的编程能力,你的技术合伙人
16
15
  order: 2
17
16
  prompt: agents/coding/system_prompt.md
17
+ avatar: agents/coding/avatar.png
18
18
  panels: [git/git, time_machine/time_machine]
@@ -40,7 +40,6 @@ id: my-ext
40
40
  name: My Extension
41
41
  description: what it does
42
42
  version: "0.1.0"
43
- origin: self
44
43
  contributes:
45
44
  api: api/handler.rb
46
45
  panels:
@@ -48,12 +48,13 @@ class ExtStudioExt < Clacky::ApiExtension
48
48
 
49
49
  # POST /api/ext/ext-studio/pack
50
50
  # body: { ext_id }
51
- # Packs a local container into a zip (into a temp dir) and reports its path.
51
+ # Packs a local container and streams the zip back as a file download.
52
52
  post "/pack" do
53
53
  ext_id = require_ext_id!
54
54
  Dir.mktmpdir("clacky-ext-studio-pack") do |tmp|
55
- res = Clacky::ExtensionPackager.pack(ext_id, out_dir: tmp)
56
- json(ok: true, ext_id: res.ext_id, path: res.path)
55
+ res = Clacky::ExtensionPackager.pack(ext_id, out_dir: tmp)
56
+ zip_data = File.binread(res.path)
57
+ send_data(zip_data, content_type: "application/zip", filename: "#{res.ext_id}.zip")
57
58
  end
58
59
  rescue Clacky::ExtensionPackager::Error => e
59
60
  error!(e.message, status: 422)
@@ -5,7 +5,6 @@ version: "0.1.0"
5
5
  author: OpenClacky
6
6
  homepage: https://www.openclacky.com
7
7
  license: MIT
8
- origin: self
9
8
  contributes:
10
9
  api: api/handler.rb
11
10
  panels:
@@ -24,6 +23,7 @@ contributes:
24
23
  description_zh: 帮你开发、调试、发布 OpenClacky 扩展的 AI 专家
25
24
  order: 5
26
25
  prompt: agents/ext-developer/system_prompt.md
26
+ avatar: agents/ext-developer/avatar.png
27
27
  panels: [studio]
28
28
  skills: [ext-scaffold, ext-debug, ext-publish]
29
29
  skills: