agentgui 1.0.959 → 1.0.960
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/.claude/workflows/gui-logic-predictability.js +88 -0
- package/AGENTS.md +11 -9
- package/PUNCHLIST-LOGIC.md +405 -0
- package/lib/broadcast.js +1 -0
- package/lib/ws-handlers-util.js +42 -4
- package/package.json +1 -1
- package/server.js +27 -0
- package/site/app/js/app.js +660 -136
- package/site/app/js/backend.js +25 -1
- package/site/app/vendor/anentrypoint-design/247420.css +116 -2
- package/site/app/vendor/anentrypoint-design/247420.js +13 -13
package/site/app/js/backend.js
CHANGED
|
@@ -363,8 +363,18 @@ export async function* streamChat(base, { model, messages, signal, agentId, resu
|
|
|
363
363
|
else if (block?.type === 'result') push({ type: 'result', block });
|
|
364
364
|
} else if (ev.type === 'streaming_complete') {
|
|
365
365
|
finish();
|
|
366
|
+
} else if (ev.type === 'streaming_cancelled') {
|
|
367
|
+
push({ type: 'cancelled' });
|
|
368
|
+
finish();
|
|
366
369
|
} else if (ev.type === 'streaming_error') {
|
|
367
|
-
|
|
370
|
+
// A remote stop (another tab / dashboard stop-all) is not a failure: the
|
|
371
|
+
// server marks it cancelled; surface it as a distinct event so the app
|
|
372
|
+
// can label the turn 'stopped' instead of a normal finish or error red.
|
|
373
|
+
if (ev.cancelled || ev.error === 'cancelled') {
|
|
374
|
+
push({ type: 'cancelled' });
|
|
375
|
+
} else {
|
|
376
|
+
errored = ev.error || 'streaming error';
|
|
377
|
+
}
|
|
368
378
|
finish();
|
|
369
379
|
}
|
|
370
380
|
});
|
|
@@ -381,6 +391,20 @@ export async function* streamChat(base, { model, messages, signal, agentId, resu
|
|
|
381
391
|
if (s === 'open') {
|
|
382
392
|
// Reconnected in time - the open handler already re-subscribed us.
|
|
383
393
|
if (graceTimer) { clearTimeout(graceTimer); graceTimer = null; }
|
|
394
|
+
// streaming_complete is fire-and-forget with no replay: if the turn
|
|
395
|
+
// finished while the socket was down, no terminal frame will ever
|
|
396
|
+
// arrive. Verify the session is still alive server-side; if it is
|
|
397
|
+
// gone, settle the iterator with a plain incomplete marker instead of
|
|
398
|
+
// hanging busy forever.
|
|
399
|
+
wsCall(base, 'chat.active', {}).then((d) => {
|
|
400
|
+
if (done) return;
|
|
401
|
+
const sessions = (d && d.sessions) || [];
|
|
402
|
+
const alive = Array.isArray(sessions) && sessions.some(x => x && x.sessionId === sessionId);
|
|
403
|
+
if (!alive) {
|
|
404
|
+
errored = errored || 'connection dropped mid-turn - the response may be incomplete; events were not replayed';
|
|
405
|
+
finish();
|
|
406
|
+
}
|
|
407
|
+
}).catch(() => {});
|
|
384
408
|
return;
|
|
385
409
|
}
|
|
386
410
|
if ((s === 'closed' || s === 'error') && !graceTimer) {
|
|
@@ -1700,6 +1700,19 @@
|
|
|
1700
1700
|
.ds-247420 .ds-upload-item.done .ds-upload-pct { color: var(--success); }
|
|
1701
1701
|
.ds-247420 .ds-upload-item.error .ds-upload-fill { background: var(--warn); }
|
|
1702
1702
|
.ds-247420 .ds-upload-item.error .ds-upload-pct { color: var(--warn); }
|
|
1703
|
+
/* Per-row upload recovery actions (replace / dismiss) — error rows are not dead ends. */
|
|
1704
|
+
.ds-247420 .ds-upload-item { grid-template-columns: minmax(0, 1fr) 120px 44px auto; }
|
|
1705
|
+
.ds-247420 .ds-upload-actions { display: inline-flex; gap: var(--space-1); justify-content: flex-end; }
|
|
1706
|
+
.ds-247420 .ds-upload-act {
|
|
1707
|
+
padding: 2px 10px; min-height: 24px; cursor: pointer;
|
|
1708
|
+
background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
|
|
1709
|
+
color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-micro);
|
|
1710
|
+
}
|
|
1711
|
+
.ds-247420 .ds-upload-act:hover { background: var(--bg-3); color: var(--fg); }
|
|
1712
|
+
.ds-247420 .ds-upload-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
1713
|
+
@media (hover: none), (pointer: coarse) {
|
|
1714
|
+
.ds-247420 .ds-upload-act { min-height: 44px; min-width: 44px; }
|
|
1715
|
+
}
|
|
1703
1716
|
|
|
1704
1717
|
/* Empty state */
|
|
1705
1718
|
.ds-247420 .ds-file-empty {
|
|
@@ -1757,6 +1770,14 @@
|
|
|
1757
1770
|
font-family: inherit; font-size: var(--fs-sm);
|
|
1758
1771
|
}
|
|
1759
1772
|
.ds-247420 .ds-modal-input:focus { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1773
|
+
/* In-body modal error (role=alert): mutation failures (409/403) surface INSIDE
|
|
1774
|
+
the dialog, not behind the fixed overlay. */
|
|
1775
|
+
.ds-247420 .ds-modal-error {
|
|
1776
|
+
margin: var(--space-2) 0 0; padding: 8px 10px;
|
|
1777
|
+
border: var(--bw-hair) solid var(--flame); border-radius: var(--r-2);
|
|
1778
|
+
background: color-mix(in oklab, var(--flame) 12%, var(--bg));
|
|
1779
|
+
color: var(--flame); font-size: var(--fs-xs);
|
|
1780
|
+
}
|
|
1760
1781
|
.ds-247420 .btn-primary.danger {
|
|
1761
1782
|
background: var(--warn);
|
|
1762
1783
|
border-color: var(--warn);
|
|
@@ -1886,10 +1907,12 @@
|
|
|
1886
1907
|
.ds-247420 .ds-file-row:hover .ds-file-check,
|
|
1887
1908
|
.ds-247420 .ds-file-row:focus-within .ds-file-check,
|
|
1888
1909
|
.ds-247420 .ds-file-check.on { opacity: 1; }
|
|
1889
|
-
/* Touch / coarse-pointer devices have no hover — keep checkboxes
|
|
1890
|
-
|
|
1910
|
+
/* Touch / coarse-pointer devices have no hover — keep checkboxes AND the
|
|
1911
|
+
per-row action buttons (rename/delete/download) visible so the file manager
|
|
1912
|
+
is fully reachable without a pointer (e.g. an iPad in landscape). */
|
|
1891
1913
|
@media (hover: none), (pointer: coarse) {
|
|
1892
1914
|
.ds-247420 .ds-file-check { opacity: 1; }
|
|
1915
|
+
.ds-247420 .ds-file-actions { opacity: 1; }
|
|
1893
1916
|
}
|
|
1894
1917
|
.ds-247420 .ds-file-check.on { background: var(--accent); border-color: var(--accent); }
|
|
1895
1918
|
.ds-247420 .ds-file-row.selected {
|
|
@@ -5415,6 +5438,97 @@
|
|
|
5415
5438
|
.ds-247420 .ds-session-meta-copy { min-height: 44px; min-width: 44px; }
|
|
5416
5439
|
}
|
|
5417
5440
|
|
|
5441
|
+
/* ============================================================================
|
|
5442
|
+
Logic/predictability sweep (2026-06-10): composer ergonomics, turn notices,
|
|
5443
|
+
windowed thread, dashboard stopping/external states, cwd validation.
|
|
5444
|
+
============================================================================ */
|
|
5445
|
+
|
|
5446
|
+
/* Enter-to-send hint: visible while the composer is focused or carries a
|
|
5447
|
+
draft; hidden under 420px to save rows. */
|
|
5448
|
+
.ds-247420 .chat-composer-hint {
|
|
5449
|
+
display: none; padding: 2px var(--space-3) 0;
|
|
5450
|
+
font-size: var(--fs-micro); color: var(--fg-3);
|
|
5451
|
+
}
|
|
5452
|
+
.ds-247420 .chat-composer:focus-within .chat-composer-hint,
|
|
5453
|
+
.ds-247420 .chat-composer.has-draft .chat-composer-hint { display: block; }
|
|
5454
|
+
@media (max-width: 420px) {
|
|
5455
|
+
.ds-247420 .chat-composer .chat-composer-hint { display: none; }
|
|
5456
|
+
}
|
|
5457
|
+
|
|
5458
|
+
/* Transient composer note (paste/drop not supported), aria-live polite. */
|
|
5459
|
+
.ds-247420 .chat-composer-note {
|
|
5460
|
+
padding: 4px var(--space-3); font-size: var(--fs-tiny); color: var(--fg-2);
|
|
5461
|
+
}
|
|
5462
|
+
|
|
5463
|
+
/* Drag-over ring: token accent, never a hex. */
|
|
5464
|
+
.ds-247420 .chat-composer.dragover { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-2); }
|
|
5465
|
+
|
|
5466
|
+
/* Per-bit composer context: only the bit that owns a control is a button. */
|
|
5467
|
+
.ds-247420 .chat-composer-context-bit {
|
|
5468
|
+
display: inline; padding: 0; margin: 0;
|
|
5469
|
+
background: none; border: none; cursor: pointer;
|
|
5470
|
+
font: inherit; color: inherit; text-decoration: underline dotted;
|
|
5471
|
+
}
|
|
5472
|
+
.ds-247420 .chat-composer-context-bit:hover { color: var(--fg-2); }
|
|
5473
|
+
.ds-247420 .chat-composer-context-bit:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
5474
|
+
@media (pointer: coarse) {
|
|
5475
|
+
.ds-247420 .chat-composer-context-bit { min-height: 44px; }
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5478
|
+
/* Out-of-band turn notices: neutral tone (NOT error red) — a stopped or
|
|
5479
|
+
incomplete turn must not read as a finished answer. */
|
|
5480
|
+
.ds-247420 .chat-msg-notice {
|
|
5481
|
+
margin-top: var(--space-1); padding: 6px 10px;
|
|
5482
|
+
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
5483
|
+
background: var(--bg-2); color: var(--fg-2); font-size: var(--fs-tiny);
|
|
5484
|
+
}
|
|
5485
|
+
.ds-247420 .chat-msg-notice.is-incomplete { border-style: dashed; }
|
|
5486
|
+
|
|
5487
|
+
/* Tail-window streaming head ('streaming · N KB so far'). */
|
|
5488
|
+
.ds-247420 .chat-stream-head {
|
|
5489
|
+
padding: 2px 0 6px; font-family: var(--ff-mono);
|
|
5490
|
+
font-size: var(--fs-micro); color: var(--fg-3);
|
|
5491
|
+
}
|
|
5492
|
+
|
|
5493
|
+
/* Windowed thread: 'show N earlier turns' control at the top. */
|
|
5494
|
+
.ds-247420 .agentchat-earlier {
|
|
5495
|
+
display: flex; align-items: center; justify-content: center;
|
|
5496
|
+
gap: var(--space-3); padding: var(--space-2) var(--space-3);
|
|
5497
|
+
}
|
|
5498
|
+
.ds-247420 .agentchat-earlier-count { font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
5499
|
+
.ds-247420 .agentchat-earlier-btn {
|
|
5500
|
+
padding: 4px 12px; min-height: 32px; border: var(--bw-hair) solid var(--bg-3);
|
|
5501
|
+
border-radius: var(--r-1); background: var(--bg-2); color: var(--fg-2); cursor: pointer;
|
|
5502
|
+
font-family: var(--ff-body); font-size: var(--fs-tiny);
|
|
5503
|
+
}
|
|
5504
|
+
.ds-247420 .agentchat-earlier-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
5505
|
+
@media (pointer: coarse) {
|
|
5506
|
+
.ds-247420 .agentchat-earlier-btn { min-height: 44px; }
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
/* Inline cwd validation line (checking / error) under the cwd input. */
|
|
5510
|
+
.ds-247420 .agentchat-cwd-hint { font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
5511
|
+
.ds-247420 .agentchat-cwd-hint.is-error { color: var(--flame); }
|
|
5512
|
+
|
|
5513
|
+
/* Dashboard: shared session title heading (same string as the rails). */
|
|
5514
|
+
.ds-247420 .ds-dash-title {
|
|
5515
|
+
font-size: var(--fs-body); font-weight: 600; color: var(--fg);
|
|
5516
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
5517
|
+
}
|
|
5518
|
+
|
|
5519
|
+
/* Stopping state: in-flight cancel reads distinctly from running/error. */
|
|
5520
|
+
.ds-247420 .ds-dash-status.is-stopping { color: var(--amber, #d9a93a); }
|
|
5521
|
+
|
|
5522
|
+
/* External (observed, not owned) session card: no stop control exists. */
|
|
5523
|
+
.ds-247420 .ds-dash-external {
|
|
5524
|
+
padding: 1px 6px; border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-pill);
|
|
5525
|
+
font-size: var(--fs-micro); color: var(--fg-3); text-transform: uppercase; letter-spacing: .03em;
|
|
5526
|
+
}
|
|
5527
|
+
.ds-247420 .ds-dash-card.is-external { border-style: dashed; }
|
|
5528
|
+
|
|
5529
|
+
/* One connection vocabulary: offline (is-lost kept as legacy alias). */
|
|
5530
|
+
.ds-247420 .ds-dash-stream.is-offline { color: var(--flame); }
|
|
5531
|
+
|
|
5418
5532
|
/* editor-primitives.css */
|
|
5419
5533
|
/* editor-primitives.css — chrome for in-engine editors, inspectors, IDEs,
|
|
5420
5534
|
debug HUDs. All rules under .ds-247420 scope (build prefixes). Tokens
|