openclacky 1.3.1 → 1.3.3

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/Dockerfile +3 -0
  4. data/README.md +1 -1
  5. data/README_JA.md +237 -0
  6. data/lib/clacky/agent/session_serializer.rb +65 -11
  7. data/lib/clacky/agent/time_machine.rb +247 -26
  8. data/lib/clacky/agent.rb +12 -1
  9. data/lib/clacky/agent_config.rb +14 -2
  10. data/lib/clacky/brand_config.rb +1 -1
  11. data/lib/clacky/default_agents/_panels/git/panel.js +201 -0
  12. data/lib/clacky/default_agents/_panels/time_machine/panel.js +640 -0
  13. data/lib/clacky/default_agents/coding/profile.yml +3 -0
  14. data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
  15. data/lib/clacky/default_skills/cron-task-creator/SKILL.md +1 -1
  16. data/lib/clacky/default_skills/extend-openclacky/SKILL.md +6 -4
  17. data/lib/clacky/default_skills/media-gen/SKILL.md +30 -6
  18. data/lib/clacky/media/openai_compat.rb +64 -1
  19. data/lib/clacky/media/output_dir.rb +43 -0
  20. data/lib/clacky/message_history.rb +9 -0
  21. data/lib/clacky/server/channel/channel_manager.rb +26 -0
  22. data/lib/clacky/server/git_panel.rb +115 -0
  23. data/lib/clacky/server/http_server.rb +521 -13
  24. data/lib/clacky/server/server_master.rb +6 -4
  25. data/lib/clacky/utils/environment_detector.rb +16 -0
  26. data/lib/clacky/version.rb +1 -1
  27. data/lib/clacky/web/app.css +512 -60
  28. data/lib/clacky/web/app.js +30 -7
  29. data/lib/clacky/web/components/code-editor.js +197 -0
  30. data/lib/clacky/web/{notify.js → components/notify.js} +1 -1
  31. data/lib/clacky/web/core/aside.js +112 -0
  32. data/lib/clacky/web/core/ext.js +387 -0
  33. data/lib/clacky/web/features/backup/store.js +92 -0
  34. data/lib/clacky/web/features/backup/view.js +94 -0
  35. data/lib/clacky/web/features/billing/store.js +163 -0
  36. data/lib/clacky/web/{billing.js → features/billing/view.js} +134 -242
  37. data/lib/clacky/web/features/brand/store.js +110 -0
  38. data/lib/clacky/web/{brand.js → features/brand/view.js} +49 -199
  39. data/lib/clacky/web/features/channels/store.js +103 -0
  40. data/lib/clacky/web/{channels.js → features/channels/view.js} +50 -127
  41. data/lib/clacky/web/features/creator/store.js +81 -0
  42. data/lib/clacky/web/{creator.js → features/creator/view.js} +53 -102
  43. data/lib/clacky/web/features/mcp/store.js +158 -0
  44. data/lib/clacky/web/{mcp.js → features/mcp/view.js} +57 -134
  45. data/lib/clacky/web/features/model-tester/store.js +77 -0
  46. data/lib/clacky/web/features/model-tester/view.js +7 -0
  47. data/lib/clacky/web/features/profile/store.js +170 -0
  48. data/lib/clacky/web/{profile.js → features/profile/view.js} +94 -144
  49. data/lib/clacky/web/features/share/store.js +145 -0
  50. data/lib/clacky/web/{share.js → features/share/view.js} +66 -202
  51. data/lib/clacky/web/features/skills/store.js +303 -0
  52. data/lib/clacky/web/features/skills/view.js +550 -0
  53. data/lib/clacky/web/features/tasks/store.js +135 -0
  54. data/lib/clacky/web/features/tasks/view.js +241 -0
  55. data/lib/clacky/web/features/trash/store.js +242 -0
  56. data/lib/clacky/web/{trash.js → features/trash/view.js} +102 -293
  57. data/lib/clacky/web/features/version/store.js +165 -0
  58. data/lib/clacky/web/features/version/view.js +323 -0
  59. data/lib/clacky/web/features/workspace/store.js +99 -0
  60. data/lib/clacky/web/features/workspace/view.js +305 -0
  61. data/lib/clacky/web/i18n.js +60 -6
  62. data/lib/clacky/web/index.html +117 -57
  63. data/lib/clacky/web/sessions.js +221 -25
  64. data/lib/clacky/web/settings.js +121 -25
  65. data/lib/clacky/web/skills.js +3 -821
  66. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +29 -0
  67. data/lib/clacky.rb +1 -0
  68. metadata +45 -20
  69. data/lib/clacky/web/backup.js +0 -119
  70. data/lib/clacky/web/model-tester.js +0 -66
  71. data/lib/clacky/web/tasks.js +0 -365
  72. data/lib/clacky/web/version.js +0 -449
  73. data/lib/clacky/web/workspace.js +0 -212
  74. /data/lib/clacky/web/{notify.mp3 → assets/notify.mp3} +0 -0
  75. /data/lib/clacky/web/{datepicker.js → components/datepicker.js} +0 -0
  76. /data/lib/clacky/web/{onboard.js → components/onboard.js} +0 -0
  77. /data/lib/clacky/web/{sidebar.js → components/sidebar.js} +0 -0
  78. /data/lib/clacky/web/{marked.min.js → vendor/marked/marked.min.js} +0 -0
