mrstack 1.1.0__py3-none-any.whl

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 (42) hide show
  1. mrstack/__init__.py +4 -0
  2. mrstack/_data/config/com.mrstack.claude-telegram.plist +25 -0
  3. mrstack/_data/config/mcp-config.example.json +23 -0
  4. mrstack/_data/config/start-daemon.sh +53 -0
  5. mrstack/_data/config/start.sh +29 -0
  6. mrstack/_data/schedulers/manage-jobs.sh +87 -0
  7. mrstack/_data/schedulers/morning-briefing.sh +29 -0
  8. mrstack/_data/schedulers/register-jobs.py +182 -0
  9. mrstack/_data/schedulers/run-threads-briefing.sh +36 -0
  10. mrstack/_data/schedulers/weekly-review.sh +26 -0
  11. mrstack/_data/templates/DESIGN-GUIDE.md +160 -0
  12. mrstack/_data/templates/alert.md +56 -0
  13. mrstack/_data/templates/evening-summary.md +73 -0
  14. mrstack/_data/templates/jarvis-alert.md +64 -0
  15. mrstack/_data/templates/morning-briefing.md +53 -0
  16. mrstack/_data/templates/weekly-review.md +79 -0
  17. mrstack/_overlay/api/dashboard.py +223 -0
  18. mrstack/_overlay/api/templates/dashboard.html +328 -0
  19. mrstack/_overlay/bot/handlers/callback.py +1432 -0
  20. mrstack/_overlay/bot/handlers/command.py +1541 -0
  21. mrstack/_overlay/bot/utils/keyboards.py +125 -0
  22. mrstack/_overlay/bot/utils/ui_components.py +166 -0
  23. mrstack/_overlay/claude/session.py +341 -0
  24. mrstack/_overlay/jarvis/__init__.py +77 -0
  25. mrstack/_overlay/jarvis/coach.py +122 -0
  26. mrstack/_overlay/jarvis/context_engine.py +463 -0
  27. mrstack/_overlay/jarvis/pattern_learner.py +255 -0
  28. mrstack/_overlay/jarvis/persona.py +84 -0
  29. mrstack/_overlay/jarvis/platform.py +182 -0
  30. mrstack/_overlay/knowledge/__init__.py +6 -0
  31. mrstack/_overlay/knowledge/manager.py +464 -0
  32. mrstack/_overlay/knowledge/memory_index.py +180 -0
  33. mrstack/cli.py +330 -0
  34. mrstack/constants.py +77 -0
  35. mrstack/daemon.py +325 -0
  36. mrstack/patcher.py +169 -0
  37. mrstack/wizard.py +271 -0
  38. mrstack-1.1.0.dist-info/METADATA +640 -0
  39. mrstack-1.1.0.dist-info/RECORD +42 -0
  40. mrstack-1.1.0.dist-info/WHEEL +4 -0
  41. mrstack-1.1.0.dist-info/entry_points.txt +2 -0
  42. mrstack-1.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,328 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Mr.Stack Dashboard</title>
