openclacky 1.1.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/CONTRIBUTING.md +92 -0
  5. data/README.md +10 -0
  6. data/README_CN.md +10 -0
  7. data/ROADMAP.md +29 -0
  8. data/docs/billing-system.md +340 -0
  9. data/docs/mcp-architecture.md +114 -0
  10. data/docs/mcp.example.json +22 -0
  11. data/lib/clacky/agent/cost_tracker.rb +37 -0
  12. data/lib/clacky/agent/llm_caller.rb +0 -1
  13. data/lib/clacky/agent/session_serializer.rb +2 -11
  14. data/lib/clacky/agent/skill_manager.rb +73 -26
  15. data/lib/clacky/agent/system_prompt_builder.rb +0 -5
  16. data/lib/clacky/agent/time_machine.rb +6 -0
  17. data/lib/clacky/agent.rb +26 -1
  18. data/lib/clacky/agent_config.rb +9 -19
  19. data/lib/clacky/billing/billing_record.rb +67 -0
  20. data/lib/clacky/billing/billing_store.rb +193 -0
  21. data/lib/clacky/cli.rb +108 -6
  22. data/lib/clacky/default_skills/browser-setup/SKILL.md +26 -4
  23. data/lib/clacky/default_skills/mcp-manager/SKILL.md +343 -0
  24. data/lib/clacky/idle_compression_timer.rb +4 -2
  25. data/lib/clacky/mcp/client.rb +204 -0
  26. data/lib/clacky/mcp/http_transport.rb +155 -0
  27. data/lib/clacky/mcp/registry.rb +229 -0
  28. data/lib/clacky/mcp/skill_provider.rb +75 -0
  29. data/lib/clacky/mcp/stdio_transport.rb +112 -0
  30. data/lib/clacky/mcp/transport.rb +23 -0
  31. data/lib/clacky/mcp/virtual_skill.rb +131 -0
  32. data/lib/clacky/message_history.rb +0 -1
  33. data/lib/clacky/server/channel/adapters/weixin/adapter.rb +2 -35
  34. data/lib/clacky/server/http_server.rb +519 -15
  35. data/lib/clacky/server/server_master.rb +8 -14
  36. data/lib/clacky/server/session_registry.rb +24 -2
  37. data/lib/clacky/server/web_ui_controller.rb +4 -0
  38. data/lib/clacky/session_manager.rb +41 -12
  39. data/lib/clacky/skill.rb +1 -5
  40. data/lib/clacky/skill_loader.rb +36 -5
  41. data/lib/clacky/tools/browser.rb +217 -38
  42. data/lib/clacky/tools/trash_manager.rb +154 -3
  43. data/lib/clacky/ui2/components/command_suggestions.rb +6 -2
  44. data/lib/clacky/ui_interface.rb +1 -0
  45. data/lib/clacky/utils/model_pricing.rb +11 -7
  46. data/lib/clacky/utils/trash_directory.rb +37 -6
  47. data/lib/clacky/version.rb +1 -1
  48. data/lib/clacky/web/app.css +2907 -1764
  49. data/lib/clacky/web/app.js +84 -10
  50. data/lib/clacky/web/billing.js +275 -0
  51. data/lib/clacky/web/brand.js +3 -0
  52. data/lib/clacky/web/i18n.js +242 -24
  53. data/lib/clacky/web/index.html +351 -134
  54. data/lib/clacky/web/mcp.js +328 -0
  55. data/lib/clacky/web/sessions.js +193 -11
  56. data/lib/clacky/web/settings.js +686 -174
  57. data/lib/clacky/web/sidebar.js +2 -0
  58. data/lib/clacky/web/trash.js +323 -60
  59. data/lib/clacky/web/ws-dispatcher.js +14 -1
  60. data/lib/clacky.rb +4 -0
  61. data/scripts/install.ps1 +23 -11
  62. metadata +30 -10
@@ -111,6 +111,10 @@ module Clacky
111
111
  # - "cache miss input" = regular prompt_tokens rate
112
112
  # - "cache hit input" = cache_read rate (DeepSeek has no separate cache-write charge)
113
113
  # - No tiered pricing (single rate regardless of context length)
114
+ # Cache-hit prices are 1/10 of launch (global, permanent since 2026-04-26).
115
+ # v4-pro is on a 75% off promo through 2026-05-31 23:59 CST; the same
116
+ # numbers become the permanent price after that date (= original × 1/4),
117
+ # so we bill at the discounted rates both before and after the cutover.
114
118
  "deepseek-v4-flash" => {
115
119
  input: {
116
120
  default: 0.14, # $0.14/MTok cache miss
@@ -122,22 +126,22 @@ module Clacky
122
126
  },
123
127
  cache: {
124
128
  write: 0.14, # DeepSeek doesn't charge extra for writes; bill at miss rate
125
- read: 0.0028 # $0.0028/MTok cache hit
129
+ read: 0.0028 # $0.0028/MTok cache hit
126
130
  }
127
131
  },
