agentgui 1.0.1060 → 1.0.1062
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/.gm/prd.yml +51 -0
- package/lib/http-handler.js +27 -13
- package/package.json +1 -1
- package/site/app/js/app.js +265 -32
- package/site/app/js/backend.js +21 -7
- package/site/app/vendor/anentrypoint-design/247420.css +74 -10
- package/site/app/vendor/anentrypoint-design/247420.js +15 -15
package/site/app/js/backend.js
CHANGED
|
@@ -91,8 +91,16 @@ export async function probeBackend(base) {
|
|
|
91
91
|
// An empty path lands on the server's first allow-root. The server confines
|
|
92
92
|
// every path to an allowlist root, so a 403 means the path is out of bounds.
|
|
93
93
|
export async function listDir(base, dirPath) {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
// A path SEGMENT (encoded as %2F for its own slashes) is silently mangled by
|
|
95
|
+
// some reverse-proxy configs that normalize proxy_pass URIs - a nginx
|
|
96
|
+
// decode-then-reencode of the request path collapses %2F back into a literal
|
|
97
|
+
// slash before forwarding, so the app receives extra path segments instead
|
|
98
|
+
// of one opaque one, loses its leading slash on strip, and 403s every
|
|
99
|
+
// absolute-path listing that isn't the bare root. A query param is never
|
|
100
|
+
// subject to that URI-path normalization, so it survives any proxy in front
|
|
101
|
+
// of this app untouched.
|
|
102
|
+
const qs = dirPath ? '?dir=' + encodeURIComponent(dirPath) : '';
|
|
103
|
+
const r = await authedFetch(base + '/api/list' + qs);
|
|
96
104
|
const j = await r.json().catch(() => ({}));
|
|
97
105
|
if (!r.ok) {
|
|
98
106
|
// Carry the HTTP status so the app can map 403/404 to plain copy (W9).
|
|
@@ -108,7 +116,10 @@ export async function listDir(base, dirPath) {
|
|
|
108
116
|
// a 403 means out-of-bounds or unsupported type, 404 missing. Returns
|
|
109
117
|
// { content, truncated }.
|
|
110
118
|
export async function readFile(base, filePath) {
|
|
111
|
-
|
|
119
|
+
// Query param, not a path segment - see listDir()'s comment above for why:
|
|
120
|
+
// a reverse proxy's URI normalization can silently collapse an encoded %2F
|
|
121
|
+
// path-segment slash back into a literal slash before forwarding.
|
|
122
|
+
const r = await authedFetch(base + '/api/file?path=' + encodeURIComponent(filePath));
|
|
112
123
|
if (!r.ok) {
|
|
113
124
|
const t = await r.text().catch(() => '');
|
|
114
125
|
throw new Error(t || ('file: ' + r.status));
|
|
@@ -119,13 +130,13 @@ export async function readFile(base, filePath) {
|
|
|
119
130
|
|
|
120
131
|
// Same-origin URL for an image file (served by /api/image, token-threaded).
|
|
121
132
|
export function imageUrl(base, filePath) {
|
|
122
|
-
return withToken(base + '/api/image
|
|
133
|
+
return withToken(base + '/api/image?path=' + encodeURIComponent(filePath));
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
// Same-origin download URL (served by /api/download, attachment disposition,
|
|
126
137
|
// confined + token-threaded). Used by the Files row download action.
|
|
127
138
|
export function downloadUrl(base, filePath) {
|
|
128
|
-
return withToken(base + '/api/download
|
|
139
|
+
return withToken(base + '/api/download?path=' + encodeURIComponent(filePath));
|
|
129
140
|
}
|
|
130
141
|
|
|
131
142
|
// ---------- File mutations (confined server endpoints) ----------
|
|
@@ -143,10 +154,13 @@ async function mutateJSON(base, route, body) {
|
|
|
143
154
|
return j;
|
|
144
155
|
}
|
|
145
156
|
|
|
146
|
-
// Stat a path (GET /api/stat
|
|
157
|
+
// Stat a path (GET /api/stat?path=<encoded>) for cwd validation. Returns {ok, dir}.
|
|
147
158
|
// Throws an Error carrying .status (403 outside roots, 404 missing).
|
|
148
159
|
export async function statPath(base, p) {
|
|
149
|
-
|
|
160
|
+
// Query param, not a path segment - see the comment in listDir() above for
|
|
161
|
+
// why: a reverse proxy's URI normalization can silently collapse an encoded
|
|
162
|
+
// %2F path-segment slash back into a literal slash before forwarding.
|
|
163
|
+
const r = await authedFetch(base + '/api/stat?path=' + encodeURIComponent(p));
|
|
150
164
|
const j = await r.json().catch(() => ({}));
|
|
151
165
|
if (!r.ok) { const e = new Error(j.error || ('stat: ' + r.status)); e.status = r.status; throw e; }
|
|
152
166
|
return j;
|
|
@@ -60,8 +60,14 @@
|
|
|
60
60
|
--sky: #3A6EFF;
|
|
61
61
|
/* --warn = interactive danger controls (buttons, banners, menus, error
|
|
62
62
|
inputs); --danger below = passive error/status text and metrics
|
|
63
|
-
(kpi/sparkline deltas, auth-error text). Two tokens, one convention.
|
|
64
|
-
|
|
63
|
+
(kpi/sparkline deltas, auth-error text). Two tokens, one convention.
|
|
64
|
+
#E0241A measured 4.19:1 on --paper — fails WCAG AA 4.5:1 for the many
|
|
65
|
+
TEXT usages (.field-error, .ds-btn-warn, .ds-stat-val.err-rate, toast/
|
|
66
|
+
session error labels), not just the interactive-control (>=3:1) usages.
|
|
67
|
+
Darkened to clear AA on --paper (5.29:1), --paper-2 (4.78:1), and the
|
|
68
|
+
thebird warm-paper preset (5.25:1) while staying visually a clear
|
|
69
|
+
warm red. */
|
|
70
|
+
--warn: #C41C0C;
|
|
65
71
|
/* Syntax-token aliases: light values pass 4.5:1 on paper; the dark blocks
|
|
66
72
|
restore the bright dark-tuned originals. Components reference ONLY these. */
|
|
67
73
|
--code-string: var(--green);
|
|
@@ -477,7 +483,7 @@
|
|
|
477
483
|
--accent: var(--acid); --accent-fg: var(--ink); --accent-ink: var(--acid-deep);
|
|
478
484
|
--accent-tint: color-mix(in oklab, var(--accent-ink) 22%, var(--bg));
|
|
479
485
|
/* A paper island under a dark ancestor must not inherit the dark signal pair. */
|
|
480
|
-
--flame: #C53E00; --amber: #7C570F; --warn: #
|
|
486
|
+
--flame: #C53E00; --amber: #7C570F; --warn: #C41C0C; --sky: #3A6EFF;
|
|
481
487
|
}
|
|
482
488
|
|
|
483
489
|
/* thebird — warm-paper brand preset. A first-class swappable theme: it lives
|
|
@@ -951,6 +957,22 @@
|
|
|
951
957
|
.ds-247420 .app-main > .ds-files-stack,
|
|
952
958
|
.ds-247420 .app-main > .grow { flex: 1 1 auto; min-height: 0; }
|
|
953
959
|
.ds-247420 .app-main.narrow { max-width: var(--measure-narrow); margin: 0 auto; }
|
|
960
|
+
/* Article-body heading rhythm and lede spacing, consumed by flatspace-rendered
|
|
961
|
+
long-form pages (docs, papers) that drop headings/panels directly into .app-main. */
|
|
962
|
+
.ds-247420 .app-main > h1,
|
|
963
|
+
.ds-247420 .app-main > h2,
|
|
964
|
+
.ds-247420 .app-main > h3 { margin-top: 36px; margin-bottom: 12px; }
|
|
965
|
+
.ds-247420 .app-main > h1:first-child { margin-top: 8px; }
|
|
966
|
+
.ds-247420 .app-main > .panel,
|
|
967
|
+
.ds-247420 .app-main > .work-detail-chips,
|
|
968
|
+
.ds-247420 .app-main > .cli { margin-top: 18px; margin-bottom: 18px; }
|
|
969
|
+
.ds-247420 .app-main .ds-lede { margin-top: 4px; margin-bottom: 18px; max-width: 64ch; line-height: 1.6; }
|
|
970
|
+
.ds-247420 .work-detail-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; row-gap: 10px; }
|
|
971
|
+
@media (max-width: 720px) {
|
|
972
|
+
.ds-247420 .app-main > h1,
|
|
973
|
+
.ds-247420 .app-main > h2,
|
|
974
|
+
.ds-247420 .app-main > h3 { margin-top: 28px; }
|
|
975
|
+
}
|
|
954
976
|
|
|
955
977
|
@media (min-width: 1400px) {
|
|
956
978
|
/* Fluid ceiling, not a hard stop: scales from 1400px up to 1920px across the
|
|
@@ -2664,6 +2686,17 @@
|
|
|
2664
2686
|
@media (hover: none), (pointer: coarse) {
|
|
2665
2687
|
.ds-247420 .ds-modal-input { font-size: 16px; min-height: 44px; }
|
|
2666
2688
|
}
|
|
2689
|
+
/* PromptDialog's optional roots-chip row (destination-path prompts with more
|
|
2690
|
+
than one allowed root) - same chip idiom the cwd editor's roots row uses. */
|
|
2691
|
+
.ds-247420 .ds-prompt-roots { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
|
|
2692
|
+
.ds-247420 .ds-prompt-root-chip {
|
|
2693
|
+
background: var(--bg-2); border: var(--bw-hair) solid var(--rule); color: var(--fg-2);
|
|
2694
|
+
border-radius: var(--r-pill); padding: 3px 10px; font: inherit; font-size: var(--fs-tiny);
|
|
2695
|
+
cursor: pointer;
|
|
2696
|
+
}
|
|
2697
|
+
.ds-247420 .ds-prompt-root-chip:hover { border-color: var(--accent); color: var(--fg); }
|
|
2698
|
+
.ds-247420 .ds-prompt-root-chip:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
2699
|
+
@media (pointer: coarse) { .ds-247420 .ds-prompt-root-chip { min-height: 44px; } }
|
|
2667
2700
|
/* In-body modal error (role=alert): mutation failures (409/403) surface INSIDE
|
|
2668
2701
|
the dialog, not behind the fixed overlay. */
|
|
2669
2702
|
.ds-247420 .ds-modal-error {
|
|
@@ -7077,6 +7110,37 @@
|
|
|
7077
7110
|
.ds-247420 .agentchat-cwd-input[aria-invalid='true'] { border-color: var(--flame); box-shadow: inset 0 0 0 var(--bw-hair) var(--flame); }
|
|
7078
7111
|
.ds-247420 .agentchat-cwd-input[aria-busy='true'] { border-color: var(--fg-3); box-shadow: inset 0 0 0 var(--bw-hair) var(--fg-3); }
|
|
7079
7112
|
|
|
7113
|
+
/* cwd practicality upgrade: editing mode stacks the input row plus any
|
|
7114
|
+
optional roots/recent/browse rows the host wires, instead of a single flat
|
|
7115
|
+
row - each sub-row wraps independently at narrow widths. */
|
|
7116
|
+
.ds-247420 .agentchat-cwd-editing { flex-direction: column; align-items: stretch; }
|
|
7117
|
+
.ds-247420 .agentchat-cwd-row { display: flex; align-items: center; gap: var(--space-2, 8px); flex-wrap: wrap; }
|
|
7118
|
+
.ds-247420 .agentchat-cwd-roots, .ds-247420 .agentchat-cwd-recent {
|
|
7119
|
+
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
|
|
7120
|
+
}
|
|
7121
|
+
.ds-247420 .agentchat-cwd-recent-label { font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
7122
|
+
.ds-247420 .agentchat-cwd-chip {
|
|
7123
|
+
background: var(--bg-2); border: var(--bw-hair) solid var(--rule); color: var(--fg-2);
|
|
7124
|
+
border-radius: var(--r-pill); padding: 3px 10px; font: inherit; font-size: var(--fs-tiny);
|
|
7125
|
+
cursor: pointer;
|
|
7126
|
+
}
|
|
7127
|
+
.ds-247420 .agentchat-cwd-chip:hover { border-color: var(--accent); color: var(--fg); }
|
|
7128
|
+
.ds-247420 .agentchat-cwd-chip:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
7129
|
+
.ds-247420 .agentchat-cwd-browse {
|
|
7130
|
+
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
|
|
7131
|
+
padding: var(--space-2, 8px); background: var(--bg-2);
|
|
7132
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
7133
|
+
max-height: 220px;
|
|
7134
|
+
}
|
|
7135
|
+
.ds-247420 .agentchat-cwd-browse-list { overflow-y: auto; display: flex; flex-direction: column; max-height: 160px; }
|
|
7136
|
+
.ds-247420 .agentchat-cwd-browse-item {
|
|
7137
|
+
background: none; border: none; color: var(--fg-2); text-align: left;
|
|
7138
|
+
padding: 6px 8px; border-radius: var(--r-1); font: inherit; font-size: var(--fs-tiny);
|
|
7139
|
+
cursor: pointer;
|
|
7140
|
+
}
|
|
7141
|
+
.ds-247420 .agentchat-cwd-browse-item:hover, .ds-247420 .agentchat-cwd-browse-item:focus-visible { background: var(--bg-3, var(--bg)); color: var(--fg); }
|
|
7142
|
+
.ds-247420 .agentchat-cwd-browse-loading, .ds-247420 .agentchat-cwd-browse-empty { padding: 6px 8px; font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
7143
|
+
|
|
7080
7144
|
/* head + thread */
|
|
7081
7145
|
.ds-247420 .agentchat-head {
|
|
7082
7146
|
display: flex;
|
|
@@ -7277,7 +7341,7 @@
|
|
|
7277
7341
|
}
|
|
7278
7342
|
/* Coarse-pointer (touch): raise cwd button to 44px minimum tap target */
|
|
7279
7343
|
@media (pointer: coarse) {
|
|
7280
|
-
.ds-247420 .agentchat-cwd-btn { min-height: 44px; }
|
|
7344
|
+
.ds-247420 .agentchat-cwd-btn, .ds-247420 .agentchat-cwd-chip, .ds-247420 .agentchat-cwd-browse-item { min-height: 44px; }
|
|
7281
7345
|
}
|
|
7282
7346
|
|
|
7283
7347
|
/* ----------------------------------------------------------------------------
|
|
@@ -7363,7 +7427,7 @@
|
|
|
7363
7427
|
label sticks to the top of the scroll area for Claude-Desktop-style headers. */
|
|
7364
7428
|
.ds-247420 .ds-session-group { display: flex; flex-direction: column; }
|
|
7365
7429
|
.ds-247420 .ds-session-group-rows { display: flex; flex-direction: column; gap: 2px; }
|
|
7366
|
-
.ds-247420 .ds-session-group-label { position: sticky; top: 0; z-index: 1; background: var(--bg-1, var(--bg)); font-size: var(--fs-tiny); font-weight: 600; color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-
|
|
7430
|
+
.ds-247420 .ds-session-group-label { position: sticky; top: 0; z-index: 1; background: var(--bg-1, var(--bg)); font-size: var(--fs-tiny); font-weight: 600; color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-label); padding: var(--space-2) var(--space-2) var(--space-1); }
|
|
7367
7431
|
.ds-247420 .ds-session-row {
|
|
7368
7432
|
position: relative; display: flex; align-items: center; gap: var(--space-2);
|
|
7369
7433
|
width: 100%; padding: var(--space-2); min-height: 52px; margin-bottom: 2px;
|
|
@@ -7660,15 +7724,15 @@
|
|
|
7660
7724
|
.ds-247420 .ds-session-meta-item + .ds-session-meta-item::before { content: '\00B7'; color: var(--fg-3); margin-right: var(--space-1); }
|
|
7661
7725
|
.ds-247420 .ds-session-meta-label { color: var(--fg-3); }
|
|
7662
7726
|
.ds-247420 .ds-session-meta-value { font-family: var(--ff-mono); color: var(--fg-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
7663
|
-
.ds-247420 .ds-session-meta-copy {
|
|
7727
|
+
.ds-247420 .ds-session-meta-copy, .ds-247420 .ds-session-meta-action {
|
|
7664
7728
|
padding: 2px 8px; min-height: 24px; cursor: pointer;
|
|
7665
7729
|
background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1);
|
|
7666
7730
|
color: var(--fg-3); font-family: var(--ff-body); font-size: var(--fs-micro);
|
|
7667
7731
|
}
|
|
7668
|
-
.ds-247420 .ds-session-meta-copy:hover { background: var(--bg-3); color: var(--fg); }
|
|
7669
|
-
.ds-247420 .ds-session-meta-copy:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; }
|
|
7732
|
+
.ds-247420 .ds-session-meta-copy:hover, .ds-247420 .ds-session-meta-action:hover { background: var(--bg-3); color: var(--fg); }
|
|
7733
|
+
.ds-247420 .ds-session-meta-copy:focus-visible, .ds-247420 .ds-session-meta-action:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; }
|
|
7670
7734
|
@media (pointer: coarse), (max-width: 640px) {
|
|
7671
|
-
.ds-247420 .ds-session-meta-copy { min-height: 44px; min-width: 44px; }
|
|
7735
|
+
.ds-247420 .ds-session-meta-copy, .ds-247420 .ds-session-meta-action { min-height: 44px; min-width: 44px; }
|
|
7672
7736
|
}
|
|
7673
7737
|
|
|
7674
7738
|
/* ============================================================================
|
|
@@ -7917,7 +7981,7 @@
|
|
|
7917
7981
|
|
|
7918
7982
|
/* Live command-center: status-bucket groups + header breakdown + heartbeat. */
|
|
7919
7983
|
.ds-247420 .ds-dash-group { display: flex; flex-direction: column; gap: var(--space-2); }
|
|
7920
|
-
.ds-247420 .ds-dash-group-label { font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: var(--tr-
|
|
7984
|
+
.ds-247420 .ds-dash-group-label { font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--fg-3); padding: 0 var(--space-1); }
|
|
7921
7985
|
.ds-247420 .ds-dash-breakdown { display: flex; align-items: center; gap: var(--space-1); font-size: var(--fs-sm); color: var(--fg-2); }
|
|
7922
7986
|
/* Shape-channel discs mirror the .status-dot-disc vocabulary (solid /
|
|
7923
7987
|
solid+halo / hollow ring) so a colour-blind user can scan the breakdown by
|