openclacky 1.3.2 → 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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -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 +49 -5
  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/default_agents/_panels/git/panel.js +201 -0
  11. data/lib/clacky/default_agents/_panels/time_machine/panel.js +640 -0
  12. data/lib/clacky/default_agents/coding/profile.yml +3 -0
  13. data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
  14. data/lib/clacky/default_skills/cron-task-creator/SKILL.md +1 -1
  15. data/lib/clacky/default_skills/extend-openclacky/SKILL.md +6 -4
  16. data/lib/clacky/default_skills/media-gen/SKILL.md +30 -6
  17. data/lib/clacky/media/openai_compat.rb +64 -1
  18. data/lib/clacky/media/output_dir.rb +43 -0
  19. data/lib/clacky/message_history.rb +9 -0
  20. data/lib/clacky/server/channel/channel_manager.rb +26 -0
  21. data/lib/clacky/server/git_panel.rb +115 -0
  22. data/lib/clacky/server/http_server.rb +497 -12
  23. data/lib/clacky/server/server_master.rb +6 -4
  24. data/lib/clacky/version.rb +1 -1
  25. data/lib/clacky/web/app.css +473 -60
  26. data/lib/clacky/web/app.js +30 -7
  27. data/lib/clacky/web/components/code-editor.js +197 -0
  28. data/lib/clacky/web/{notify.js → components/notify.js} +1 -1
  29. data/lib/clacky/web/core/aside.js +112 -0
  30. data/lib/clacky/web/core/ext.js +387 -0
  31. data/lib/clacky/web/features/backup/store.js +92 -0
  32. data/lib/clacky/web/features/backup/view.js +94 -0
  33. data/lib/clacky/web/features/billing/store.js +163 -0
  34. data/lib/clacky/web/{billing.js → features/billing/view.js} +132 -240
  35. data/lib/clacky/web/features/brand/store.js +110 -0
  36. data/lib/clacky/web/{brand.js → features/brand/view.js} +49 -199
  37. data/lib/clacky/web/features/channels/store.js +103 -0
  38. data/lib/clacky/web/{channels.js → features/channels/view.js} +50 -127
  39. data/lib/clacky/web/features/creator/store.js +81 -0
  40. data/lib/clacky/web/{creator.js → features/creator/view.js} +53 -102
  41. data/lib/clacky/web/features/mcp/store.js +158 -0
  42. data/lib/clacky/web/{mcp.js → features/mcp/view.js} +57 -134
  43. data/lib/clacky/web/features/model-tester/store.js +77 -0
  44. data/lib/clacky/web/features/model-tester/view.js +7 -0
  45. data/lib/clacky/web/features/profile/store.js +170 -0
  46. data/lib/clacky/web/{profile.js → features/profile/view.js} +94 -144
  47. data/lib/clacky/web/features/share/store.js +145 -0
  48. data/lib/clacky/web/{share.js → features/share/view.js} +66 -202
  49. data/lib/clacky/web/features/skills/store.js +303 -0
  50. data/lib/clacky/web/features/skills/view.js +550 -0
  51. data/lib/clacky/web/features/tasks/store.js +135 -0
  52. data/lib/clacky/web/features/tasks/view.js +241 -0
  53. data/lib/clacky/web/features/trash/store.js +242 -0
  54. data/lib/clacky/web/{trash.js → features/trash/view.js} +102 -293
  55. data/lib/clacky/web/features/version/store.js +165 -0
  56. data/lib/clacky/web/features/version/view.js +323 -0
  57. data/lib/clacky/web/features/workspace/store.js +99 -0
  58. data/lib/clacky/web/features/workspace/view.js +305 -0
  59. data/lib/clacky/web/i18n.js +56 -6
  60. data/lib/clacky/web/index.html +117 -58
  61. data/lib/clacky/web/sessions.js +221 -25
  62. data/lib/clacky/web/settings.js +118 -22
  63. data/lib/clacky/web/skills.js +3 -863
  64. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +29 -0
  65. data/lib/clacky.rb +1 -0
  66. metadata +45 -20
  67. data/lib/clacky/web/backup.js +0 -119
  68. data/lib/clacky/web/model-tester.js +0 -66
  69. data/lib/clacky/web/tasks.js +0 -373
  70. data/lib/clacky/web/version.js +0 -449
  71. data/lib/clacky/web/workspace.js +0 -316
  72. /data/lib/clacky/web/{notify.mp3 → assets/notify.mp3} +0 -0
  73. /data/lib/clacky/web/{datepicker.js → components/datepicker.js} +0 -0
  74. /data/lib/clacky/web/{onboard.js → components/onboard.js} +0 -0
  75. /data/lib/clacky/web/{sidebar.js → components/sidebar.js} +0 -0
  76. /data/lib/clacky/web/{marked.min.js → vendor/marked/marked.min.js} +0 -0
