@cccarv82/freya 1.0.34 → 1.0.35

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.
package/cli/web-ui.css CHANGED
@@ -2,30 +2,33 @@
2
2
  Keep this file plain CSS to avoid escaping issues in inline template literals. */
3
3
 
4
4
  :root {
5
- --radius: 14px;
6
- --shadow: 0 18px 55px rgba(16, 24, 40, .10);
7
- --shadow2: 0 10px 20px rgba(16, 24, 40, .08);
8
- --ring: 0 0 0 4px rgba(59, 130, 246, .18);
9
-
10
- --bg: #f3f6fb;
11
- --paper: #fff;
12
- --paper2: rgba(255,255,255,.78);
13
- --line: rgba(15, 23, 42, .10);
14
- --line2: rgba(15, 23, 42, .18);
15
- --text: #0f172a;
16
- --muted: rgba(15, 23, 42, .72);
17
- --faint: rgba(15, 23, 42, .55);
5
+ --radius: 16px;
6
+ --radius2: 12px;
7
+ --shadow: 0 20px 60px rgba(16, 24, 40, .12);
8
+ --shadow2: 0 10px 22px rgba(16, 24, 40, .10);
9
+ --ring: 0 0 0 4px rgba(37, 99, 235, .18);
10
+
11
+ /* Warm cream palette (light-first) */
12
+ --bg: #f7f0e6;
13
+ --paper: #fffaf2;
14
+ --paper2: rgba(255, 250, 242, .78);
15
+ --line: rgba(30, 41, 59, .10);
16
+ --line2: rgba(30, 41, 59, .18);
17
+ --text: #111827;
18
+ --muted: rgba(17, 24, 39, .74);
19
+ --faint: rgba(17, 24, 39, .56);
20
+
18
21
  --accent: #f97316;
19
22
  --primary: #2563eb;
20
- --chip: rgba(37, 99, 235, .09);
21
- --chip2: rgba(249, 115, 22, .12);
23
+ --chip: rgba(37, 99, 235, .10);
24
+ --chip2: rgba(249, 115, 22, .14);
22
25
 
23
26
  --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
24
27
  --sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
25
28
  }
26
29
 
