agentgui 1.0.947 → 1.0.949
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-audit.js +86 -0
- package/AGENTS.md +29 -11
- package/docs/demo.html +27 -27
- package/lib/codec.js +1 -1
- package/lib/http-handler.js +31 -4
- package/lib/process-message.js +1 -1
- package/lib/stream-event-handler.js +3 -3
- package/lib/terminal.js +1 -1
- package/lib/ws-handlers-util.js +9 -0
- package/lib/ws-setup.js +1 -1
- package/package.json +2 -2
- package/scripts/build-rippleui.mjs +5 -5
- package/scripts/capture-screenshots.mjs +3 -3
- package/scripts/copy-vendor.js +1 -1
- package/scripts/harvest-fixtures.mjs +7 -7
- package/scripts/seed-large-conversation.js +2 -2
- package/scripts/smoke-ws-chat.mjs +2 -2
- package/server.js +1 -1
- package/site/app/index.html +25 -19
- package/site/app/js/app.js +224 -76
- package/site/app/js/backend.js +13 -9
- package/site/app/vendor/anentrypoint-design/247420.css +923 -46
- package/site/app/vendor/anentrypoint-design/247420.js +89 -42
- package/site/theme.mjs +1 -1
- package/test.js +27 -11
|
@@ -66,7 +66,7 @@ function det(prefix, ...seeds) {
|
|
|
66
66
|
return `${prefix}-${h.slice(0, 16)}`;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
// Anonymise
|
|
69
|
+
// Anonymise - returns cleaned text
|
|
70
70
|
function scrub(text) {
|
|
71
71
|
if (typeof text !== 'string') return text;
|
|
72
72
|
return text
|
|
@@ -87,8 +87,8 @@ function synthAssistant(title) {
|
|
|
87
87
|
`\`lib/db-queries.js\` to use the new column and patch the associated tests.\n\n` +
|
|
88
88
|
`The fix is a one-line change to the INSERT statement. All 19 tests pass now.`,
|
|
89
89
|
'Refactor auth middleware':
|
|
90
|
-
`The current auth middleware has three responsibilities
|
|
91
|
-
`and CORS
|
|
90
|
+
`The current auth middleware has three responsibilities - rate limiting, basic-auth check, ` +
|
|
91
|
+
`and CORS - packed into a single 80-line function. I'll split them into three small ` +
|
|
92
92
|
`middlewares in \`lib/http-middlewares/\` and compose them in \`http-handler.js\`. ` +
|
|
93
93
|
`No behaviour change, just readability.`,
|
|
94
94
|
'Add dark mode toggle':
|
|
@@ -109,13 +109,13 @@ function synthAssistant(title) {
|
|
|
109
109
|
`markdown doc grouped by module. Output goes to \`docs/api.md\`. I'll add a JSDoc-style comment ` +
|
|
110
110
|
`parser so handler descriptions can live inline with the route.`,
|
|
111
111
|
};
|
|
112
|
-
return lookup[title] || 'Done
|
|
112
|
+
return lookup[title] || 'Done - see the diff for details.';
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function synthUser(title) {
|
|
116
116
|
const lookup = {
|
|
117
117
|
'Fix failing tests in db-queries':
|
|
118
|
-
'Hey
|
|
118
|
+
'Hey - the test suite has been flaky since yesterday. Can you figure out which specs are failing and fix them? Start with `bun test` and work from there.',
|
|
119
119
|
'Refactor auth middleware':
|
|
120
120
|
`The auth middleware in lib/http-handler.js has grown into a monster. Please split it into single-responsibility pieces.`,
|
|
121
121
|
'Add dark mode toggle':
|
|
@@ -123,7 +123,7 @@ function synthUser(title) {
|
|
|
123
123
|
'Write migration for user schema':
|
|
124
124
|
`Add last_login_at and a preferences JSON column to the users table. Include a backfill for existing rows.`,
|
|
125
125
|
'Debug WebSocket reconnect loop':
|
|
126
|
-
`Clients are getting stuck in a reconnect loop
|
|
126
|
+
`Clients are getting stuck in a reconnect loop - the network tab shows two sockets opening before one closes. Can you trace it in ws-machine and fix?`,
|
|
127
127
|
'Generate API docs from handlers':
|
|
128
128
|
`We need API docs. Generate them from the route handler declarations and dump to docs/api.md.`,
|
|
129
129
|
};
|
|
@@ -171,7 +171,7 @@ function build() {
|
|
|
171
171
|
|
|
172
172
|
const db = openDb(OUT_DB);
|
|
173
173
|
|
|
174
|
-
// Use the real schema pipeline
|
|
174
|
+
// Use the real schema pipeline - same as database.js - so fixture DB always matches production.
|
|
175
175
|
initSchema(db);
|
|
176
176
|
migrateFromJson(db, path.join(OUT_DIR, 'nonexistent.json'));
|
|
177
177
|
migrateToACP(db);
|
|
@@ -61,7 +61,7 @@ console.error(`[seed] inserting conversation ${convId} with ${turns} turns, ${ch
|
|
|
61
61
|
db.run(
|
|
62
62
|
`INSERT INTO conversations (id, agentId, title, created_at, updated_at, status, agentType, workingDirectory, model)
|
|
63
63
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
64
|
-
[convId, 'cli-claude', `Profiling Seed
|
|
64
|
+
[convId, 'cli-claude', `Profiling Seed - ${turns} turns`, startTime, now, 'active', 'claude', '/home/user', 'claude-opus-4-6']
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
const insertMsg = db.prepare(
|
|
@@ -155,5 +155,5 @@ for (let i = 0; i < turns; i += BATCH) {
|
|
|
155
155
|
|
|
156
156
|
db.close();
|
|
157
157
|
process.stderr.write('\n');
|
|
158
|
-
console.error(`[seed] complete
|
|
158
|
+
console.error(`[seed] complete - ${totalChunks} total chunks for conv ${convId}`);
|
|
159
159
|
console.log(convId);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Smoke-test the WS chat protocol added in this session.
|
|
2
|
-
// Boots no server
|
|
2
|
+
// Boots no server - assumes one is already running at ws://localhost:$PORT/sync.
|
|
3
3
|
//
|
|
4
4
|
// Usage: PORT=3990 node scripts/smoke-ws-chat.mjs
|
|
5
5
|
//
|
|
@@ -43,7 +43,7 @@ ws.on('message', async (data) => {
|
|
|
43
43
|
console.log('sync_connected, clientId =', m.clientId);
|
|
44
44
|
try {
|
|
45
45
|
const r1 = await call('agents.list');
|
|
46
|
-
console.log('agents.list OK, count =', r1.agents.length, '
|
|
46
|
+
console.log('agents.list OK, count =', r1.agents.length, '- first =', r1.agents[0]?.id);
|
|
47
47
|
const r2 = await call('conversation.subscribe', { sessionId: 'smoke-test-sid' });
|
|
48
48
|
console.log('conversation.subscribe OK =', r2);
|
|
49
49
|
console.log('PASS');
|
package/server.js
CHANGED
|
@@ -179,7 +179,7 @@ server.on('error', (err) => {
|
|
|
179
179
|
if (err.code === 'EADDRINUSE') {
|
|
180
180
|
_portRetries++;
|
|
181
181
|
if (_portRetries > MAX_PORT_RETRIES) {
|
|
182
|
-
// Bail instead of retrying forever
|
|
182
|
+
// Bail instead of retrying forever - an unbounded retry loop leaks a
|
|
183
183
|
// live process that holds no useful port and accumulates on each launch.
|
|
184
184
|
console.error(`Port ${PORT} still in use after ${MAX_PORT_RETRIES} retries; exiting. Free the port or set PORT to a different value.`);
|
|
185
185
|
process.exit(1);
|
package/site/app/index.html
CHANGED
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<title>agentgui</title>
|
|
7
|
-
<meta name="description" content="agentgui
|
|
8
|
-
<!-- The GUI lives in the anentrypoint-design kit and is
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
<meta name="description" content="agentgui - multi-agent client with same-origin server, in-process ccsniff history, and ACP chat.">
|
|
8
|
+
<!-- The GUI lives in the anentrypoint-design kit and is vendored locally under
|
|
9
|
+
./vendor/anentrypoint-design so the shipped UI is PREDICTABLE: it does not
|
|
10
|
+
silently shift when the upstream package publishes, and it works offline
|
|
11
|
+
(the markdown stack still fetches marked/dompurify/prismjs on first chat
|
|
12
|
+
render). Update flow: edit the kit at c:\dev\anentrypoint-design, run
|
|
13
|
+
`node scripts/build.mjs`, copy dist/247420.{js,css} here, then publish the
|
|
14
|
+
kit so unpkg stays in sync. -->
|
|
15
|
+
<link rel="stylesheet" href="./vendor/anentrypoint-design/247420.css">
|
|
13
16
|
<script type="importmap">
|
|
14
|
-
{ "imports": { "anentrypoint-design": "
|
|
17
|
+
{ "imports": { "anentrypoint-design": "./vendor/anentrypoint-design/247420.js" } }
|
|
15
18
|
</script>
|
|
16
19
|
<style>
|
|
17
20
|
:root {
|
|
@@ -44,7 +47,7 @@
|
|
|
44
47
|
#app { height: 100vh; height: 100dvh; }
|
|
45
48
|
#app > * { height: 100%; }
|
|
46
49
|
|
|
47
|
-
/* Themed thin scrollbars
|
|
50
|
+
/* Themed thin scrollbars - the native chrome scrollbar is chunky/light and
|
|
48
51
|
clashes with the dark theme on the history sidebar and settings column. */
|
|
49
52
|
* {
|
|
50
53
|
scrollbar-width: thin;
|
|
@@ -70,16 +73,10 @@
|
|
|
70
73
|
.ds-247420 [data-prog-focus]:focus-visible,
|
|
71
74
|
[data-prog-focus]:focus, [data-prog-focus]:focus-visible { outline: none !important; box-shadow: none !important; }
|
|
72
75
|
|
|
73
|
-
/* skip link
|
|
74
|
-
|
|
75
|
-
position: absolute; left: -9999px; top: 0; z-index: 1000;
|
|
76
|
-
padding: .5em .9em; border-radius: 6px;
|
|
77
|
-
background: var(--accent, var(--agentgui-accent)); color: #06120a;
|
|
78
|
-
text-decoration: none; font-weight: 600;
|
|
79
|
-
}
|
|
80
|
-
.skip-link:focus { left: 8px; top: 8px; outline: 2px solid #fff; outline-offset: 2px; }
|
|
76
|
+
/* (The skip link is rendered + styled by the design system's AppShell;
|
|
77
|
+
agentgui carries no local .skip-link rule.) */
|
|
81
78
|
|
|
82
|
-
/* status connection dot
|
|
79
|
+
/* status connection dot - a CSS-drawn disc (real UI affordance, not a text
|
|
83
80
|
glyph). The .status-dot-disc child is always present; the parent's state
|
|
84
81
|
class colours it, and only is-live pulses. */
|
|
85
82
|
.status-dot { display: inline-flex; align-items: center; gap: .4em; white-space: nowrap; }
|
|
@@ -180,7 +177,7 @@
|
|
|
180
177
|
|
|
181
178
|
/* Topbar nav: the DS renders the active tab as a large filled green pill that
|
|
182
179
|
sits taller than the inactive text links and reads as misaligned. Make all
|
|
183
|
-
tabs consistent
|
|
180
|
+
tabs consistent - equal padding, the active one a subtle tinted underline-pill
|
|
184
181
|
rather than an oversized oval. */
|
|
185
182
|
/* Prefix with .ds-247420 (the <html> class) to match the DS selector's
|
|
186
183
|
specificity; source order then lets these win. */
|
|
@@ -249,7 +246,7 @@
|
|
|
249
246
|
.agentgui-main-settings .settings-grid { margin-top: 0; }
|
|
250
247
|
|
|
251
248
|
/* The DS Chat head computes its own zero-padded count ("00 msgs") and ignores
|
|
252
|
-
our sub prop; it reads as a bug. Hide the DS sub
|
|
249
|
+
our sub prop; it reads as a bug. Hide the DS sub - streaming state shows via
|
|
253
250
|
the title and the busy banner. Also hide the DS's empty decorative head dot. */
|
|
254
251
|
.chat-head .sub { display: none; }
|
|
255
252
|
.chat-head .dot { display: none; }
|
|
@@ -258,6 +255,15 @@
|
|
|
258
255
|
them a pointer cursor, so the affordance is invisible. */
|
|
259
256
|
.ds-event-list .row[role="button"] { cursor: pointer; }
|
|
260
257
|
.ds-event-list .row[role="button"]:hover { background: color-mix(in srgb, var(--fg, var(--agentgui-fg)) 5%, transparent); }
|
|
258
|
+
/* Flash the row a search result landed on, so the match is obvious. */
|
|
259
|
+
.ds-event-list .row.event-flash { animation: agentgui-event-flash 2s ease-out; }
|
|
260
|
+
@keyframes agentgui-event-flash {
|
|
261
|
+
0% { background: color-mix(in srgb, var(--accent, var(--agentgui-accent)) 40%, transparent); }
|
|
262
|
+
100% { background: transparent; }
|
|
263
|
+
}
|
|
264
|
+
@media (prefers-reduced-motion: reduce) {
|
|
265
|
+
.ds-event-list .row.event-flash { animation: none; outline: 2px solid var(--accent, var(--agentgui-accent)); }
|
|
266
|
+
}
|
|
261
267
|
|
|
262
268
|
/* Chat composer: hide the idle scrollbar on the (empty/short) textarea. */
|
|
263
269
|
.chat-composer textarea { overflow-y: auto; scrollbar-width: thin; }
|