@cccarv82/freya 1.0.33 → 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 +195 -71
- package/cli/web-ui.js +49 -1
- package/cli/web.js +177 -133
- package/package.json +1 -1
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:
|
|
6
|
-
--
|
|
7
|
-
--
|
|
8
|
-
--
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
--
|
|
13
|
-
--
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--
|
|
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, .
|
|
21
|
-
--chip2: rgba(249, 115, 22, .
|
|
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: #
|
|
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:
|
|
46
|
-
|
|
47
|
-
|
|
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:
|
|
55
|
+
.app { padding: 18px; }
|
|
52
56
|
|
|
53
57
|
.frame {
|
|
54
|
-
max-width:
|
|
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,
|
|
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:
|
|
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,
|
|
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: .
|
|
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:
|
|
134
|
+
.sideTitle { font-weight: 800; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
|
|
123
135
|
|
|
124
|
-
.
|
|
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:
|
|
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
|
-
.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
145
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
.
|
|
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,
|
|
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,.
|
|
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,
|
|
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:
|
|
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
|
-
.
|
|
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
|
-
.
|
|
180
|
-
|
|
181
|
-
@media (max-width:
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
|
|
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:
|
|
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
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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
|
@@ -277,6 +277,38 @@ function postTeamsCard(url, card) {
|
|
|
277
277
|
return postJson(url, card);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
function extractFirstJsonObject(text) {
|
|
281
|
+
const t = String(text || '');
|
|
282
|
+
const start = t.indexOf('{');
|
|
283
|
+
if (start === -1) return null;
|
|
284
|
+
|
|
285
|
+
let depth = 0;
|
|
286
|
+
let inString = false;
|
|
287
|
+
let esc = false;
|
|
288
|
+
|
|
289
|
+
for (let i = start; i < t.length; i++) {
|
|
290
|
+
const ch = t[i];
|
|
291
|
+
|
|
292
|
+
if (esc) { esc = false; continue; }
|
|
293
|
+
if (ch === '\\') { esc = true; continue; }
|
|
294
|
+
|
|
295
|
+
if (ch === '"') {
|
|
296
|
+
inString = !inString;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (inString) continue;
|
|
301
|
+
|
|
302
|
+
if (ch === '{') depth++;
|
|
303
|
+
if (ch === '}') {
|
|
304
|
+
depth--;
|
|
305
|
+
if (depth === 0) return t.slice(start, i + 1);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
280
312
|
function escapeJsonControlChars(jsonText) {
|
|
281
313
|
// Replace unescaped control chars inside JSON string literals with safe escapes.
|
|
282
314
|
// Handles Copilot outputs where newlines/tabs leak into string values.
|
|
@@ -645,6 +677,7 @@ function buildHtml(safeDefault) {
|
|
|
645
677
|
<div class="frame">
|
|
646
678
|
<div class="shell">
|
|
647
679
|
|
|
680
|
+
<!-- LEFT: Workspaces / Topics -->
|
|
648
681
|
<aside class="sidebar">
|
|
649
682
|
<div class="sideHeader">
|
|
650
683
|
<div class="logo">FREYA</div>
|
|
@@ -654,47 +687,41 @@ function buildHtml(safeDefault) {
|
|
|
654
687
|
<div class="sidePath" id="sidePath">./freya</div>
|
|
655
688
|
|
|
656
689
|
<div class="sideGroup">
|
|
657
|
-
<div class="sideTitle">
|
|
658
|
-
<
|
|
659
|
-
|
|
660
|
-
|
|
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>
|
|
661
699
|
<div style="height:10px"></div>
|
|
662
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>
|
|
663
701
|
<div class="help"><b>Migrate data</b>: ajusta formatos/schemaVersion quando uma versão nova exige.</div>
|
|
664
702
|
</div>
|
|
665
703
|
|
|
666
704
|
<div class="sideGroup">
|
|
667
|
-
<div class="sideTitle">
|
|
668
|
-
<div class="
|
|
669
|
-
|
|
670
|
-
|
|
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>
|
|
671
713
|
</div>
|
|
672
714
|
|
|
673
715
|
<div class="sideGroup">
|
|
674
|
-
<div class="sideTitle">
|
|
675
|
-
<
|
|
676
|
-
<div style="height:
|
|
677
|
-
<div class="
|
|
678
|
-
<button class="btn primary sideBtn" onclick="saveAndPlan()">Save + Process (Agents)</button>
|
|
679
|
-
<button class="btn sideBtn" onclick="runSuggestedReports()">Run suggested reports</button>
|
|
680
|
-
</div>
|
|
681
|
-
|
|
682
|
-
<div style="height:10px"></div>
|
|
683
|
-
<label style="display:flex; align-items:center; gap:10px; user-select:none">
|
|
684
|
-
<input id="autoApply" type="checkbox" checked style="width:auto" onchange="toggleAutoApply()" />
|
|
685
|
-
Auto-apply plan
|
|
686
|
-
</label>
|
|
687
|
-
<div class="help">Quando ligado, o Save+Process já aplica tasks/blockers automaticamente.</div>
|
|
688
|
-
|
|
689
|
-
<label style="display:flex; align-items:center; gap:10px; user-select:none; margin-top:10px">
|
|
690
|
-
<input id="autoRunReports" type="checkbox" style="width:auto" onchange="toggleAutoRunReports()" />
|
|
691
|
-
Auto-run suggested reports
|
|
692
|
-
</label>
|
|
693
|
-
<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>
|
|
694
720
|
</div>
|
|
695
721
|
</aside>
|
|
696
722
|
|
|
697
|
-
|
|
723
|
+
<!-- MIDDLE: Reports / Today -->
|
|
724
|
+
<main class="center">
|
|
698
725
|
<div class="topbar">
|
|
699
726
|
<div class="brand"><span class="spark"></span> Local-first status assistant</div>
|
|
700
727
|
<div class="actions">
|
|
@@ -703,83 +730,35 @@ function buildHtml(safeDefault) {
|
|
|
703
730
|
</div>
|
|
704
731
|
</div>
|
|
705
732
|
|
|
706
|
-
<div class="
|
|
707
|
-
<
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
<div class="card" onclick="runReport('status')">
|
|
712
|
-
<div class="icon">E</div>
|
|
713
|
-
<div class="title">Executive report</div>
|
|
714
|
-
<div class="desc">Status pronto para stakeholders (entregas, projetos, blockers).</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>
|
|
715
738
|
</div>
|
|
716
|
-
<div class="
|
|
717
|
-
<
|
|
718
|
-
<div class="title">SM weekly</div>
|
|
719
|
-
<div class="desc">Resumo, wins, riscos e foco da próxima semana.</div>
|
|
720
|
-
</div>
|
|
721
|
-
<div class="card" onclick="runReport('blockers')">
|
|
722
|
-
<div class="icon orange">B</div>
|
|
723
|
-
<div class="title">Blockers</div>
|
|
724
|
-
<div class="desc">Lista priorizada por severidade + idade (pra destravar rápido).</div>
|
|
725
|
-
</div>
|
|
726
|
-
<div class="card" onclick="runReport('daily')">
|
|
727
|
-
<div class="icon">D</div>
|
|
728
|
-
<div class="title">Daily</div>
|
|
729
|
-
<div class="desc">Ontem / Hoje / Bloqueios — pronto pra standup.</div>
|
|
739
|
+
<div class="statusLine">
|
|
740
|
+
<span class="small" id="last"></span>
|
|
730
741
|
</div>
|
|
731
742
|
</div>
|
|
732
743
|
|
|
733
|
-
<div class="
|
|
734
|
-
<
|
|
735
|
-
<div class="panelHead"
|
|
736
|
-
|
|
737
|
-
<label>Workspace dir</label>
|
|
738
|
-
<div class="row">
|
|
739
|
-
<input id="dir" placeholder="./freya" />
|
|
740
|
-
<button class="btn small" onclick="pickDir()">Browse</button>
|
|
741
|
-
</div>
|
|
742
|
-
<div class="help">Escolha a pasta que contém <code>data/</code>, <code>logs/</code> e <code>scripts/</code>.</div>
|
|
743
|
-
|
|
744
|
-
<div style="height:12px"></div>
|
|
745
|
-
|
|
746
|
-
<label>Discord webhook URL</label>
|
|
747
|
-
<input id="discord" placeholder="https://discord.com/api/webhooks/..." />
|
|
748
|
-
<div style="height:10px"></div>
|
|
749
|
-
|
|
750
|
-
<label>Teams webhook URL</label>
|
|
751
|
-
<input id="teams" placeholder="https://..." />
|
|
752
|
-
<div class="help">Os webhooks ficam salvos na workspace em <code>data/settings/settings.json</code>.</div>
|
|
753
|
-
|
|
754
|
-
<div style="height:10px"></div>
|
|
755
|
-
<label style="display:flex; align-items:center; gap:10px; user-select:none; margin: 6px 0 12px 0">
|
|
756
|
-
<input id="prettyPublish" type="checkbox" checked style="width:auto" onchange="togglePrettyPublish()" />
|
|
757
|
-
Pretty publish (cards/embeds)
|
|
758
|
-
</label>
|
|
759
|
-
|
|
744
|
+
<div class="midGrid">
|
|
745
|
+
<section class="panel">
|
|
746
|
+
<div class="panelHead">
|
|
747
|
+
<b>Today</b>
|
|
760
748
|
<div class="stack">
|
|
761
|
-
<button class="btn" onclick="
|
|
762
|
-
<button class="btn" onclick="publish('discord')">Publish selected → Discord</button>
|
|
763
|
-
<button class="btn" onclick="publish('teams')">Publish selected → Teams</button>
|
|
764
|
-
</div>
|
|
765
|
-
|
|
766
|
-
<div style="height:14px"></div>
|
|
767
|
-
|
|
768
|
-
<div class="help"><b>Dica:</b> clique em um relatório em <i>Reports</i> para ver o preview e habilitar publish/copy.</div>
|
|
769
|
-
|
|
770
|
-
<div style="height:14px"></div>
|
|
771
|
-
<label>Project slug rules</label>
|
|
772
|
-
<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>
|
|
773
|
-
<div class="help">Regras usadas pra inferir <code>projectSlug</code>. Formato JSON (objeto com <code>rules</code>). Editável no estilo Obsidian-friendly.</div>
|
|
774
|
-
<div class="stack" style="margin-top:10px">
|
|
775
|
-
<button class="btn" onclick="reloadSlugRules()">Reload rules</button>
|
|
776
|
-
<button class="btn" onclick="saveSlugRules()">Save rules</button>
|
|
777
|
-
<button class="btn" onclick="exportObsidian()">Export Obsidian notes</button>
|
|
749
|
+
<button class="btn small" onclick="refreshToday()">Refresh</button>
|
|
778
750
|
</div>
|
|
779
751
|
</div>
|
|
780
|
-
|
|
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>
|
|
781
760
|
|
|
782
|
-
<
|
|
761
|
+
<section class="panel">
|
|
783
762
|
<div class="panelHead">
|
|
784
763
|
<b>Reports</b>
|
|
785
764
|
<div class="stack">
|
|
@@ -791,25 +770,9 @@ function buildHtml(safeDefault) {
|
|
|
791
770
|
<div id="reportsList" style="display:grid; gap:8px"></div>
|
|
792
771
|
<div class="help">Últimos relatórios em <code>docs/reports</code>. Clique para abrir preview.</div>
|
|
793
772
|
</div>
|
|
794
|
-
</
|
|
795
|
-
|
|
796
|
-
<div class="panel">
|
|
797
|
-
<div class="panelHead">
|
|
798
|
-
<b>Today</b>
|
|
799
|
-
<div class="stack">
|
|
800
|
-
<button class="btn small" onclick="refreshToday()">Refresh</button>
|
|
801
|
-
</div>
|
|
802
|
-
</div>
|
|
803
|
-
<div class="panelBody">
|
|
804
|
-
<div class="small" style="margin-bottom:8px; opacity:.8">Do Now</div>
|
|
805
|
-
<div id="tasksList" style="display:grid; gap:8px"></div>
|
|
806
|
-
<div style="height:12px"></div>
|
|
807
|
-
<div class="small" style="margin-bottom:8px; opacity:.8">Open blockers</div>
|
|
808
|
-
<div id="blockersList" style="display:grid; gap:8px"></div>
|
|
809
|
-
</div>
|
|
810
|
-
</div>
|
|
773
|
+
</section>
|
|
811
774
|
|
|
812
|
-
<
|
|
775
|
+
<section class="panel midSpan">
|
|
813
776
|
<div class="panelHead">
|
|
814
777
|
<b>Preview</b>
|
|
815
778
|
<div class="stack">
|
|
@@ -825,11 +788,106 @@ function buildHtml(safeDefault) {
|
|
|
825
788
|
<div id="reportPreview" class="log md" style="font-family: var(--sans);"></div>
|
|
826
789
|
<div class="help">O preview renderiza Markdown básico (headers, listas, code). O botão Copy copia o conteúdo completo.</div>
|
|
827
790
|
</div>
|
|
828
|
-
</
|
|
791
|
+
</section>
|
|
829
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>
|
|
830
847
|
</div>
|
|
831
848
|
</main>
|
|
832
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
|
+
|
|
833
891
|
</div>
|
|
834
892
|
</div>
|
|
835
893
|
</div>
|
|
@@ -1206,14 +1264,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1206
1264
|
const planRaw = String(payload.plan || '').trim();
|
|
1207
1265
|
if (!planRaw) return safeJson(res, 400, { error: 'Missing plan' });
|
|
1208
1266
|
|
|
1209
|
-
|
|
1210
|
-
const start = text.indexOf('{');
|
|
1211
|
-
const end = text.lastIndexOf('}');
|
|
1212
|
-
if (start === -1 || end === -1 || end <= start) return null;
|
|
1213
|
-
return text.slice(start, end + 1);
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
const jsonText = extractJson(planRaw) || planRaw;
|
|
1267
|
+
const jsonText = extractFirstJsonObject(planRaw) || planRaw;
|
|
1217
1268
|
let plan;
|
|
1218
1269
|
try {
|
|
1219
1270
|
plan = JSON.parse(jsonText);
|
|
@@ -1298,14 +1349,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1298
1349
|
const planRaw = String(payload.plan || '').trim();
|
|
1299
1350
|
if (!planRaw) return safeJson(res, 400, { error: 'Missing plan' });
|
|
1300
1351
|
|
|
1301
|
-
|
|
1302
|
-
const start = text.indexOf('{');
|
|
1303
|
-
const end = text.lastIndexOf('}');
|
|
1304
|
-
if (start === -1 || end === -1 || end <= start) return null;
|
|
1305
|
-
return text.slice(start, end + 1);
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
const jsonText = extractJson(planRaw) || planRaw;
|
|
1352
|
+
const jsonText = extractFirstJsonObject(planRaw) || planRaw;
|
|
1309
1353
|
|
|
1310
1354
|
function errorSnippet(text, pos) {
|
|
1311
1355
|
const p = Number.isFinite(pos) ? pos : 0;
|