27
30
  [data-theme="dark"] {
28
- --bg: #0b1220;
31
+ --bg: #0b111c;
29
32
  --paper: rgba(17, 24, 39, .92);
30
33
  --paper2: rgba(17, 24, 39, .78);
31
34
  --line: rgba(148, 163, 184, .16);
@@ -42,35 +45,44 @@
42
45
  body {
43
46
  margin: 0;
44
47
  font-family: var(--sans);
45
- background: radial-gradient(900px 400px at 20% 0%, rgba(37,99,235,.14), transparent 60%),
46
- radial-gradient(900px 450px at 90% 10%, rgba(249,115,22,.12), transparent 60%),
47
- var(--bg);
48
+ background:
49
+ radial-gradient(900px 400px at 12% 0%, rgba(249,115,22,.12), transparent 60%),
50
+ radial-gradient(900px 450px at 90% 8%, rgba(37,99,235,.14), transparent 60%),
51
+ var(--bg);
48
52
  color: var(--text);
49
53
  }
50
54
 
51
- .app { padding: 20px; }
55
+ .app { padding: 18px; }
52
56
 
53
57
  .frame {
54
- max-width: 1200px;
58
+ max-width: 1400px;
55
59
  margin: 0 auto;
56
60
  border-radius: 22px;
57
61
  overflow: hidden;
58
62
  box-shadow: var(--shadow);
59
63
  border: 1px solid var(--line);
60
- background: rgba(255,255,255,.35);
64
+ background: rgba(255, 250, 242, .35);
61
65
  }
62
66
 
63
67
  .shell {
64
68
  display: grid;
65
- grid-template-columns: 290px 1fr;
69
+ grid-template-columns: 290px minmax(520px, 1fr) 380px;
70
+ min-height: calc(100vh - 36px);
66
71
  }
67
72
 
68
- @media (max-width: 980px) {
73
+ @media (max-width: 1200px) {
74
+ .shell { grid-template-columns: 280px 1fr; }
75
+ .chatPane { display: none; }
76
+ }
77
+
78
+ @media (max-width: 860px) {
69
79
  .shell { grid-template-columns: 1fr; }
80
+ .sidebar { border-right: none; border-bottom: 1px solid var(--line); }
70
81
  }
71
82
 
83
+ /* LEFT */
72
84
  .sidebar {
73
- background: linear-gradient(180deg, rgba(255,255,255,.75), rgba(255,255,255,.45));
85
+ background: linear-gradient(180deg, rgba(255,250,242,.85), rgba(255,250,242,.60));
74
86
  border-right: 1px solid var(--line);
75
87
  padding: 14px;
76
88
  }
@@ -88,7 +100,7 @@ body {
88
100
 
89
101
  .sideHeader .logo {
90
102
  font-weight: 900;
91
- letter-spacing: .08em;
103
+ letter-spacing: .10em;
92
104
  font-size: 12px;
93
105
  color: var(--muted);
94
106
  }
@@ -119,39 +131,41 @@ body {
119
131
  }
120
132
 
121
133
  .sideGroup { margin-top: 10px; padding: 10px 6px; border-top: 1px solid var(--line); }
122
- .sideTitle { font-weight: 800; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
134
+ .sideTitle { font-weight: 800; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
123
135
 
124
- .btn {
136
+ .cardsMini { display: grid; gap: 8px; }
137
+ .miniCard {
138
+ width: 100%;
139
+ text-align: left;
125
140
  border: 1px solid var(--line);
126
- border-radius: 12px;
141
+ border-radius: 14px;
127
142
  background: var(--paper2);
128
143
  padding: 10px 12px;
129
144
  cursor: pointer;
145
+ display: flex;
146
+ align-items: center;
147
+ gap: 10px;
130
148
  font-weight: 800;
131
149
  color: var(--muted);
132
150
  }
151
+ .miniCard:hover { border-color: var(--line2); box-shadow: var(--shadow2); }
133
152
 
134
- .btn:hover { border-color: var(--line2); box-shadow: var(--shadow2); }
135
- .btn.small { padding: 7px 10px; border-radius: 10px; font-size: 12px; }
136
- .btn.primary { background: rgba(37,99,235,.10); border-color: rgba(37,99,235,.30); color: rgba(37,99,235,.95); }
137
-
138
- .sideBtn { width: 100%; text-align: left; margin-top: 8px; }
139
-
140
- .k {
141
- display: inline-block;
142
- padding: 2px 6px;
153
+ .miniIcon {
154
+ width: 26px;
155
+ height: 26px;
156
+ border-radius: 10px;
157
+ display: grid;
158
+ place-items: center;
159
+ background: var(--chip);
143
160
  border: 1px solid var(--line);
144
- border-radius: 8px;
145
- background: rgba(255,255,255,.65);
146
- font-family: var(--mono);
147
- font-size: 12px;
148
- color: var(--muted);
161
+ color: var(--primary);
162
+ font-weight: 900;
149
163
  }
164
+ .miniIcon.warn { background: var(--chip2); color: var(--accent); }
150
165
 
151
- [data-theme="dark"] .k { background: rgba(0,0,0,.18); }
152
-
153
- .main { background: rgba(255,255,255,.58); }
154
- [data-theme="dark"] .main { background: rgba(10, 14, 26, .55); }
166
+ /* CENTER */
167
+ .center { background: rgba(255, 250, 242, .58); }
168
+ [data-theme="dark"] .center { background: rgba(10, 14, 26, .55); }
155
169
 
156
170
  .topbar {
157
171
  display: flex;
@@ -159,67 +173,177 @@ body {
159
173
  align-items: center;
160
174
  padding: 14px 16px;
161
175
  border-bottom: 1px solid var(--line);
162
- background: linear-gradient(90deg, rgba(255,255,255,.65), rgba(255,255,255,.35));
176
+ background: linear-gradient(90deg, rgba(255,250,242,.75), rgba(255,250,242,.45));
163
177
  }
164
178
 
165
179
  [data-theme="dark"] .topbar { background: linear-gradient(90deg, rgba(17,24,39,.88), rgba(17,24,39,.55)); }
166
180
 
167
181
  .brand { display: flex; align-items: center; gap: 10px; font-weight: 900; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
168
- .spark { width: 10px; height: 10px; border-radius: 4px; background: linear-gradient(135deg, var(--accent), var(--primary)); box-shadow: 0 0 0 6px rgba(249,115,22,.12); }
182
+ .spark { width: 10px; height: 10px; border-radius: 4px; background: linear-gradient(135deg, var(--accent), var(--primary)); box-shadow: 0 0 0 6px rgba(249,115,22,.10); }
169
183
  .actions { display: flex; align-items: center; gap: 10px; }
170
- .chip { font-family: var(--mono); font-size: 12px; padding: 7px 10px; border-radius: 999px; border: 1px solid var(--line); background: rgba(255,255,255,.55); color: var(--faint); }
184
+ .chip { font-family: var(--mono); font-size: 12px; padding: 7px 10px; border-radius: 999px; border: 1px solid var(--line); background: rgba(255,250,242,.65); color: var(--faint); }
171
185
  [data-theme="dark"] .chip { background: rgba(0,0,0,.20); }
172
- .toggle { border: 1px solid var(--line); border-radius: 999px; background: var(--paper2); padding: 7px 10px; cursor: pointer; color: var(--muted); font-weight: 700; font-size: 12px; }
186
+ .toggle { border: 1px solid var(--line); border-radius: 999px; background: var(--paper2); padding: 7px 10px; cursor: pointer; color: var(--muted); font-weight: 800; font-size: 12px; }
173
187
 
174
- .section { padding: 16px; }
188
+ .centerBody { padding: 16px; }
189
+ .centerHead { display: flex; justify-content: space-between; align-items: flex-end; gap: 18px; margin-bottom: 14px; }
190
+ .statusLine { display:flex; align-items:center; justify-content:flex-end; gap: 12px; }
175
191
 
176
192
  h1 { margin: 0; font-size: 22px; letter-spacing: -.02em; }
177
193
  .subtitle { margin-top: 6px; color: var(--muted); font-size: 13px; line-height: 1.4; max-width: 860px; }
178
194
 
179
- .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 14px; }
180
- @media (max-width: 1100px) { .cards { grid-template-columns: repeat(2, 1fr);} }
181
- @media (max-width: 620px) { .cards { grid-template-columns: 1fr;} }
182
-
183
- .card { border: 1px solid var(--line); background: var(--paper2); border-radius: 14px; padding: 12px; display: grid; gap: 6px; cursor: pointer; transition: transform .10s ease, border-color .16s ease, box-shadow .16s ease; box-shadow: 0 1px 0 rgba(16,24,40,.04); }
184
- .card:hover { transform: translateY(-1px); border-color: var(--line2); box-shadow: 0 10px 22px rgba(16,24,40,.10); }
185
-
186
- .icon { width: 34px; height: 34px; border-radius: 12px; display: grid; place-items: center; background: var(--chip); border: 1px solid var(--line); color: var(--primary); font-weight: 900; }
187
- .icon.orange { background: var(--chip2); color: var(--accent); }
188
-
189
- .title { font-weight: 800; font-size: 13px; }
190
- .desc { color: var(--muted); font-size: 12px; line-height: 1.35; }
191
-
192
- .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; }
193
- @media (max-width: 980px) { .grid2 { grid-template-columns: 1fr; } }
195
+ .midGrid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
196
+ .midSpan { grid-column: 1 / -1; }
197
+ @media (max-width: 980px) {
198
+ .midGrid { grid-template-columns: 1fr; }
199
+ .midSpan { grid-column: auto; }
200
+ }
194
201
 
195
- .panel { border: 1px solid var(--line); background: var(--paper); border-radius: 14px; overflow: hidden; }
202
+ .panel { border: 1px solid var(--line); background: var(--paper); border-radius: var(--radius); overflow: hidden; box-shadow: 0 1px 0 rgba(16,24,40,.04); }
196
203
  .panelHead { display: flex; align-items: center; justify-content: space-between; padding: 12px 12px; border-bottom: 1px solid var(--line); background: linear-gradient(180deg, var(--paper2), var(--paper)); }
197
204
  .panelHead b { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
198
205
  .panelBody { padding: 12px; }
199
206
 
207
+ /* DEV DRAWER */
208
+ .devDrawer { margin-top: 14px; border: 1px dashed var(--line2); border-radius: var(--radius); background: rgba(255,250,242,.42); }
209
+ [data-theme="dark"] .devDrawer { background: rgba(0,0,0,.18); }
210
+ .devDrawer > summary {
211
+ cursor: pointer;
212
+ list-style: none;
213
+ padding: 12px 14px;
214
+ font-weight: 900;
215
+ color: var(--muted);
216
+ }
217
+ .devDrawer > summary::-webkit-details-marker { display:none; }
218
+ .devBody { padding: 0 14px 14px; }
219
+ .devGrid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
220
+ @media (max-width: 1100px) { .devGrid { grid-template-columns: 1fr; } }
221
+
222
+ /* FORMS */
200
223
  label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
201
224
  input { width: 100%; padding: 11px 12px; border-radius: 12px; border: 1px solid var(--line); background: rgba(255,255,255,.72); color: var(--text); outline: none; }
202
225
  [data-theme="dark"] input { background: rgba(0,0,0,.16); }
203
226
  input:focus { box-shadow: var(--ring); border-color: rgba(37,99,235,.35); }
227
+ textarea {
228
+ width: 100%;
229
+ padding: 10px 12px;
230
+ border-radius: 12px;
231
+ border: 1px solid var(--line);
232
+ background: rgba(255,255,255,.72);
233
+ color: var(--text);
234
+ outline: none;
235
+ resize: vertical;
236
+ }
237
+ [data-theme="dark"] textarea { background: rgba(0,0,0,.16); }
238
+ textarea:focus { box-shadow: var(--ring); border-color: rgba(37,99,235,.35); }
204
239
 
205
240
  .row { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; }
206
241
  .stack { display: flex; gap: 10px; flex-wrap: wrap; }
207
242
  .help { font-size: 12px; color: var(--faint); line-height: 1.4; }
243
+ .small { font-size: 12px; color: var(--faint); }
208
244
 
209
- .log { padding: 12px; border: 1px solid var(--line); border-radius: 14px; background: rgba(255,255,255,.65); font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: pre-wrap; word-break: break-word; max-height: 340px; overflow: auto; }
245
+ /* BUTTONS */
246
+ .btn {
247
+ border: 1px solid var(--line);
248
+ border-radius: 12px;
249
+ background: var(--paper2);
250
+ padding: 10px 12px;
251
+ cursor: pointer;
252
+ font-weight: 900;
253
+ color: var(--muted);
254
+ }
255
+
256
+ .btn:hover { border-color: var(--line2); box-shadow: var(--shadow2); }
257
+ .btn.small { padding: 7px 10px; border-radius: 10px; font-size: 12px; }
258
+ .btn.primary { background: rgba(37,99,235,.12); border-color: rgba(37,99,235,.34); color: rgba(37,99,235,.95); }
259
+ .sideBtn { width: 100%; text-align: left; margin-top: 8px; }
260
+
261
+ .k {
262
+ display: inline-block;
263
+ padding: 2px 6px;
264
+ border: 1px solid var(--line);
265
+ border-radius: 8px;
266
+ background: rgba(255,250,242,.75);
267
+ font-family: var(--mono);
268
+ font-size: 12px;
269
+ color: var(--muted);
270
+ }
271
+ [data-theme="dark"] .k { background: rgba(0,0,0,.18); }
272
+
273
+ /* REPORT/TODAY ITEMS + PREVIEW */
274
+ .log { padding: 12px; border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,250,242,.65); font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: pre-wrap; word-break: break-word; max-height: 360px; overflow: auto; }
210
275
  [data-theme="dark"] .log { background: rgba(0,0,0,.18); }
211
276
 
212
277
  .rep { width: 100%; text-align: left; border: 1px solid var(--line); border-radius: 12px; background: var(--paper2); padding: 10px 12px; cursor: pointer; font-family: var(--mono); font-size: 12px; color: var(--muted); }
213
278
  .rep:hover { border-color: var(--line2); box-shadow: 0 10px 22px rgba(16,24,40,.10); }
214
279
  .repActive { border-color: rgba(59,130,246,.55); box-shadow: 0 0 0 4px rgba(59,130,246,.12); }
215
280
 
281
+ /* Markdown */
216
282
  .md-h1{ font-size: 20px; margin: 10px 0 6px; }
217
283
  .md-h2{ font-size: 16px; margin: 10px 0 6px; }
218
284
  .md-h3{ font-size: 14px; margin: 10px 0 6px; }
219
285
  .md-p{ margin: 6px 0; color: var(--muted); line-height: 1.5; }
220
286
  .md-ul{ margin: 6px 0 6px 18px; color: var(--muted); }
221
- .md-inline{ font-family: var(--mono); font-size: 12px; padding: 2px 6px; border: 1px solid var(--line); border-radius: 8px; background: rgba(255,255,255,.55); }
287
+ .md-inline{ font-family: var(--mono); font-size: 12px; padding: 2px 6px; border: 1px solid var(--line); border-radius: 8px; background: rgba(255,250,242,.60); }
222
288
  [data-theme="dark"] .md-inline{ background: rgba(0,0,0,.18); }
223
- .md-code{ background: rgba(0,0,0,.05); border: 1px solid var(--line); border-radius: 14px; padding: 12px; overflow:auto; }
289
+ .md-code{ background: rgba(0,0,0,.05); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px; overflow:auto; }
224
290
  [data-theme="dark"] .md-code{ background: rgba(0,0,0,.22); }
225
291
  .md-sp{ height: 10px; }
292
+
293
+ /* RIGHT: CHAT */
294
+ .chatPane {
295
+ border-left: 1px solid var(--line);
296
+ background: linear-gradient(180deg, rgba(255,250,242,.82), rgba(255,250,242,.60));
297
+ display: grid;
298
+ grid-template-rows: auto 1fr auto;
299
+ }
300
+ [data-theme="dark"] .chatPane {
301
+ background: linear-gradient(180deg, rgba(17,24,39,.92), rgba(17,24,39,.68));
302
+ }
303
+
304
+ .chatHead { padding: 14px; border-bottom: 1px solid var(--line); }
305
+ .chatTitle { font-weight: 950; letter-spacing: -.01em; }
306
+ .chatSub { margin-top: 2px; font-size: 12px; color: var(--faint); }
307
+
308
+ .chatThread {
309
+ padding: 14px;
310
+ overflow: auto;
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: 10px;
314
+ }
315
+
316
+ .bubble {
317
+ max-width: 92%;
318
+ border-radius: 18px;
319
+ padding: 10px 12px;
320
+ border: 1px solid var(--line);
321
+ box-shadow: 0 1px 0 rgba(16,24,40,.03);
322
+ }
323
+
324
+ .bubble .bubbleMeta { font-size: 11px; font-weight: 900; color: var(--faint); margin-bottom: 6px; }
325
+ .bubble .bubbleBody { font-size: 13px; line-height: 1.45; color: var(--text); }
326
+
327
+ .bubble.user {
328
+ align-self: flex-end;
329
+ background: rgba(37,99,235,.10);
330
+ border-color: rgba(37,99,235,.22);
331
+ }
332
+
333
+ .bubble.assistant {
334
+ align-self: flex-start;
335
+ background: rgba(255,250,242,.82);
336
+ }
337
+ [data-theme="dark"] .bubble.assistant { background: rgba(0,0,0,.18); }
338
+
339
+ .chatComposer {
340
+ padding: 12px 14px 14px;
341
+ border-top: 1px solid var(--line);
342
+ background: rgba(255,250,242,.55);
343
+ }
344
+ [data-theme="dark"] .chatComposer { background: rgba(0,0,0,.12); }
345
+
346
+ .composerActions { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
347
+ .composerToggles { margin-top: 10px; display: grid; gap: 6px; }
348
+ .toggleRow { display:flex; align-items:center; gap:10px; user-select:none; font-size: 12px; color: var(--muted); }
349
+ .statusFooter { margin-top: 10px; display:flex; justify-content:flex-end; }
package/cli/web-ui.js CHANGED
@@ -114,6 +114,37 @@
114
114
  return html;
115
115
  }
116
116
 
117
+ function chatAppend(role, text, opts = {}) {
118
+ const thread = $('chatThread');
119
+ if (!thread) return;
120
+
121
+ const bubble = document.createElement('div');
122
+ bubble.className = 'bubble ' + (role === 'user' ? 'user' : 'assistant');
123
+
124
+ const meta = document.createElement('div');
125
+ meta.className = 'bubbleMeta';
126
+ meta.textContent = role === 'user' ? 'You' : 'FREYA';
127
+
128
+ const body = document.createElement('div');
129
+ body.className = 'bubbleBody';
130
+
131
+ const raw = String(text || '');
132
+ if (opts.markdown) {
133
+ body.innerHTML = renderMarkdown(raw);
134
+ } else {
135
+ body.innerHTML = escapeHtml(raw).replace(/\n/g, '<br>');
136
+ }
137
+
138
+ bubble.appendChild(meta);
139
+ bubble.appendChild(body);
140
+ thread.appendChild(bubble);
141
+
142
+ // keep newest in view
143
+ try {
144
+ thread.scrollTop = thread.scrollHeight;
145
+ } catch {}
146
+ }
147
+
117
148
  function setOut(text) {
118
149
  state.lastText = text || '';
119
150
  const el = $('reportPreview');
@@ -717,6 +748,8 @@
717
748
  return;
718
749
  }
719
750
 
751
+ chatAppend('user', text);
752
+
720
753
  setPill('run', 'saving…');
721
754
  await api('/api/inbox/add', { dir: dirOrDefault(), text });
722
755
 
@@ -727,7 +760,9 @@
727
760
 
728
761
  // Show plan output in Preview panel
729
762
  const header = r.ok === false ? '## Agent Plan (planner unavailable)\n\n' : '## Agent Plan (draft)\n\n';
730
- setOut(header + (r.plan || ''));
763
+ const planOut = header + (r.plan || '');
764
+ setOut(planOut);
765
+ chatAppend('assistant', planOut, { markdown: true });
731
766
  ta.value = '';
732
767
 
733
768
  if (r.ok === false) {
@@ -807,6 +842,7 @@
807
842
  }
808
843
 
809
844
  setOut(msg);
845
+ chatAppend('assistant', msg, { markdown: true });
810
846
  setPill('ok', 'applied');
811
847
  setTimeout(() => setPill('ok', 'idle'), 800);
812
848
  } catch (e) {
@@ -821,6 +857,18 @@
821
857
  $('chipPort').textContent = location.host;
822
858
  loadLocal();
823
859
 
860
+ // Developer drawer (persist open/close)
861
+ try {
862
+ const d = $('devDrawer');
863
+ if (d) {
864
+ const open = localStorage.getItem('freya.devDrawer') === '1';
865
+ if (open) d.open = true;
866
+ d.addEventListener('toggle', () => {
867
+ try { localStorage.setItem('freya.devDrawer', d.open ? '1' : '0'); } catch {}
868
+ });
869
+ }
870
+ } catch {}
871
+
824
872
  // Load persisted settings from the workspace + bootstrap (auto-init + auto-health)
825
873
  (async () => {
826
874
  let defaults = null;
package/cli/web.js CHANGED
@@ -677,6 +677,7 @@ function buildHtml(safeDefault) {
677
677
  <div class="frame">
678
678
  <div class="shell">
679
679
 
680
+ <!-- LEFT: Workspaces / Topics -->
680
681
  <aside class="sidebar">
681
682
  <div class="sideHeader">
682
683
  <div class="logo">FREYA</div>
@@ -686,47 +687,41 @@ function buildHtml(safeDefault) {
686
687
  <div class="sidePath" id="sidePath">./freya</div>
687
688
 
688
689
  <div class="sideGroup">
689
- <div class="sideTitle">Workspace</div>
690
- <button class="btn sideBtn" onclick="pickDir()">Select workspace…</button>
691
- <button class="btn sideBtn" onclick="doUpdate()">Sync workspace</button>
692
- <button class="btn sideBtn" onclick="doMigrate()">Migrate data</button>
690
+ <div class="sideTitle">Workspaces</div>
691
+ <div class="row" style="grid-template-columns: 1fr auto">
692
+ <input id="dir" placeholder="./freya" />
693
+ <button class="btn small" onclick="pickDir()">Browse</button>
694
+ </div>
695
+ <div class="stack" style="margin-top:10px">
696
+ <button class="btn sideBtn" onclick="doUpdate()">Sync workspace</button>
697
+ <button class="btn sideBtn" onclick="doMigrate()">Migrate data</button>
698
+ </div>
693
699
  <div style="height:10px"></div>
694
700
  <div class="help"><b>Sync workspace</b>: atualiza scripts/templates/agents na pasta <code>freya</code> sem sobrescrever <code>data/</code> e <code>logs/</code>.</div>
695
701
  <div class="help"><b>Migrate data</b>: ajusta formatos/schemaVersion quando uma versão nova exige.</div>
696
702
  </div>
697
703
 
698
704
  <div class="sideGroup">
699
- <div class="sideTitle">Atalhos</div>
700
- <div class="help"><span class="k">--dev</span> cria dados de exemplo para testar rápido.</div>
701
- <div style="height:8px"></div>
702
- <div class="help"><span class="k">--port</span> muda a porta (default 3872).</div>
705
+ <div class="sideTitle">Quick reports</div>
706
+ <div class="cardsMini">
707
+ <button class="miniCard" type="button" onclick="runReport('status')"><span class="miniIcon">E</span><span>Executive</span></button>
708
+ <button class="miniCard" type="button" onclick="runReport('sm-weekly')"><span class="miniIcon">S</span><span>SM weekly</span></button>
709
+ <button class="miniCard" type="button" onclick="runReport('blockers')"><span class="miniIcon warn">B</span><span>Blockers</span></button>
710
+ <button class="miniCard" type="button" onclick="runReport('daily')"><span class="miniIcon">D</span><span>Daily</span></button>
711
+ </div>
712
+ <div class="help" style="margin-top:8px">Clique para gerar e atualizar o preview/publicação.</div>
703
713
  </div>
704
714
 
705
715
  <div class="sideGroup">
706
- <div class="sideTitle">Daily Input</div>
707
- <textarea id="inboxText" rows="6" placeholder="Cole aqui updates do dia (status, blockers, decisões, ideias)…" style="width:100%; padding:10px 12px; border-radius:12px; border:1px solid var(--line); background: rgba(255,255,255,.72); color: var(--text); outline:none; resize: vertical;"></textarea>
708
- <div style="height:10px"></div>
709
- <div class="stack">
710
- <button class="btn primary sideBtn" onclick="saveAndPlan()">Save + Process (Agents)</button>
711
- <button class="btn sideBtn" onclick="runSuggestedReports()">Run suggested reports</button>
712
- </div>
713
-
714
- <div style="height:10px"></div>
715
- <label style="display:flex; align-items:center; gap:10px; user-select:none">
716
- <input id="autoApply" type="checkbox" checked style="width:auto" onchange="toggleAutoApply()" />
717
- Auto-apply plan
718
- </label>
719
- <div class="help">Quando ligado, o Save+Process já aplica tasks/blockers automaticamente.</div>
720
-
721
- <label style="display:flex; align-items:center; gap:10px; user-select:none; margin-top:10px">
722
- <input id="autoRunReports" type="checkbox" style="width:auto" onchange="toggleAutoRunReports()" />
723
- Auto-run suggested reports
724
- </label>
725
- <div class="help">Quando ligado, após aplicar o plano, ele também roda os reports sugeridos automaticamente.</div>
716
+ <div class="sideTitle">Tips</div>
717
+ <div class="help"><span class="k">--dev</span> cria dados de exemplo para testar rápido.</div>
718
+ <div style="height:8px"></div>
719
+ <div class="help"><span class="k">--port</span> muda a porta (default 3872).</div>
726
720
  </div>
727
721
  </aside>
728
722
 
729
- <main class="main">
723
+ <!-- MIDDLE: Reports / Today -->
724
+ <main class="center">
730
725
  <div class="topbar">
731
726
  <div class="brand"><span class="spark"></span> Local-first status assistant</div>
732
727
  <div class="actions">
@@ -735,83 +730,35 @@ function buildHtml(safeDefault) {
735
730
  </div>
736
731
  </div>
737
732
 
738
- <div class="section">
739
- <h1>Morning, how can I help?</h1>
740
- <div class="subtitle">Selecione uma workspace e gere relatórios (Executive / SM / Blockers / Daily). Você pode publicar no Discord/Teams com 1 clique.</div>
741
-
742
- <div class="cards">
743
- <div class="card" onclick="runReport('status')">
744
- <div class="icon">E</div>
745
- <div class="title">Executive report</div>
746
- <div class="desc">Status pronto para stakeholders (entregas, projetos, blockers).</div>
747
- </div>
748
- <div class="card" onclick="runReport('sm-weekly')">
749
- <div class="icon">S</div>
750
- <div class="title">SM weekly</div>
751
- <div class="desc">Resumo, wins, riscos e foco da próxima semana.</div>
733
+ <div class="centerBody">
734
+ <div class="centerHead">
735
+ <div>
736
+ <h1 style="margin:0">Your day at a glance</h1>
737
+ <div class="subtitle">Workspaces, Today (tasks/blockers), reports & preview. Use the right panel as a chat-style capture.</div>
752
738
  </div>
753
- <div class="card" onclick="runReport('blockers')">
754
- <div class="icon orange">B</div>
755
- <div class="title">Blockers</div>
756
- <div class="desc">Lista priorizada por severidade + idade (pra destravar rápido).</div>
757
- </div>
758
- <div class="card" onclick="runReport('daily')">
759
- <div class="icon">D</div>
760
- <div class="title">Daily</div>
761
- <div class="desc">Ontem / Hoje / Bloqueios — pronto pra standup.</div>
739
+ <div class="statusLine">
740
+ <span class="small" id="last"></span>
762
741
  </div>
763
742
  </div>
764
743
 
765
- <div class="grid2">
766
- <div class="panel">
767
- <div class="panelHead"><b>Workspace & publish settings</b><span class="small" id="last"></span></div>
768
- <div class="panelBody">
769
- <label>Workspace dir</label>
770
- <div class="row">
771
- <input id="dir" placeholder="./freya" />
772
- <button class="btn small" onclick="pickDir()">Browse</button>
773
- </div>
774
- <div class="help">Escolha a pasta que contém <code>data/</code>, <code>logs/</code> e <code>scripts/</code>.</div>
775
-
776
- <div style="height:12px"></div>
777
-
778
- <label>Discord webhook URL</label>
779
- <input id="discord" placeholder="https://discord.com/api/webhooks/..." />
780
- <div style="height:10px"></div>
781
-
782
- <label>Teams webhook URL</label>
783
- <input id="teams" placeholder="https://..." />
784
- <div class="help">Os webhooks ficam salvos na workspace em <code>data/settings/settings.json</code>.</div>
785
-
786
- <div style="height:10px"></div>
787
- <label style="display:flex; align-items:center; gap:10px; user-select:none; margin: 6px 0 12px 0">
788
- <input id="prettyPublish" type="checkbox" checked style="width:auto" onchange="togglePrettyPublish()" />
789
- Pretty publish (cards/embeds)
790
- </label>
791
-
744
+ <div class="midGrid">
745
+ <section class="panel">
746
+ <div class="panelHead">
747
+ <b>Today</b>
792
748
  <div class="stack">
793
- <button class="btn" onclick="saveSettings()">Save settings</button>
794
- <button class="btn" onclick="publish('discord')">Publish selected → Discord</button>
795
- <button class="btn" onclick="publish('teams')">Publish selected → Teams</button>
796
- </div>
797
-
798
- <div style="height:14px"></div>
799
-
800
- <div class="help"><b>Dica:</b> clique em um relatório em <i>Reports</i> para ver o preview e habilitar publish/copy.</div>
801
-
802
- <div style="height:14px"></div>
803
- <label>Project slug rules</label>
804
- <textarea id="slugRules" rows="8" placeholder="{ \"rules\": [ { \"contains\": \"fideliza\", \"slug\": \"vivo/fidelizacao\" } ] }" style="width:100%; padding:10px 12px; border-radius:12px; border:1px solid var(--line); background: rgba(255,255,255,.72); color: var(--text); outline:none; resize: vertical; font-family: var(--mono);"></textarea>
805
- <div class="help">Regras usadas pra inferir <code>projectSlug</code>. Formato JSON (objeto com <code>rules</code>). Editável no estilo Obsidian-friendly.</div>
806
- <div class="stack" style="margin-top:10px">
807
- <button class="btn" onclick="reloadSlugRules()">Reload rules</button>
808
- <button class="btn" onclick="saveSlugRules()">Save rules</button>
809
- <button class="btn" onclick="exportObsidian()">Export Obsidian notes</button>
749
+ <button class="btn small" onclick="refreshToday()">Refresh</button>
810
750
  </div>
811
751
  </div>
812
- </div>
752
+ <div class="panelBody">
753
+ <div class="small" style="margin-bottom:8px; opacity:.8">Do Now</div>
754
+ <div id="tasksList" style="display:grid; gap:8px"></div>
755
+ <div style="height:12px"></div>
756
+ <div class="small" style="margin-bottom:8px; opacity:.8">Open blockers</div>
757
+ <div id="blockersList" style="display:grid; gap:8px"></div>
758
+ </div>
759
+ </section>
813
760
 
814
- <div class="panel">
761
+ <section class="panel">
815
762
  <div class="panelHead">
816
763
  <b>Reports</b>
817
764
  <div class="stack">
@@ -823,25 +770,9 @@ function buildHtml(safeDefault) {
823
770
  <div id="reportsList" style="display:grid; gap:8px"></div>
824
771
  <div class="help">Últimos relatórios em <code>docs/reports</code>. Clique para abrir preview.</div>
825
772
  </div>
826
- </div>
773
+ </section>
827
774
 
828
- <div class="panel">
829
- <div class="panelHead">
830
- <b>Today</b>
831
- <div class="stack">
832
- <button class="btn small" onclick="refreshToday()">Refresh</button>
833
- </div>
834
- </div>
835
- <div class="panelBody">
836
- <div class="small" style="margin-bottom:8px; opacity:.8">Do Now</div>
837
- <div id="tasksList" style="display:grid; gap:8px"></div>
838
- <div style="height:12px"></div>
839
- <div class="small" style="margin-bottom:8px; opacity:.8">Open blockers</div>
840
- <div id="blockersList" style="display:grid; gap:8px"></div>
841
- </div>
842
- </div>
843
-
844
- <div class="panel">
775
+ <section class="panel midSpan">
845
776
  <div class="panelHead">
846
777
  <b>Preview</b>
847
778
  <div class="stack">
@@ -857,11 +788,106 @@ function buildHtml(safeDefault) {
857
788
  <div id="reportPreview" class="log md" style="font-family: var(--sans);"></div>
858
789
  <div class="help">O preview renderiza Markdown básico (headers, listas, code). O botão Copy copia o conteúdo completo.</div>
859
790
  </div>
860
- </div>
791
+ </section>
861
792
  </div>
793
+
794
+ <details class="devDrawer" id="devDrawer">
795
+ <summary>Developer</summary>
796
+ <div class="devBody">
797
+ <div class="devGrid">
798
+ <div class="panel">
799
+ <div class="panelHead"><b>Publish settings</b></div>
800
+ <div class="panelBody">
801
+ <label>Discord webhook URL</label>
802
+ <input id="discord" placeholder="https://discord.com/api/webhooks/..." />
803
+ <div style="height:10px"></div>
804
+
805
+ <label>Teams webhook URL</label>
806
+ <input id="teams" placeholder="https://..." />
807
+ <div class="help">Os webhooks ficam salvos na workspace em <code>data/settings/settings.json</code>.</div>
808
+
809
+ <div style="height:10px"></div>
810
+ <label style="display:flex; align-items:center; gap:10px; user-select:none; margin: 6px 0 12px 0">
811
+ <input id="prettyPublish" type="checkbox" checked style="width:auto" onchange="togglePrettyPublish()" />
812
+ Pretty publish (cards/embeds)
813
+ </label>
814
+
815
+ <div class="stack">
816
+ <button class="btn" onclick="saveSettings()">Save settings</button>
817
+ <button class="btn" onclick="publish('discord')">Publish selected → Discord</button>
818
+ <button class="btn" onclick="publish('teams')">Publish selected → Teams</button>
819
+ </div>
820
+ </div>
821
+ </div>
822
+
823
+ <div class="panel">
824
+ <div class="panelHead"><b>Slug rules & export</b></div>
825
+ <div class="panelBody">
826
+ <label>Project slug rules</label>
827
+ <textarea id="slugRules" rows="8" placeholder="{ \"rules\": [ { \"contains\": \"fideliza\", \"slug\": \"vivo/fidelizacao\" } ] }" style="width:100%; padding:10px 12px; border-radius:12px; border:1px solid var(--line); background: rgba(255,255,255,.72); color: var(--text); outline:none; resize: vertical; font-family: var(--mono);"></textarea>
828
+ <div class="help">Regras usadas pra inferir <code>projectSlug</code>. Formato JSON (objeto com <code>rules</code>).</div>
829
+ <div class="stack" style="margin-top:10px">
830
+ <button class="btn" onclick="reloadSlugRules()">Reload rules</button>
831
+ <button class="btn" onclick="saveSlugRules()">Save rules</button>
832
+ <button class="btn" onclick="exportObsidian()">Export Obsidian notes</button>
833
+ </div>
834
+ </div>
835
+ </div>
836
+
837
+ <div class="panel">
838
+ <div class="panelHead"><b>Debug</b></div>
839
+ <div class="panelBody">
840
+ <div class="help">Logs ficam em <code>logs/</code> e debug traces em <code>.debuglogs/</code> dentro da workspace.</div>
841
+ <div class="help">Use <b>Open file</b> / <b>Copy path</b> no Preview para abrir/compartilhar o relatório selecionado.</div>
842
+ </div>
843
+ </div>
844
+ </div>
845
+ </div>
846
+ </details>
862
847
  </div>
863
848
  </main>
864
849
 
850
+ <!-- RIGHT: Chat -->
851
+ <aside class="chatPane">
852
+ <div class="chatHead">
853
+ <div>
854
+ <div class="chatTitle">Chat</div>
855
+ <div class="chatSub">Capture updates, then let Agents plan/apply.</div>
856
+ </div>
857
+ </div>
858
+
859
+ <div class="chatThread" id="chatThread">
860
+ <div class="bubble assistant">
861
+ <div class="bubbleMeta">FREYA</div>
862
+ <div class="bubbleBody">Cole seus updates (status, blockers, decisões, ideias) e clique em <b>Save + Process</b>.</div>
863
+ </div>
864
+ </div>
865
+
866
+ <div class="chatComposer">
867
+ <textarea id="inboxText" rows="5" placeholder="Cole aqui updates do dia (status, blockers, decisões, ideias)…"></textarea>
868
+
869
+ <div class="composerActions">
870
+ <button class="btn primary" type="button" onclick="saveAndPlan()">Save + Process (Agents)</button>
871
+ <button class="btn" type="button" onclick="runSuggestedReports()">Run suggested reports</button>
872
+ </div>
873
+
874
+ <div class="composerToggles">
875
+ <label class="toggleRow">
876
+ <input id="autoApply" type="checkbox" checked style="width:auto" onchange="toggleAutoApply()" />
877
+ Auto-apply plan
878
+ </label>
879
+ <label class="toggleRow">
880
+ <input id="autoRunReports" type="checkbox" style="width:auto" onchange="toggleAutoRunReports()" />
881
+ Auto-run suggested reports
882
+ </label>
883
+ </div>
884
+
885
+ <div class="statusFooter">
886
+ <span id="status" class="small">idle</span>
887
+ </div>
888
+ </div>
889
+ </aside>
890
+
865
891
  </div>
866
892
  </div>
867
893
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js",