128
132
 
129
133
  "deepseek-v4-pro" => {
130
134
  input: {
131
- default: 1.74, # $1.74/MTok cache miss
132
- over_200k: 1.74
135
+ default: 0.435, # $0.435/MTok cache miss (75% off; permanent after 5/31)
136
+ over_200k: 0.435
133
137
  },
134
138
  output: {
135
- default: 3.48, # $3.48/MTok
136
- over_200k: 3.48
139
+ default: 0.87, # $0.87/MTok (75% off; permanent after 5/31)
140
+ over_200k: 0.87
137
141
  },
138
142
  cache: {
139
- write: 1.74, # no separate write charge; bill at miss rate
140
- read: 0.0145 # $0.0145/MTok cache hit
143
+ write: 0.435, # no separate write charge; bill at miss rate
144
+ read: 0.003625 # $0.003625/MTok cache hit (1/10 × 75% off)
141
145
  }
142
146
  },
143
147
 
@@ -4,17 +4,28 @@ require "digest"
4
4
  require "fileutils"
5
5
 
6
6
  module Clacky
7
- # Manages global trash directory at ~/.clacky/trash
8
- # Organizes trash by project directory using path hash
7
+ # Manages global trash directory at ~/.clacky/trash.
8
+ # Organises both file-trash and session-trash under one root:
9
+ # ~/.clacky/trash/
10
+ # ├── file-trash/ ← AI-deleted project files, keyed by project hash
11
+ # └── sessions-trash/ ← soft-deleted sessions (JSON + chunk MD files)
9
12
  class TrashDirectory
10
13
  GLOBAL_TRASH_ROOT = File.join(Dir.home, ".clacky", "trash")
11
14
 
15
+ def self.files_trash_dir
16
+ File.join(GLOBAL_TRASH_ROOT, "file-trash")
17
+ end
18
+
19
+ def self.sessions_trash_dir
20
+ File.join(GLOBAL_TRASH_ROOT, "sessions-trash")
21
+ end
22
+
12
23
  attr_reader :project_root, :trash_dir, :backup_dir
13
24
 
14
25
  def initialize(project_root = Dir.pwd)
15
26
  @project_root = File.expand_path(project_root)
16
27
  @project_hash = generate_project_hash(@project_root)
17
- @trash_dir = File.join(GLOBAL_TRASH_ROOT, @project_hash)
28
+ @trash_dir = File.join(self.class.files_trash_dir, @project_hash)
18
29
  @backup_dir = File.join(@trash_dir, "backups")
19
30
 
20
31
  setup_directories
@@ -63,12 +74,32 @@ module Clacky
63
74
  warn "Warning: Could not create project metadata: #{e.message}"
64
75
  end
65
76
 
77
+ # ── Legacy migration ──────────────────────────────────────────────
78
+
79
+ OLD_TRASH_ROOT = File.join(Dir.home, ".clacky", "trash")
80
+
81
+ # One-time: move pre-file-trash project hash dirs from ~/.clacky/trash/
82
+ # directly into the new file-trash/ subdirectory. Safe to call on every boot.
83
+ def self.migrate_legacy_if_needed
84
+ return unless Dir.exist?(OLD_TRASH_ROOT)
85
+
86
+ FileUtils.mkdir_p(files_trash_dir)
87
+
88
+ Dir.glob(File.join(OLD_TRASH_ROOT, "*")).each do |entry|
89
+ basename = File.basename(entry)
90
+ next if %w[file-trash sessions-trash].include?(basename)
91
+ next if File.directory?(File.join(files_trash_dir, basename))
92
+
93
+ FileUtils.mv(entry, files_trash_dir)
94
+ end
95
+ end
96
+
66
97
  # Get all project directories that have trash
67
98
  def self.all_projects
68
- return [] unless Dir.exist?(GLOBAL_TRASH_ROOT)
99
+ return [] unless Dir.exist?(files_trash_dir)
69
100
 
70
101
  projects = []
71
- Dir.glob(File.join(GLOBAL_TRASH_ROOT, "*", ".project_metadata.json")).each do |metadata_file|
102
+ Dir.glob(File.join(files_trash_dir, "*", ".project_metadata.json")).each do |metadata_file|
72
103
  begin
73
104
  metadata = JSON.parse(File.read(metadata_file))
74
105
  projects << {
@@ -93,7 +124,7 @@ module Clacky
93
124
 
94
125
  # Clean up trash directories for non-existent projects
95
126
  def self.cleanup_orphaned_projects
96
- return 0 unless Dir.exist?(GLOBAL_TRASH_ROOT)
127
+ return 0 unless Dir.exist?(files_trash_dir)
97
128
 
98
129
  cleaned_count = 0
99
130
  all_projects.each do |project|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clacky
4
- VERSION = "1.1.6"
4
+ VERSION = "1.2.0"
5
5
  end