@@ -0,0 +1,163 @@
1
+ // ── Billing · store — usage data, currency settings, network ──────────────
2
+ //
3
+ // Owns billing state (summary / daily / sessions / model list / current period
4
+ // & model filter), currency conversion utilities (localStorage-backed), the
5
+ // data fetch, and clear-data actions. It never renders.
6
+ //
7
+ // Currency utilities are pure and read by both the view and other modules, so
8
+ // they live with the data layer. Emits store events the view reacts to; mirrors
9
+ // them to the extension bus via Clacky.ext.emit.
10
+ //
11
+ // `Billing` stays the single public facade.
12
+ //
13
+ // Depends on: Clacky.ext.
14
+ // ───────────────────────────────────────────────────────────────────────────
15
+
16
+ const BillingStore = (() => {
17
+ let _summary = null;
18
+ let _daily = [];
19
+ let _sessions = [];
20
+ let _allModels = [];
21
+ let _currentPeriod = "day";
22
+ let _currentModel = "all";
23
+
24
+ const CURRENCY_STORAGE_KEY = "clacky-currency";
25
+ const EXCHANGE_RATE_STORAGE_KEY = "clacky-exchange-rate";
26
+ const DEFAULT_USD_TO_CNY_RATE = 6.7944;
27
+
28
+ const _listeners = {};
29
+
30
+ function _on(event, handler) {
31
+ (_listeners[event] ||= []).push(handler);
32
+ return () => {
33
+ const list = _listeners[event];
34
+ const i = list ? list.indexOf(handler) : -1;
35
+ if (i >= 0) list.splice(i, 1);
36
+ };
37
+ }
38
+
39
+ function _emit(event, payload) {
40
+ (_listeners[event] || []).forEach((h) => h(payload));
41
+ if (window.Clacky && Clacky.ext) Clacky.ext.emit(event, payload);
42
+ }
43
+
44
+ function _getCurrency() {
45
+ try { return localStorage.getItem(CURRENCY_STORAGE_KEY) || "USD"; } catch (_) { return "USD"; }
46
+ }
47
+
48
+ function _getExchangeRate() {
49
+ try {
50
+ const rate = localStorage.getItem(EXCHANGE_RATE_STORAGE_KEY);
51
+ if (rate) {
52
+ const parsed = parseFloat(rate);
53
+ if (!isNaN(parsed) && parsed > 0) return parsed;
54
+ }
55
+ } catch (_) {}
56
+ return DEFAULT_USD_TO_CNY_RATE;
57
+ }
58
+
59
+ function _setExchangeRate(rate) {
60
+ try {
61
+ if (rate && !isNaN(rate) && rate > 0) {
62
+ localStorage.setItem(EXCHANGE_RATE_STORAGE_KEY, rate.toString());
63
+ document.dispatchEvent(new CustomEvent("currencychange"));
64
+ }
65
+ } catch (_) {}
66
+ }
67
+
68
+ function _convertCost(usdCost) {
69
+ if (_getCurrency() === "CNY") return usdCost * _getExchangeRate();
70
+ return usdCost;
71
+ }
72
+
73
+ function _getCurrencySymbol() {
74
+ return _getCurrency() === "CNY" ? "¥" : "$";
75
+ }
76
+
77
+ const state = {
78
+ get summary() { return _summary; },
79
+ get daily() { return _daily; },
80
+ get sessions() { return _sessions; },
81
+ get allModels() { return _allModels; },
82
+ get currentPeriod() { return _currentPeriod; },
83
+ get currentModel() { return _currentModel; },
84
+ };
85
+
86
+ const Billing = {
87
+ on: _on,
88
+ state,
89
+
90
+ getCurrency: _getCurrency,
91
+ getExchangeRate: _getExchangeRate,
92
+ setExchangeRate: _setExchangeRate,
93
+ convertCost: _convertCost,
94
+ getCurrencySymbol: _getCurrencySymbol,
95
+
96
+ /** Entry point: load usage data. */
97
+ open() {
98
+ return Billing.load();
99
+ },
100
+
101
+ /** Re-emit a changed event so the view re-renders (e.g. on currency change). */
102
+ refreshView() {
103
+ if (_summary) _emit("billing:changed");
104
+ },
105
+
106
+ setPeriod(period) { _currentPeriod = period; return Billing.load(); },
107
+ setModel(model) { _currentModel = model; return Billing.load(); },
108
+
109
+ async load() {
110
+ const isFirstLoad = !_summary;
111
+ _emit("billing:loading", { isFirstLoad });
112
+
113
+ try {
114
+ const modelParam = (_currentModel && _currentModel !== "all") ? `&model=${encodeURIComponent(_currentModel)}` : "";
115
+ const [summaryRes, dailyRes, sessionsRes] = await Promise.all([
116
+ fetch(`/api/billing/summary?period=${_currentPeriod}${modelParam}`),
117
+ fetch(`/api/billing/daily?days=30${modelParam}`),
118
+ fetch(`/api/billing/sessions?period=${_currentPeriod}${modelParam}&limit=100`)
119
+ ]);
120
+
121
+ _summary = await summaryRes.json();
122
+ const dailyData = await dailyRes.json();
123
+ _daily = dailyData.days || [];
124
+
125
+ const sessionsData = await sessionsRes.json();
126
+ _sessions = sessionsData.sessions || [];
127
+
128
+ if (!_currentModel || _currentModel === "all") {
129
+ _allModels = _summary.by_model ? Object.keys(_summary.by_model) : [];
130
+ }
131
+
132
+ _emit("billing:changed");
133
+ } catch (e) {
134
+ _emit("billing:error", { message: e.message });
135
+ }
136
+ },
137
+
138
+ /** Fetch summary for a single period (used by scorecard background fill). */
139
+ async fetchSummary(period) {
140
+ const modelParam = (_currentModel && _currentModel !== "all") ? `&model=${encodeURIComponent(_currentModel)}` : "";
141
+ const r = await fetch(`/api/billing/summary?period=${period}${modelParam}`);
142
+ return r.json();
143
+ },
144
+
145
+ async clearData(scope) {
146
+ try {
147
+ const res = await fetch(`/api/billing/clear?scope=${scope}`, { method: "DELETE" });
148
+ const data = await res.json();
149
+ if (res.ok) {
150
+ await Billing.load();
151
+ } else {
152
+ _emit("billing:actionError", { message: data.error || "Failed to clear data" });
153
+ }
154
+ } catch (e) {
155
+ _emit("billing:actionError", { message: `Error clearing data: ${e.message}` });
156
+ }
157
+ },
158
+ };
159
+
160
+ return Billing;
161
+ })();
162
+
163
+ const Billing = BillingStore;