opencroc 1.6.7 โ†’ 1.6.8

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.
@@ -6,44 +6,160 @@
6
6
  <title>OpenCroc Studio ๐ŸŠ</title>
7
7
  <style>
8
8
  :root {
9
- --bg-dark: #0a0a1a;
10
- --bg-panel: #12122a;
11
- --bg-card: #1a1a3e;
12
- --accent: #4ecca3;
13
- --accent-dim: #2a8a6a;
14
- --red: #e94560;
15
- --orange: #f39c12;
16
- --blue: #3498db;
17
- --purple: #9b59b6;
18
- --text: #e0e0e0;
19
- --text-dim: #888;
20
- --pixel-border: 2px solid #333;
9
+ --bg-dark: #070b14;
10
+ --bg-panel: #101829;
11
+ --bg-panel-2: #0f1524;
12
+ --bg-card: #19263f;
13
+ --bg-soft: #233354;
14
+ --accent: #53d2a6;
15
+ --accent-dim: #2b8f73;
16
+ --red: #f05f78;
17
+ --orange: #f6ad55;
18
+ --blue: #59a5ff;
19
+ --purple: #b58cff;
20
+ --text: #e7edf8;
21
+ --text-dim: #8b9cc0;
22
+ --text-subtle: #6a7da5;
23
+ --pixel-border: 1px solid rgba(131, 156, 211, 0.22);
24
+ --shadow-lg: 0 14px 30px rgba(0, 0, 0, 0.38);
25
+ --shadow-md: 0 8px 20px rgba(0, 0, 0, 0.28);
21
26
  }
22
27
  * { margin:0; padding:0; box-sizing:border-box; }