7
+ <script src="https://telegram.org/js/telegram-web-app.js"></script>
8
+ <style>
9
+ :root {
10
+ --bg: var(--tg-theme-bg-color, #1a1a2e);
11
+ --text: var(--tg-theme-text-color, #e0e0e0);
12
+ --hint: var(--tg-theme-hint-color, #888);
13
+ --link: var(--tg-theme-link-color, #64b5f6);
14
+ --btn: var(--tg-theme-button-color, #7c4dff);
15
+ --btn-text: var(--tg-theme-button-text-color, #fff);
16
+ --secondary-bg: var(--tg-theme-secondary-bg-color, #16213e);
17
+ --section: var(--tg-theme-section-bg-color, var(--secondary-bg));
18
+ --card-radius: 12px;
19
+ --gap: 12px;
20
+ }
21
+
22
+ * { margin: 0; padding: 0; box-sizing: border-box; }
23
+
24
+ body {
25
+ font-family: -apple-system, 'SF Pro', 'Segoe UI', Roboto, sans-serif;
26
+ background: var(--bg);
27
+ color: var(--text);
28
+ padding: var(--gap);
29
+ min-height: 100vh;
30
+ }
31
+
32
+ .header {
33
+ text-align: center;
34
+ padding: 16px 0 12px;
35
+ }
36
+ .header h1 { font-size: 20px; font-weight: 600; }
37
+ .header .subtitle { color: var(--hint); font-size: 13px; margin-top: 4px; }
38
+
39
+ .stats-grid {
40
+ display: grid;
41
+ grid-template-columns: repeat(3, 1fr);
42
+ gap: var(--gap);
43
+ margin-bottom: var(--gap);
44
+ }
45
+
46
+ .stat-card {
47
+ background: var(--section);
48
+ border-radius: var(--card-radius);
49
+ padding: 14px;
50
+ text-align: center;
51
+ }
52
+ .stat-card .value {
53
+ font-size: 24px;
54
+ font-weight: 700;
55
+ color: var(--link);
56
+ }
57
+ .stat-card .label {
58
+ font-size: 11px;
59
+ color: var(--hint);
60
+ margin-top: 4px;
61
+ text-transform: uppercase;
62
+ letter-spacing: 0.5px;
63
+ }
64
+
65
+ .section {
66
+ background: var(--section);
67
+ border-radius: var(--card-radius);
68
+ padding: 14px;
69
+ margin-bottom: var(--gap);
70
+ }
71
+ .section-title {
72
+ font-size: 14px;
73
+ font-weight: 600;
74
+ margin-bottom: 10px;
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 6px;
78
+ }
79
+
80
+ .job-item {
81
+ display: flex;
82
+ align-items: center;
83
+ justify-content: space-between;
84
+ padding: 8px 0;
85
+ border-bottom: 1px solid rgba(255,255,255,0.06);
86
+ }
87
+ .job-item:last-child { border-bottom: none; }
88
+ .job-info { flex: 1; }
89
+ .job-name { font-size: 13px; font-weight: 500; }
90
+ .job-cron { font-size: 11px; color: var(--hint); }
91
+ .job-actions { display: flex; gap: 6px; }
92
+
93
+ .btn {
94
+ background: var(--btn);
95
+ color: var(--btn-text);
96
+ border: none;
97
+ border-radius: 8px;
98
+ padding: 6px 12px;
99
+ font-size: 12px;
100
+ cursor: pointer;
101
+ font-weight: 500;
102
+ transition: opacity 0.2s;
103
+ }
104
+ .btn:active { opacity: 0.7; }
105
+ .btn.outline {
106
+ background: transparent;
107
+ border: 1px solid var(--btn);
108
+ color: var(--btn);
109
+ }
110
+ .btn.danger { background: #e53935; }
111
+
112
+ .toggle {
113
+ width: 44px;
114
+ height: 24px;
115
+ border-radius: 12px;
116
+ background: #555;
117
+ position: relative;
118
+ cursor: pointer;
119
+ transition: background 0.3s;
120
+ }
121
+ .toggle.active { background: #4caf50; }
122
+ .toggle::after {
123
+ content: '';
124
+ position: absolute;
125
+ width: 20px;
126
+ height: 20px;
127
+ border-radius: 50%;
128
+ background: #fff;
129
+ top: 2px;
130
+ left: 2px;
131
+ transition: transform 0.3s;
132
+ }
133
+ .toggle.active::after { transform: translateX(20px); }
134
+
135
+ .memory-file {
136
+ font-size: 12px;
137
+ padding: 4px 0;
138
+ color: var(--hint);
139
+ display: flex;
140
+ justify-content: space-between;
141
+ }
142
+
143
+ .activity-item {
144
+ padding: 8px 0;
145
+ border-bottom: 1px solid rgba(255,255,255,0.06);
146
+ }
147
+ .activity-item:last-child { border-bottom: none; }
148
+ .activity-prompt {
149
+ font-size: 13px;
150
+ white-space: nowrap;
151
+ overflow: hidden;
152
+ text-overflow: ellipsis;
153
+ }
154
+ .activity-meta {
155
+ font-size: 11px;
156
+ color: var(--hint);
157
+ margin-top: 2px;
158
+ }
159
+
160
+ .loading {
161
+ text-align: center;
162
+ padding: 20px;
163
+ color: var(--hint);
164
+ }
165
+
166
+ .refresh-bar {
167
+ text-align: center;
168
+ padding: 8px;
169
+ font-size: 11px;
170
+ color: var(--hint);
171
+ }
172
+ </style>
173
+ </head>
174
+ <body>
175
+
176
+ <div class="header">
177
+ <h1>Mr.Stack</h1>
178
+ <div class="subtitle">Dashboard</div>
179
+ </div>
180
+
181
+ <div class="stats-grid">
182
+ <div class="stat-card">
183
+ <div class="value" id="stat-today">-</div>
184
+ <div class="label">Today</div>
185
+ </div>
186
+ <div class="stat-card">
187
+ <div class="value" id="stat-sessions">-</div>
188
+ <div class="label">Sessions</div>
189
+ </div>
190
+ <div class="stat-card">
191
+ <div class="value" id="stat-jobs">-</div>
192
+ <div class="label">Jobs</div>
193
+ </div>
194
+ </div>
195
+
196
+ <div class="section">
197
+ <div class="section-title">Schedule</div>
198
+ <div id="jobs-list"><div class="loading">Loading...</div></div>
199
+ </div>
200
+
201
+ <div class="section">
202
+ <div class="section-title">Memory</div>
203
+ <div id="memory-info"><div class="loading">Loading...</div></div>
204
+ </div>
205
+
206
+ <div class="section">
207
+ <div class="section-title">Recent Activity</div>
208
+ <div id="activity-list"><div class="loading">Loading...</div></div>
209
+ </div>
210
+
211
+ <div class="refresh-bar" id="refresh-bar">Auto-refresh: 30s</div>
212
+
213
+ <script>
214
+ const tg = window.Telegram?.WebApp;
215
+ if (tg) {
216
+ tg.ready();
217
+ tg.expand();
218
+ }
219
+
220
+ const BASE = window.location.origin + '/dashboard';
221
+
222
+ async function fetchJSON(path) {
223
+ try {
224
+ const res = await fetch(BASE + path);
225
+ return await res.json();
226
+ } catch (e) {
227
+ console.error('Fetch error:', path, e);
228
+ return null;
229
+ }
230
+ }
231
+
232
+ async function loadStats() {
233
+ const data = await fetchJSON('/api/stats');
234
+ if (!data || data.error) return;
235
+ document.getElementById('stat-today').textContent = data.today_interactions;
236
+ document.getElementById('stat-sessions').textContent = data.total_sessions;
237
+ document.getElementById('stat-jobs').textContent = data.active_jobs;
238
+ }
239
+
240
+ async function loadJobs() {
241
+ const jobs = await fetchJSON('/api/jobs');
242
+ const container = document.getElementById('jobs-list');
243
+ if (!jobs || jobs.length === 0) {
244
+ container.innerHTML = '<div class="loading">No jobs</div>';
245
+ return;
246
+ }
247
+ container.innerHTML = jobs.map(j => `
248
+ <div class="job-item">
249
+ <div class="job-info">
250
+ <div class="job-name">${j.name}</div>
251
+ <div class="job-cron">${j.cron}</div>
252
+ </div>
253
+ <div class="job-actions">
254
+ <div class="toggle ${j.active ? 'active' : ''}"
255
+ onclick="toggleJob('${j.name}', this)"></div>
256
+ <button class="btn outline" onclick="runJob('${j.name}')">Run</button>
257
+ </div>
258
+ </div>
259
+ `).join('');
260
+ }
261
+
262
+ async function loadMemory() {
263
+ const data = await fetchJSON('/api/memory');
264
+ const container = document.getElementById('memory-info');
265
+ if (!data || data.status !== 'active') {
266
+ container.innerHTML = '<div class="loading">Not configured</div>';
267
+ return;
268
+ }
269
+ let html = `<div class="memory-file"><span>${data.file_count} files</span><span>${data.interaction_count} interactions</span></div>`;
270
+ data.files.slice(0, 8).forEach(f => {
271
+ const size = f.size > 1024 ? (f.size/1024).toFixed(1) + 'KB' : f.size + 'B';
272
+ html += `<div class="memory-file"><span>${f.path}</span><span>${size}</span></div>`;
273
+ });
274
+ container.innerHTML = html;
275
+ }
276
+
277
+ async function loadActivity() {
278
+ const items = await fetchJSON('/api/activity');
279
+ const container = document.getElementById('activity-list');
280
+ if (!items || items.length === 0) {
281
+ container.innerHTML = '<div class="loading">No activity</div>';
282
+ return;
283
+ }
284
+ container.innerHTML = items.map(a => `
285
+ <div class="activity-item">
286
+ <div class="activity-prompt">${escapeHtml(a.prompt)}</div>
287
+ <div class="activity-meta">${a.session_id} &middot; ${formatTime(a.timestamp)}</div>
288
+ </div>
289
+ `).join('');
290
+ }
291
+
292
+ async function toggleJob(name, el) {
293
+ const res = await fetch(BASE + `/api/jobs/${name}/toggle`, {method: 'POST'});
294
+ const data = await res.json();
295
+ if (data.active !== undefined) {
296
+ el.classList.toggle('active', data.active);
297
+ }
298
+ loadStats();
299
+ }
300
+
301
+ async function runJob(name) {
302
+ await fetch(BASE + `/api/jobs/${name}/run`, {method: 'POST'});
303
+ if (tg) tg.showAlert(`${name} triggered`);
304
+ }
305
+
306
+ function escapeHtml(text) {
307
+ const d = document.createElement('div');
308
+ d.textContent = text;
309
+ return d.innerHTML;
310
+ }
311
+
312
+ function formatTime(ts) {
313
+ if (!ts) return '';
314
+ const d = new Date(ts);
315
+ return d.toLocaleTimeString('ko-KR', {hour: '2-digit', minute: '2-digit'});
316
+ }
317
+
318
+ async function refresh() {
319
+ await Promise.all([loadStats(), loadJobs(), loadMemory(), loadActivity()]);
320
+ document.getElementById('refresh-bar').textContent =
321
+ `Updated: ${new Date().toLocaleTimeString('ko-KR')}`;
322
+ }
323
+
324
+ refresh();
325
+ setInterval(refresh, 30000);
326
+ </script>
327
+ </body>
328
+ </html>