@@ -0,0 +1,145 @@
1
+ // ── Share · store — brand source, scorecard state, frequency cap, telemetry
2
+ //
3
+ // Owns the share feature's data: the brand identity (hydrated from
4
+ // /api/brand/status), the live scorecard stats + selected period, the
5
+ // success-count / cooldown frequency cap (localStorage), and the telemetry
6
+ // beacon. It never renders.
7
+ //
8
+ // White-label safety lives here: a branded build NEVER falls back to
9
+ // openclacky.com — the homepage/QR url is simply null when unset.
10
+ //
11
+ // `Share` stays the single public facade.
12
+ //
13
+ // Depends on: Clacky.ext.
14
+ // ───────────────────────────────────────────────────────────────────────────
15
+
16
+ const ShareStore = (() => {
17
+ const DEFAULT_NAME = "OpenClacky";
18
+ const DEFAULT_HOMEPAGE = "https://www.openclacky.com/";
19
+
20
+ const COUNT_KEY = "clacky-share-success-count";
21
+ const COOLDOWN_KEY = "clacky-share-cooldown-until";
22
+ const COOLDOWN_MS = 7 * 24 * 60 * 60 * 1000;
23
+ const PROMPT_AT = [1, 5];
24
+
25
+ let _brand = { name: DEFAULT_NAME, homepageUrl: DEFAULT_HOMEPAGE, logoUrl: null };
26
+ let _scorecard = null;
27
+ let _scorePeriod = null;
28
+
29
+ const _listeners = {};
30
+
31
+ function _on(event, handler) {
32
+ (_listeners[event] ||= []).push(handler);
33
+ return () => {
34
+ const list = _listeners[event];
35
+ const i = list ? list.indexOf(handler) : -1;
36
+ if (i >= 0) list.splice(i, 1);
37
+ };
38
+ }
39
+
40
+ function _emit(event, payload) {
41
+ (_listeners[event] || []).forEach((h) => h(payload));
42
+ if (window.Clacky && Clacky.ext) Clacky.ext.emit(event, payload);
43
+ }
44
+
45
+ const state = {
46
+ get brand() { return _brand; },
47
+ get scorecard() { return _scorecard; },
48
+ get scorePeriod() { return _scorePeriod; },
49
+ set scorePeriod(p) { _scorePeriod = p; },
50
+ shareUrl() { return _brand.homepageUrl; },
51
+
52
+ /** Stats for the selected period, falling back to flat fields. */
53
+ curStats() {
54
+ if (_scorecard && _scorecard.periods && _scorePeriod && _scorecard.periods[_scorePeriod]) {
55
+ return _scorecard.periods[_scorePeriod];
56
+ }
57
+ return _scorecard;
58
+ },
59
+ };
60
+
61
+ async function _hydrateBrand() {
62
+ try {
63
+ const res = await fetch("/api/brand/status");
64
+ if (!res.ok) return;
65
+ const data = await res.json();
66
+ if (data && data.branded) {
67
+ _brand = {
68
+ name: (data.product_name || "").trim() || DEFAULT_NAME,
69
+ homepageUrl: (data.homepage_url || "").trim() || null,
70
+ logoUrl: (data.logo_url || "").trim() || null
71
+ };
72
+ _emit("share:brandChanged", _brand);
73
+ }
74
+ } catch (_e) { /* keep defaults */ }
75
+ }
76
+
77
+ function _successCount() {
78
+ return parseInt(localStorage.getItem(COUNT_KEY) || "0", 10) || 0;
79
+ }
80
+ function _bumpSuccessCount() {
81
+ const n = _successCount() + 1;
82
+ localStorage.setItem(COUNT_KEY, String(n));
83
+ return n;
84
+ }
85
+ function _inCooldown() {
86
+ const until = parseInt(localStorage.getItem(COOLDOWN_KEY) || "0", 10) || 0;
87
+ return Date.now() < until;
88
+ }
89
+ function _startCooldown() {
90
+ localStorage.setItem(COOLDOWN_KEY, String(Date.now() + COOLDOWN_MS));
91
+ }
92
+
93
+ const Share = {
94
+ on: _on,
95
+ state,
96
+ PROMPT_AT,
97
+
98
+ hydrateBrand: _hydrateBrand,
99
+
100
+ /** Enter scorecard mode with live stats; picks the default period. */
101
+ setScorecard(stats) {
102
+ _scorecard = stats || null;
103
+ _scorePeriod = _scorecard
104
+ ? (_scorecard.defaultPeriod && _scorecard.periods && _scorecard.periods[_scorecard.defaultPeriod]
105
+ ? _scorecard.defaultPeriod
106
+ : (_scorecard.periods ? Object.keys(_scorecard.periods)[0] : null))
107
+ : null;
108
+ _emit("share:scorecardChanged", { scorecard: _scorecard, period: _scorePeriod });
109
+ },
110
+
111
+ /** Merge a late-arriving period's stats and notify the view. */
112
+ addScorecardPeriod(key, stats) {
113
+ if (!_scorecard) return false;
114
+ if (!_scorecard.periods) _scorecard.periods = {};
115
+ _scorecard.periods[key] = stats;
116
+ _emit("share:scorecardPeriodAdded", { key, stats });
117
+ return true;
118
+ },
119
+
120
+ clearScorecard() {
121
+ _scorecard = null;
122
+ _scorePeriod = null;
123
+ _emit("share:scorecardChanged", { scorecard: null, period: null });
124
+ },
125
+
126
+ /** Bump success count and decide whether to auto-prompt; starts cooldown. */
127
+ consumeSuccess() {
128
+ const n = _bumpSuccessCount();
129
+ if (_inCooldown()) return { prompt: false };
130
+ if (!PROMPT_AT.includes(n)) return { prompt: false };
131
+ _startCooldown();
132
+ return { prompt: true, count: n };
133
+ },
134
+
135
+ telemetry(event, extra) {
136
+ if (typeof fetch === "undefined") return;
137
+ const body = JSON.stringify({ event, extra: extra || {} });
138
+ fetch("/api/telemetry", { method: "POST", headers: { "Content-Type": "application/json" }, body }).catch(() => {});
139
+ },
140
+ };
141
+
142
+ return Share;
143
+ })();
144
+
145
+ const Share = ShareStore;