23
- body { background:var(--bg-dark); color:var(--text); font-family:'Courier New','Consolas',monospace; overflow:hidden; height:100vh; }
24
-
25
- .app { display:grid; grid-template-rows:48px 1fr 220px; grid-template-columns:220px 1fr 280px; height:100vh; }
28
+ body {
29
+ background:
30
+ radial-gradient(circle at 20% 10%, rgba(83, 210, 166, 0.12), transparent 35%),
31
+ radial-gradient(circle at 80% 20%, rgba(89, 165, 255, 0.12), transparent 35%),
32
+ linear-gradient(180deg, #05070d 0%, var(--bg-dark) 55%, #060810 100%);
33
+ color:var(--text);
34
+ font-family:'Courier New','Consolas',monospace;
35
+ overflow:hidden;
36
+ height:100vh;
37
+ }
26
38
 
27
- .header { grid-column:1/-1; background:var(--bg-panel); border-bottom:var(--pixel-border); display:flex; align-items:center; padding:0 16px; gap:12px; }
28
- .header .logo { font-size:24px; }
29
- .header h1 { font-size:15px; color:var(--accent); }
39
+ .app { display:grid; grid-template-rows:68px 1fr 238px; grid-template-columns:260px 1fr 340px; height:100vh; gap:8px; padding:8px; }
40
+
41
+ .header {
42
+ grid-column:1/-1;
43
+ background:linear-gradient(180deg, rgba(16, 24, 41, 0.95), rgba(15, 21, 36, 0.9));
44
+ border:var(--pixel-border);
45
+ border-radius:12px;
46
+ display:flex;
47
+ align-items:center;
48
+ padding:0 16px;
49
+ gap:12px;
50
+ box-shadow:var(--shadow-lg);
51
+ backdrop-filter: blur(8px);
52
+ }
53
+ .header .logo {
54
+ font-size:26px;
55
+ width:40px;
56
+ height:40px;
57
+ border-radius:10px;
58
+ display:grid;
59
+ place-items:center;
60
+ background:linear-gradient(135deg, rgba(83,210,166,.2), rgba(89,165,255,.2));
61
+ border:1px solid rgba(131,156,211,.26);
62
+ }
63
+ .header .title-wrap { display:flex; flex-direction:column; gap:2px; }
64
+ .header h1 { font-size:15px; color:var(--accent); letter-spacing:.4px; }
65
+ .header .subtitle { font-size:10px; color:var(--text-subtle); }
30
66
  .header .actions { display:flex; gap:6px; }
31
- .btn { background:var(--accent-dim); color:#fff; border:none; padding:5px 12px; font-family:inherit; font-size:11px; border-radius:3px; cursor:pointer; transition:all .2s; }
32
- .btn:hover { background:var(--accent); transform:translateY(-1px); }
67
+ .view-switch {
68
+ display:flex;
69
+ background:rgba(13,20,34,.78);
70
+ border:1px solid rgba(131,156,211,.26);
71
+ border-radius:10px;
72
+ padding:2px;
73
+ margin-right:4px;
74
+ }
75
+ .view-switch button {
76
+ background:transparent;
77
+ color:var(--text-dim);
78
+ border:none;
79
+ font-family:inherit;
80
+ font-size:10px;
81
+ padding:5px 10px;
82
+ border-radius:8px;
83
+ cursor:pointer;
84
+ }
85
+ .view-switch button.active {
86
+ background:rgba(83,210,166,.18);
87
+ color:var(--accent);
88
+ border:1px solid rgba(83,210,166,.35);
89
+ }
90
+ .btn {
91
+ background:linear-gradient(180deg, rgba(43,143,115,.9), rgba(31,109,88,.9));
92
+ color:#fff;
93
+ border:1px solid rgba(83,210,166,.35);
94
+ padding:6px 12px;
95
+ font-family:inherit;
96
+ font-size:11px;
97
+ border-radius:8px;
98
+ cursor:pointer;
99
+ transition:all .2s;
100
+ box-shadow:var(--shadow-md);
101
+ }
102
+ .btn:hover { background:linear-gradient(180deg, rgba(83,210,166,.95), rgba(43,143,115,.95)); transform:translateY(-1px); }
33
103
  .btn:active { transform:translateY(0); }
34
104
  .btn:disabled { opacity:.4; cursor:not-allowed; transform:none; }
35
- .btn.danger { background:#8b2035; }
36
- .btn.danger:hover { background:var(--red); }
37
- .mode-select { background:var(--bg-card); color:var(--text); border:1px solid #333; border-radius:3px; font-family:inherit; font-size:10px; padding:4px 6px; }
38
- .header .stats { margin-left:auto; display:flex; gap:14px; font-size:11px; color:var(--text-dim); }
39
- .header .stats span { color:var(--accent); font-weight:bold; }
40
- .conn-dot { width:8px; height:8px; border-radius:50%; background:var(--red); transition:background .3s; }
41
- .conn-dot.on { background:var(--accent); }
42
-
43
- .sidebar { background:var(--bg-panel); border-right:var(--pixel-border); overflow-y:auto; padding:8px; }
44
- .sidebar h3 { font-size:10px; text-transform:uppercase; color:var(--text-dim); padding:8px 4px 4px; letter-spacing:1px; }
45
- .mod-item { padding:5px 8px; border-radius:3px; font-size:11px; cursor:pointer; display:flex; align-items:center; gap:6px; transition:background .15s; }
46
- .mod-item:hover { background:var(--bg-card); }
105
+ .btn.danger { background:linear-gradient(180deg, rgba(155,49,72,.9), rgba(127,34,55,.9)); border-color:rgba(240,95,120,.38); }
106
+ .btn.danger:hover { background:linear-gradient(180deg, rgba(240,95,120,.95), rgba(163,57,80,.95)); }
107
+ .mode-select {
108
+ background:var(--bg-card);
109
+ color:var(--text);
110
+ border:1px solid rgba(131,156,211,.26);
111
+ border-radius:8px;
112
+ font-family:inherit;
113
+ font-size:10px;
114
+ padding:6px 8px;
115
+ min-width:88px;
116
+ }
117
+ .header .stats { margin-left:auto; display:flex; gap:8px; font-size:10px; color:var(--text-dim); }
118
+ .header .stats > div {
119
+ background:rgba(25, 38, 63, 0.62);
120
+ border:1px solid rgba(131,156,211,.2);
121
+ border-radius:10px;
122
+ padding:6px 8px;
123
+ min-width:72px;
124
+ text-align:center;
125
+ }
126
+ .header .stats span { display:block; color:var(--accent); font-weight:bold; font-size:12px; margin-top:2px; }
127
+ .conn-dot {
128
+ width:10px;
129
+ height:10px;
130
+ border-radius:50%;
131
+ background:var(--red);
132
+ box-shadow:0 0 0 3px rgba(240,95,120,.2);
133
+ transition:background .3s, box-shadow .3s;
134
+ }
135
+ .conn-dot.on { background:var(--accent); box-shadow:0 0 0 3px rgba(83,210,166,.2); }
136
+
137
+ .sidebar {
138
+ background:linear-gradient(180deg, rgba(16,24,41,.96), rgba(15,21,36,.92));
139
+ border:var(--pixel-border);
140
+ border-radius:12px;
141
+ overflow-y:auto;
142
+ padding:10px;
143
+ box-shadow:var(--shadow-md);
144
+ }
145
+ .sidebar h3 { font-size:10px; text-transform:uppercase; color:var(--text-subtle); padding:10px 6px 6px; letter-spacing:1.1px; }
146
+ .mod-item {
147
+ padding:7px 10px;
148
+ border-radius:8px;
149
+ font-size:11px;
150
+ cursor:pointer;
151
+ display:flex;
152
+ align-items:center;
153
+ gap:6px;
154
+ transition:background .15s, transform .15s;
155
+ margin-bottom:3px;
156
+ border:1px solid transparent;
157
+ }
158
+ .mod-item:hover {
159
+ background:rgba(35,51,84,.58);
160
+ border-color:rgba(83,210,166,.2);
161
+ transform:translateX(2px);
162
+ }
47
163
  .dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
48
164
  .dot.idle { background:var(--text-dim); }
49
165
  .dot.testing,.dot.working { background:var(--orange); animation:blink .7s infinite; }
@@ -52,34 +168,150 @@
52
168
  .dot.failed,.dot.error { background:var(--red); }
53
169
  @keyframes blink { 50%{opacity:.3} }
54
170
 
55
- .main { position:relative; overflow:hidden; }
171
+ .main {
172
+ position:relative;
173
+ overflow:hidden;
174
+ background:linear-gradient(180deg, rgba(16,24,41,.95), rgba(15,21,36,.92));
175
+ border:var(--pixel-border);
176
+ border-radius:12px;
177
+ box-shadow:var(--shadow-lg);
178
+ }
56
179
  #graph-canvas { width:100%; height:100%; display:block; cursor:grab; }
57
- .tooltip { position:absolute; background:var(--bg-card); border:1px solid var(--accent-dim); border-radius:4px; padding:8px 12px; font-size:11px; pointer-events:none; z-index:100; display:none; max-width:280px; }
180
+ .view {
181
+ position:absolute;
182
+ inset:0;
183
+ }
184
+ .view.hidden { display:none; }
185
+ .pixel-stage {
186
+ position:relative;
187
+ width:100%;
188
+ height:100%;
189
+ overflow:hidden;
190
+ background:
191
+ linear-gradient(rgba(8,12,20,.2), rgba(8,12,20,.5)),
192
+ url('./assets/star/office_bg_small.webp') center/cover no-repeat;
193
+ }
194
+ .pixel-stage::before {
195
+ content:'';
196
+ position:absolute;
197
+ inset:0;
198
+ background-image:
199
+ linear-gradient(rgba(111,141,194,.13) 1px, transparent 1px),
200
+ linear-gradient(90deg, rgba(111,141,194,.13) 1px, transparent 1px);
201
+ background-size: 28px 28px;
202
+ pointer-events:none;
203
+ }
204
+ .pixel-stage .asset {
205
+ position:absolute;
206
+ image-rendering:pixelated;
207
+ z-index:2;
208
+ filter: drop-shadow(0 6px 10px rgba(0,0,0,.35));
209
+ opacity:.96;
210
+ }
211
+ .pixel-stage .desk-asset { width:180px; bottom:90px; left:40px; }
212
+ .pixel-stage .server-asset { width:110px; top:24px; right:34px; }
213
+ .pixel-stage .coffee-asset { width:72px; top:100px; right:180px; }
214
+ .pixel-stage .walls-asset { width:220px; top:10px; left:46%; transform:translateX(-50%); opacity:.45; }
215
+ .pixel-agent-layer {
216
+ position:absolute;
217
+ inset:0;
218
+ z-index:3;
219
+ }
220
+ .pixel-agent {
221
+ position:absolute;
222
+ width:44px;
223
+ transition: left .55s ease, top .55s ease;
224
+ image-rendering:pixelated;
225
+ filter: drop-shadow(0 5px 7px rgba(0,0,0,.36));
226
+ }
227
+ .pixel-agent.working,.pixel-agent.testing { animation: bob .45s infinite alternate; }
228
+ .pixel-agent.thinking { animation: thinking 1s infinite; }
229
+ .pixel-agent.error,.pixel-agent.failed { animation: shake .28s infinite; }
230
+ .pixel-agent.done,.pixel-agent.passed { animation: pulse .85s infinite; }
231
+ @keyframes bob { from { transform: translateY(0); } to { transform: translateY(-3px); } }
232
+ @keyframes thinking { 0%,100%{transform:rotate(0)} 50%{transform:rotate(-3deg)} }
233
+ @keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-2px)} 75%{transform:translateX(2px)} }
234
+ @keyframes pulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.06)} }
235
+ .pixel-label {
236
+ position:absolute;
237
+ transform:translate(-50%, -50%);
238
+ background:rgba(6,10,18,.82);
239
+ border:1px solid rgba(83,210,166,.35);
240
+ border-radius:6px;
241
+ padding:2px 6px;
242
+ font-size:9px;
243
+ color:#e9f3ff;
244
+ white-space:nowrap;
245
+ z-index:4;
246
+ }
247
+ .pixel-kpis {
248
+ position:absolute;
249
+ left:14px;
250
+ top:14px;
251
+ display:flex;
252
+ gap:8px;
253
+ z-index:4;
254
+ }
255
+ .pixel-kpi {
256
+ min-width:90px;
257
+ background:rgba(10,16,28,.72);
258
+ border:1px solid rgba(131,156,211,.24);
259
+ border-radius:8px;
260
+ padding:6px 8px;
261
+ box-shadow:var(--shadow-md);
262
+ }
263
+ .pixel-kpi .t { font-size:9px; color:var(--text-subtle); }
264
+ .pixel-kpi .v { font-size:12px; color:var(--accent); font-weight:bold; margin-top:2px; }
265
+ .tooltip { position:absolute; background:rgba(25,38,63,.94); border:1px solid rgba(83,210,166,.35); border-radius:8px; padding:8px 12px; font-size:11px; pointer-events:none; z-index:100; display:none; max-width:280px; box-shadow:var(--shadow-md); }
58
266
  .tooltip.visible { display:block; }
59
267
 
60
- .log-panel { background:var(--bg-panel); border-left:var(--pixel-border); display:flex; flex-direction:column; overflow:hidden; }
61
- .panel-tabs { display:flex; border-bottom:1px solid #222; }
62
- .panel-tabs .tab { background:none; border:none; color:var(--text-dim); font-family:inherit; font-size:10px; padding:8px 12px; cursor:pointer; text-transform:uppercase; letter-spacing:1px; border-bottom:2px solid transparent; }
63
- .panel-tabs .tab.active { color:var(--accent); border-bottom-color:var(--accent); }
268
+ .log-panel { background:linear-gradient(180deg, rgba(16,24,41,.96), rgba(15,21,36,.92)); border:var(--pixel-border); border-radius:12px; display:flex; flex-direction:column; overflow:hidden; box-shadow:var(--shadow-md); }
269
+ .panel-tabs { display:flex; border-bottom:1px solid rgba(131,156,211,.18); background:rgba(25,38,63,.3); }
270
+ .panel-tabs .tab { background:none; border:none; color:var(--text-dim); font-family:inherit; font-size:10px; padding:9px 12px; cursor:pointer; text-transform:uppercase; letter-spacing:1px; border-bottom:2px solid transparent; }
271
+ .panel-tabs .tab.active { color:var(--accent); border-bottom-color:var(--accent); background:rgba(35,51,84,.45); }
64
272
  .panel-tabs .tab:hover { color:var(--text); }
65
273
  .file-list { flex:1; overflow-y:auto; padding:4px 8px; font-size:10px; }
66
- .file-item { padding:6px 8px; border-bottom:1px solid #1a1a2e; cursor:pointer; border-radius:3px; }
67
- .file-item:hover { background:var(--bg-card); }
274
+ .file-item { padding:7px 8px; border-bottom:1px solid rgba(131,156,211,.12); cursor:pointer; border-radius:8px; transition:background .15s; }
275
+ .file-item:hover { background:rgba(35,51,84,.55); }
68
276
  .file-item .fname { color:var(--accent); font-weight:bold; }
69
277
  .file-item .fmeta { color:var(--text-dim); font-size:9px; margin-top:2px; }
70
- .file-preview { position:fixed; top:60px; left:50%; transform:translateX(-50%); width:700px; max-height:80vh; background:var(--bg-panel); border:2px solid var(--accent-dim); border-radius:8px; z-index:200; display:none; flex-direction:column; }
278
+ .file-preview { position:fixed; top:60px; left:50%; transform:translateX(-50%); width:760px; max-height:82vh; background:var(--bg-panel); border:1px solid rgba(83,210,166,.35); border-radius:12px; z-index:200; display:none; flex-direction:column; box-shadow:var(--shadow-lg); }
71
279
  .file-preview.visible { display:flex; }
72
- .file-preview .fp-header { display:flex; justify-content:space-between; align-items:center; padding:10px 14px; border-bottom:1px solid #333; }
280
+ .file-preview .fp-header { display:flex; justify-content:space-between; align-items:center; padding:10px 14px; border-bottom:1px solid rgba(131,156,211,.18); }
73
281
  .file-preview .fp-header h4 { font-size:12px; color:var(--accent); margin:0; }
74
282
  .file-preview .fp-close { background:none; border:none; color:var(--text-dim); font-size:18px; cursor:pointer; }
75
- .file-preview pre { flex:1; overflow:auto; padding:12px; margin:0; font-size:11px; line-height:1.5; color:var(--text); background:#0d0d20; }
283
+ .file-preview pre { flex:1; overflow:auto; padding:14px; margin:0; font-size:11px; line-height:1.5; color:var(--text); background:#0c1220; }
76
284
  .log-list { flex:1; overflow-y:auto; padding:4px 8px; font-size:10px; line-height:1.6; }
77
- .log-list .log-entry { padding:2px 0; border-bottom:1px solid #1a1a2e; word-break:break-all; }
285
+ .log-list .log-entry { padding:4px 2px; border-bottom:1px solid rgba(131,156,211,.08); word-break:break-all; }
78
286
  .log-list .log-entry.warn { color:var(--orange); }
79
287
  .log-list .log-entry.error { color:var(--red); }
80
288
 
81
- .office { grid-column:1/-1; background:var(--bg-panel); border-top:var(--pixel-border); display:flex; overflow-x:auto; padding:8px; gap:8px; }
82
- .desk { flex:0 0 180px; background:var(--bg-card); border:1px solid #333; border-radius:4px; padding:8px; display:flex; flex-direction:column; align-items:center; gap:2px; position:relative; overflow:hidden; }
289
+ .office {
290
+ grid-column:1/-1;
291
+ background:
292
+ linear-gradient(180deg, rgba(16,24,41,.96), rgba(15,21,36,.92));
293
+ border:var(--pixel-border);
294
+ border-radius:12px;
295
+ display:flex;
296
+ overflow-x:auto;
297
+ padding:10px;
298
+ gap:10px;
299
+ box-shadow:var(--shadow-md);
300
+ }
301
+ .desk {
302
+ flex:0 0 190px;
303
+ background:linear-gradient(180deg, rgba(25,38,63,.95), rgba(22,33,54,.9));
304
+ border:1px solid rgba(131,156,211,.22);
305
+ border-radius:10px;
306
+ padding:10px;
307
+ display:flex;
308
+ flex-direction:column;
309
+ align-items:center;
310
+ gap:3px;
311
+ position:relative;
312
+ overflow:hidden;
313
+ box-shadow:0 8px 18px rgba(0,0,0,.25);
314
+ }
83
315
  .desk .badge { position:absolute; top:4px; right:4px; width:8px; height:8px; border-radius:50%; }
84
316
  .desk .croc-sprite { font-size:40px; position:relative; z-index:1; }
85
317
  .desk.idle .croc-sprite { animation:croc-idle 3s infinite; }
@@ -104,8 +336,15 @@
104
336
  <div class="app">
105
337
  <header class="header">
106
338
  <div class="logo">๐ŸŠ</div>
107
- <h1>OpenCroc Studio</h1>
339
+ <div class="title-wrap">
340
+ <h1>OpenCroc Studio</h1>
341
+ <div class="subtitle">Pixel Ops Dashboard ยท Real-time Multi-Agent Runtime</div>
342
+ </div>
108
343
  <div class="actions">
344
+ <div class="view-switch">
345
+ <button id="view-dashboard" class="active">Dashboard</button>
346
+ <button id="view-office">Pixel Office</button>
347
+ </div>
109
348
  <button class="btn" id="btn-scan" title="Scan project">๐Ÿ” Scan</button>
110
349
  <button class="btn" id="btn-pipeline" title="Run full pipeline">โ–ถ Pipeline</button>
111
350
  <select id="run-mode" class="mode-select" title="Test run mode">
@@ -118,11 +357,11 @@
118
357
  <button class="btn danger" id="btn-reset" title="Reset agents">โน Reset</button>
119
358
  </div>
120
359
  <div class="stats">
121
- <div>Modules: <span id="s-mod">-</span></div>
122
- <div>Models: <span id="s-mdl">-</span></div>
123
- <div>APIs: <span id="s-api">-</span></div>
124
- <div>Tests: <span id="s-files">-</span></div>
125
- <div id="s-results-wrap" style="display:none">Results: <span id="s-results" style="color:var(--accent)">-</span></div>
360
+ <div>Modules <span id="s-mod">-</span></div>
361
+ <div>Models <span id="s-mdl">-</span></div>
362
+ <div>APIs <span id="s-api">-</span></div>
363
+ <div>Tests <span id="s-files">-</span></div>
364
+ <div id="s-results-wrap" style="display:none">Results <span id="s-results" style="color:var(--accent)">-</span></div>
126
365
  </div>
127
366
  <div class="conn-dot" id="conn-dot" title="WebSocket"></div>
128
367
  </header>
@@ -135,7 +374,23 @@
135
374
  </aside>
136
375
 
137
376
  <main class="main">
138
- <canvas id="graph-canvas"></canvas>
377
+ <div class="view" id="graph-view">
378
+ <canvas id="graph-canvas"></canvas>
379
+ </div>
380
+ <div class="view hidden" id="pixel-view">
381
+ <div class="pixel-stage">
382
+ <img class="asset desk-asset" src="./assets/star/desk-v3.webp" alt="desk">
383
+ <img class="asset server-asset" src="./assets/botreview/server.gif" alt="server">
384
+ <img class="asset coffee-asset" src="./assets/botreview/coffee-machine.gif" alt="coffee">
385
+ <img class="asset walls-asset" src="./assets/botreview/walls.png" alt="walls">
386
+ <div class="pixel-kpis">
387
+ <div class="pixel-kpi"><div class="t">Working</div><div class="v" id="kpi-working">0</div></div>
388
+ <div class="pixel-kpi"><div class="t">Errors</div><div class="v" id="kpi-errors">0</div></div>
389
+ <div class="pixel-kpi"><div class="t">Done</div><div class="v" id="kpi-done">0</div></div>
390
+ </div>
391
+ <div class="pixel-agent-layer" id="pixel-agent-layer"></div>
392
+ </div>
393
+ </div>
139
394
  <div class="tooltip" id="tooltip"></div>
140
395
  </main>
141
396
 
@@ -165,7 +420,8 @@ const S = {
165
420
  project:null, graph:{nodes:[],edges:[]}, agents:[], ws:null,
166
421
  pan:{x:0,y:0}, zoom:1, dragging:false, dragStart:{x:0,y:0},
167
422
  nodePos:new Map(), hoveredNode:null, running:false, _userPanned:false,
168
- generatedFiles:[], testMetrics:null, testQuality:null, reports:[], runMode:'auto'
423
+ generatedFiles:[], testMetrics:null, testQuality:null, reports:[], runMode:'auto',
424
+ currentView:'dashboard'
169
425
  };
170
426
 
171
427
  async function fetchProject(){
@@ -229,7 +485,7 @@ function connectWS(){
229
485
  try{
230
486
  const m=JSON.parse(e.data);
231
487
  if(m.type==='agent:update'&&Array.isArray(m.payload)){
232
- S.agents=m.payload; renderOffice(); renderAgentSB();
488
+ S.agents=m.payload; renderOffice(); renderAgentSB(); renderPixelOffice();
233
489
  }else if(m.type==='graph:update'){
234
490
  S.graph=m.payload; layoutGraph(); renderCanvas(); renderModList(); updateStats();
235
491
  }else if(m.type==='log'){
@@ -467,7 +723,7 @@ function updateAll(){
467
723
  document.getElementById('s-mdl').textContent=S.project.stats?.models||0;
468
724
  document.getElementById('s-api').textContent=S.project.stats?.endpoints||0;
469
725
  }
470
- renderModList();renderOffice();renderAgentSB();renderCanvas();
726
+ renderModList();renderOffice();renderAgentSB();renderPixelOffice();renderCanvas();
471
727
  }
472
728
  function renderModList(){
473
729
  const el=document.getElementById('mod-list'),mods=S.graph.nodes.filter(n=>n.type==='module');
@@ -518,6 +774,46 @@ function renderOffice(){
518
774
  '<div class="desk-items">'+(dd[a.role]||'')+'</div></div>';
519
775
  }).join('');
520
776
  }
777
+ function renderPixelOffice(){
778
+ const el=document.getElementById('pixel-agent-layer');
779
+ const stageWidth=(document.getElementById('pixel-view').clientWidth||900)-80;
780
+ const stageHeight=(document.getElementById('pixel-view').clientHeight||520)-120;
781
+ const presets=[
782
+ {x:.18,y:.64},{x:.3,y:.66},{x:.42,y:.62},{x:.56,y:.6},{x:.72,y:.63},{x:.82,y:.52},
783
+ {x:.22,y:.45},{x:.48,y:.42},{x:.66,y:.4},{x:.78,y:.72}
784
+ ];
785
+ const roles=['char_0','char_1','char_2'];
786
+ const working=S.agents.filter(a=>a.status==='working'||a.status==='testing').length;
787
+ const errors=S.agents.filter(a=>a.status==='error'||a.status==='failed').length;
788
+ const done=S.agents.filter(a=>a.status==='done'||a.status==='passed').length;
789
+ document.getElementById('kpi-working').textContent=String(working);
790
+ document.getElementById('kpi-errors').textContent=String(errors);
791
+ document.getElementById('kpi-done').textContent=String(done);
792
+ if(!S.agents.length){el.innerHTML='';return;}
793
+ el.innerHTML=S.agents.map((a,i)=>{
794
+ const p=presets[i%presets.length];
795
+ const x=Math.max(16,Math.round(stageWidth*p.x));
796
+ const y=Math.max(20,Math.round(stageHeight*p.y));
797
+ const roleSprite=roles[i%roles.length];
798
+ const labelY=Math.max(16,y-12);
799
+ return '<img class="pixel-agent '+a.status+'" src="./assets/botreview/'+roleSprite+'.png" style="left:'+x+'px;top:'+y+'px" alt="'+esc(a.name)+'" />'
800
+ +'<div class="pixel-label" style="left:'+(x+22)+'px;top:'+labelY+'px">'+esc(a.name)+' ยท '+esc(a.status)+'</div>';
801
+ }).join('');
802
+ }
803
+ function setView(view){
804
+ S.currentView=view;
805
+ const dashboard=view==='dashboard';
806
+ document.getElementById('graph-view').classList.toggle('hidden',!dashboard);
807
+ document.getElementById('pixel-view').classList.toggle('hidden',dashboard);
808
+ document.getElementById('view-dashboard').classList.toggle('active',dashboard);
809
+ document.getElementById('view-office').classList.toggle('active',!dashboard);
810
+ document.getElementById('tooltip').classList.remove('visible');
811
+ if(dashboard){
812
+ setTimeout(()=>{layoutGraph();renderCanvas();},0);
813
+ }else{
814
+ renderPixelOffice();
815
+ }
816
+ }
521
817
  function esc(s){return s?s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'):'';}
522
818
 
523
819
  document.getElementById('btn-scan').addEventListener('click',doScan);
@@ -526,6 +822,8 @@ document.getElementById('btn-reset').addEventListener('click',doReset);
526
822
  document.getElementById('btn-run-tests').addEventListener('click',doRunTests);
527
823
  document.getElementById('btn-reports').addEventListener('click',doReports);
528
824
  document.getElementById('run-mode').addEventListener('change',e=>{S.runMode=e.target.value;});
825
+ document.getElementById('view-dashboard').addEventListener('click',()=>setView('dashboard'));
826
+ document.getElementById('view-office').addEventListener('click',()=>setView('office'));
529
827
 
530
828
  // Tab switching
531
829
  document.querySelectorAll('.panel-tabs .tab').forEach(tab=>{
@@ -650,7 +948,7 @@ function renderReports(){
650
948
  }
651
949
 
652
950
  (async()=>{setupCanvas();await fetchProject();connectWS();addLog('๐ŸŠ OpenCroc Studio ready');
653
- window.addEventListener('resize',()=>{layoutGraph();renderCanvas();});})();
951
+ window.addEventListener('resize',()=>{layoutGraph();renderCanvas();renderPixelOffice();});})();
654
952
  </script>
655
953
  </body>
656
954
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencroc",
3
- "version": "1.6.7",
3
+ "version": "1.6.8",
4
4
  "description": "AI-native E2E testing framework โ€” source-aware test generation, intelligent validation, and self-healing",
5
5
  "keywords": [
6
6
  "e2e",