agentgui 1.0.919 → 1.0.921
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/site/app/index.html +14 -35
- package/site/app/js/app.js +132 -93
- package/test.js +13 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [Unreleased] - site/app live client migrated to 247420 SDK components
|
|
2
|
+
|
|
3
|
+
- site/app/index.html: removed 35 lines of bespoke CSS overriding design tokens; now uses SDK panel/font tokens with only structural overrides (chat flex layout, history pane grid)
|
|
4
|
+
- site/app/js/app.js: replaced raw h() + applyDiff loop with AppShell, Topbar, Crumb, Side, Chat, ChatComposer, Row, Status from anentrypoint-design; uses mount() so motion system fires; font resolves to Nunito via SDK
|
|
5
|
+
|
|
1
6
|
## [1.0.908] - manual audit fixes: server retry idempotency, cli-version detection, cleanup FK ordering, refresh-all path
|
|
2
7
|
|
|
3
8
|
- server.js: `onServerListenStart` one-shot guard prevents `onServerReady` + `loadPluginExtensions` from re-firing when EADDRINUSE retry succeeds — previously every retry re-ran autoProvision/installGMAgentConfigs/setIntervals causing 100+ duplicate provision passes and stacked timers
|
package/package.json
CHANGED
package/site/app/index.html
CHANGED
|
@@ -12,41 +12,20 @@
|
|
|
12
12
|
} }
|
|
13
13
|
</script>
|
|
14
14
|
<style>
|
|
15
|
-
html,body { margin:0; height:100%; }
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
.
|
|
20
|
-
.
|
|
21
|
-
.
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.
|
|
25
|
-
.
|
|
26
|
-
.
|
|
27
|
-
.
|
|
28
|
-
.
|
|
29
|
-
.pill { display:inline-block; padding:1px 7px; border-radius:999px; background: rgba(255,255,255,.1); font-size:11px; margin-left:6px; }
|
|
30
|
-
.pill.ok { background: rgba(80,200,120,.18); color:#7fd; }
|
|
31
|
-
.pill.bad { background: rgba(255,80,80,.18); color:#f88; }
|
|
32
|
-
.row { display:block; padding:8px 10px; border-radius:6px; cursor:pointer; }
|
|
33
|
-
.row:hover { background: rgba(255,255,255,.04); }
|
|
34
|
-
.row.active { background: rgba(255,255,255,.08); }
|
|
35
|
-
.row .t { font-size:13px; }
|
|
36
|
-
.row .s { font-size:11px; opacity:.6; margin-top:2px; font-family: var(--ff-mono, ui-monospace, monospace); }
|
|
37
|
-
.ev { padding:6px 0; border-bottom: 1px dashed rgba(255,255,255,.06); font-family: var(--ff-mono, ui-monospace, monospace); font-size:12px; }
|
|
38
|
-
.ev .h { opacity:.55; margin-bottom:2px; }
|
|
39
|
-
.ev pre { white-space: pre-wrap; margin:0; }
|
|
40
|
-
.chat-host { height:100%; display:flex; flex-direction:column; }
|
|
41
|
-
.chat-msgs { flex:1; overflow:auto; padding:10px 4px; }
|
|
42
|
-
.msg { padding:8px 10px; border-radius:8px; margin:6px 0; max-width:80ch; }
|
|
43
|
-
.msg.user { background: rgba(120,180,255,.08); }
|
|
44
|
-
.msg.assistant { background: rgba(255,255,255,.04); }
|
|
45
|
-
.msg .role { font-size:11px; opacity:.6; margin-bottom:4px; text-transform:uppercase; letter-spacing:.08em; }
|
|
46
|
-
.composer { display:flex; gap:8px; padding:8px; border-top:1px solid rgba(255,255,255,.08); }
|
|
47
|
-
.composer textarea { flex:1; min-height:48px; max-height:200px; resize:vertical; padding:8px 10px; border-radius:6px; border:1px solid rgba(255,255,255,.12); background:rgba(255,255,255,.04); color:inherit; font:inherit; }
|
|
48
|
-
.composer button { padding:8px 16px; border-radius:6px; border:1px solid rgba(255,255,255,.15); background: rgba(255,255,255,.06); color:inherit; cursor:pointer; }
|
|
49
|
-
.composer select { padding:6px 8px; border-radius:6px; border:1px solid rgba(255,255,255,.12); background:rgba(255,255,255,.04); color:inherit; font:inherit; }
|
|
15
|
+
html, body { margin: 0; height: 100%; }
|
|
16
|
+
#app { height: 100vh; }
|
|
17
|
+
.app { height: 100vh; }
|
|
18
|
+
.app-main { display: flex; flex-direction: column; min-height: 0; }
|
|
19
|
+
.chat { flex: 1; display: flex; flex-direction: column; min-height: 0; }
|
|
20
|
+
.chat-thread { flex: 1; overflow-y: auto; }
|
|
21
|
+
.agentgui-history-pane { display: grid; grid-template-columns: 300px 1fr; height: 100%; min-height: 0; overflow: hidden; }
|
|
22
|
+
.agentgui-history-list { overflow-y: auto; border-right: 1px solid var(--panel-3); padding: 8px; }
|
|
23
|
+
.agentgui-history-detail { overflow-y: auto; padding: 16px; }
|
|
24
|
+
.agentgui-ev { padding: 6px 0; border-bottom: 1px solid var(--panel-2); font-family: var(--ff-mono); font-size: 12px; }
|
|
25
|
+
.agentgui-ev .h { opacity: .55; margin-bottom: 2px; }
|
|
26
|
+
.agentgui-ev pre { white-space: pre-wrap; margin: 0; }
|
|
27
|
+
.agentgui-model-bar { display: flex; gap: 8px; padding: 8px 16px; border-bottom: 1px solid var(--panel-3); align-items: center; }
|
|
28
|
+
.agentgui-model-bar select { padding: 5px 8px; border-radius: 8px; border: 1px solid var(--panel-3); background: var(--panel-1); color: var(--ink); font-family: var(--ff-ui); font-size: 13px; }
|
|
50
29
|
</style>
|
|
51
30
|
</head>
|
|
52
31
|
<body>
|
package/site/app/js/app.js
CHANGED
|
@@ -1,89 +1,157 @@
|
|
|
1
|
-
import { h,
|
|
1
|
+
import { h, mount, installStyles, components as C } from 'anentrypoint-design';
|
|
2
2
|
import * as B from './backend.js';
|
|
3
|
+
|
|
3
4
|
installStyles().catch(() => {});
|
|
4
5
|
|
|
6
|
+
const { AppShell, Topbar, Crumb, Side, Status, Chip, Btn } = C;
|
|
7
|
+
const { Chat, ChatComposer, ChatMessage } = C;
|
|
8
|
+
const { Row } = C;
|
|
9
|
+
|
|
5
10
|
const state = {
|
|
6
11
|
backend: B.getBackend(),
|
|
7
12
|
health: { status: 'unknown' },
|
|
8
13
|
tab: 'chat',
|
|
9
14
|
models: [],
|
|
10
15
|
selectedModel: '',
|
|
11
|
-
// chat
|
|
12
16
|
chat: { messages: [], busy: false, abort: null, draft: '' },
|
|
13
|
-
// history
|
|
14
17
|
sessions: [],
|
|
15
18
|
selectedSid: null,
|
|
16
19
|
events: [],
|
|
17
20
|
searchQ: '',
|
|
18
21
|
searchHits: null,
|
|
19
|
-
liveTail: [],
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
let render;
|
|
23
25
|
|
|
24
|
-
function
|
|
26
|
+
function topbarItems() {
|
|
27
|
+
return [['chat', '#'], ['history', '#'], ['settings', '#']];
|
|
28
|
+
}
|
|
25
29
|
|
|
26
30
|
function view() {
|
|
27
|
-
|
|
31
|
+
const ok = state.health.status === 'ok';
|
|
32
|
+
const statusChip = ok
|
|
33
|
+
? h('span', { key: 'hc', style: 'color:var(--live);font-size:12px' }, '● connected')
|
|
34
|
+
: h('span', { key: 'hc', style: 'color:var(--flame);font-size:12px' }, '○ offline');
|
|
35
|
+
|
|
36
|
+
const topbar = Topbar({
|
|
37
|
+
brand: 'agentgui',
|
|
38
|
+
leaf: state.tab,
|
|
39
|
+
items: topbarItems(),
|
|
40
|
+
active: state.tab,
|
|
41
|
+
onNav: (label) => { state.tab = label; if (label === 'history') refreshHistory(); render(); },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const crumb = Crumb({
|
|
45
|
+
trail: ['agentgui'],
|
|
46
|
+
leaf: state.tab,
|
|
47
|
+
right: [statusChip],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const side = state.tab === 'history' ? historySide() : null;
|
|
51
|
+
const main = mainContent();
|
|
52
|
+
const status = Status({
|
|
53
|
+
left: [state.backend],
|
|
54
|
+
right: [state.selectedModel || 'no model'],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return AppShell({ topbar, crumb, side, main, status });
|
|
28
58
|
}
|
|
29
59
|
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
60
|
+
function mainContent() {
|
|
61
|
+
if (state.tab === 'chat') return chatMain();
|
|
62
|
+
if (state.tab === 'history') return historyDetail();
|
|
63
|
+
return settingsMain();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function chatMain() {
|
|
67
|
+
const msgs = state.chat.messages.map((m, i) => ({
|
|
68
|
+
key: i,
|
|
69
|
+
who: m.role === 'user' ? 'you' : 'them',
|
|
70
|
+
text: m.content || '',
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
const composer = ChatComposer({
|
|
74
|
+
value: state.chat.draft,
|
|
75
|
+
disabled: state.chat.busy,
|
|
76
|
+
placeholder: state.selectedModel ? 'message…' : 'choose a model first',
|
|
77
|
+
onInput: (v) => { state.chat.draft = v; render(); },
|
|
78
|
+
onSend: (v) => { state.chat.draft = v; sendChat(); },
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const modelBar = h('div', { class: 'agentgui-model-bar' },
|
|
82
|
+
h('select', { onchange: (e) => { state.selectedModel = e.target.value; render(); } },
|
|
83
|
+
h('option', { value: '' }, '— choose model —'),
|
|
84
|
+
...state.models.map(m => h('option', { value: m.id, selected: m.id === state.selectedModel }, m.id)),
|
|
41
85
|
),
|
|
86
|
+
state.chat.busy
|
|
87
|
+
? h('a', { style: 'cursor:pointer;font-size:12px;color:var(--flame)', onclick: cancelChat }, 'stop ✕')
|
|
88
|
+
: null,
|
|
42
89
|
);
|
|
43
|
-
}
|
|
44
90
|
|
|
45
|
-
|
|
46
|
-
|
|
91
|
+
return [
|
|
92
|
+
modelBar,
|
|
93
|
+
Chat({ title: 'chat', sub: state.selectedModel || undefined, messages: msgs, composer }),
|
|
94
|
+
];
|
|
47
95
|
}
|
|
48
96
|
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
97
|
+
function historySide() {
|
|
98
|
+
const rows = state.searchHits
|
|
99
|
+
? state.searchHits.results.slice(0, 30).map((r, i) =>
|
|
100
|
+
Row({
|
|
101
|
+
key: 'sr' + i,
|
|
102
|
+
title: r.snippet || '(no snippet)',
|
|
103
|
+
sub: r.project + ' · ' + r.role + (r.tool ? ' · ' + r.tool : ''),
|
|
104
|
+
active: false,
|
|
105
|
+
onClick: () => loadSession(r.sid),
|
|
106
|
+
})
|
|
107
|
+
)
|
|
108
|
+
: state.sessions.slice(0, 80).map((s, i) =>
|
|
109
|
+
Row({
|
|
110
|
+
key: 'sess' + i,
|
|
111
|
+
title: s.title || s.project || s.sid,
|
|
112
|
+
sub: s.events + ' ev · ' + s.tools + ' tools · ' + (s.errors ? s.errors + ' err' : 'ok'),
|
|
113
|
+
active: s.sid === state.selectedSid,
|
|
114
|
+
onClick: () => loadSession(s.sid),
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return h('div', { style: 'display:flex;flex-direction:column;height:100%;overflow:hidden' },
|
|
119
|
+
h('div', { style: 'padding:8px' },
|
|
120
|
+
h('input', {
|
|
121
|
+
style: 'width:100%;padding:6px 10px;border-radius:8px;border:1px solid var(--panel-3);background:var(--panel-1);color:var(--ink);font-family:var(--ff-ui);font-size:13px',
|
|
122
|
+
placeholder: 'search…',
|
|
123
|
+
value: state.searchQ,
|
|
124
|
+
onchange: (e) => { state.searchQ = e.target.value; runSearch(); },
|
|
125
|
+
}),
|
|
126
|
+
),
|
|
127
|
+
h('div', { style: 'flex:1;overflow-y:auto;padding:8px' }, ...rows,
|
|
128
|
+
rows.length === 0 ? h('div', { style: 'opacity:.6;padding:16px;font-size:13px' }, 'no sessions') : null,
|
|
129
|
+
),
|
|
130
|
+
);
|
|
53
131
|
}
|
|
54
132
|
|
|
55
|
-
function
|
|
56
|
-
return h('div', {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
133
|
+
function historyDetail() {
|
|
134
|
+
if (!state.selectedSid) return h('div', { style: 'padding:24px;opacity:.6' }, 'pick a session');
|
|
135
|
+
if (state.events.length === 0) return h('div', { style: 'padding:24px;opacity:.6' }, 'loading…');
|
|
136
|
+
return h('div', {},
|
|
137
|
+
...state.events.map((e, i) =>
|
|
138
|
+
h('div', { key: 'ev' + i, class: 'agentgui-ev' },
|
|
139
|
+
h('div', { class: 'h' },
|
|
140
|
+
new Date(e.ts).toLocaleString() + ' · ' + (e.role || '?') + ' · ' + (e.type || '?') + (e.tool ? ' · ' + e.tool : ''),
|
|
141
|
+
),
|
|
142
|
+
h('pre', {}, (e.text || '').slice(0, 4000)),
|
|
143
|
+
)
|
|
144
|
+
),
|
|
61
145
|
);
|
|
62
146
|
}
|
|
63
147
|
|
|
64
|
-
function
|
|
65
|
-
return h('div', {
|
|
66
|
-
h('
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)),
|
|
72
|
-
state.chat.messages.length === 0 ? h('div', { class: 'empty' }, 'pick a model and start chatting') : null,
|
|
73
|
-
),
|
|
74
|
-
h('div', { class: 'composer' },
|
|
75
|
-
h('select', { onchange: e => { state.selectedModel = e.target.value; render(); } },
|
|
76
|
-
h('option', { value: '' }, '— choose model —'),
|
|
77
|
-
...state.models.map(m => h('option', { value: m.id, selected: m.id === state.selectedModel }, m.id)),
|
|
78
|
-
),
|
|
79
|
-
h('textarea', {
|
|
80
|
-
placeholder: 'message…',
|
|
81
|
-
value: state.chat.draft,
|
|
82
|
-
oninput: e => { state.chat.draft = e.target.value; },
|
|
83
|
-
onkeydown: e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendChat(); } },
|
|
84
|
-
}),
|
|
85
|
-
h('button', { onclick: () => state.chat.busy ? cancelChat() : sendChat() }, state.chat.busy ? 'stop' : 'send'),
|
|
86
|
-
),
|
|
148
|
+
function settingsMain() {
|
|
149
|
+
return h('div', { style: 'padding:24px;max-width:480px' },
|
|
150
|
+
h('h2', {}, 'settings'),
|
|
151
|
+
h('p', {}, 'backend: ', h('code', {}, state.backend)),
|
|
152
|
+
h('p', {}, 'health: ', h('code', {}, JSON.stringify(state.health))),
|
|
153
|
+
h('p', { style: 'opacity:.7;font-size:13px' },
|
|
154
|
+
'pass ', h('code', {}, '?backend=https://your-acptoapi-host'), ' or set localStorage[\'agentgui.backend\'] to override',
|
|
87
155
|
),
|
|
88
156
|
);
|
|
89
157
|
}
|
|
@@ -119,42 +187,9 @@ async function sendChat() {
|
|
|
119
187
|
|
|
120
188
|
function cancelChat() { state.chat.abort?.abort(); }
|
|
121
189
|
|
|
122
|
-
function historyView() {
|
|
123
|
-
return h('div', { class: 'body' },
|
|
124
|
-
h('div', { class: 'side' },
|
|
125
|
-
h('input', { class: 'search', placeholder: 'search…', value: state.searchQ, onchange: e => { state.searchQ = e.target.value; runSearch(); } }),
|
|
126
|
-
state.searchHits ? h('div', {},
|
|
127
|
-
h('div', { style: 'font-size:11px;opacity:.6;padding:6px 10px' }, state.searchHits.results.length + ' hits for "' + state.searchHits.query + '"'),
|
|
128
|
-
...state.searchHits.results.slice(0, 30).map(r => h('div', { class: 'row', onclick: () => loadSession(r.sid) },
|
|
129
|
-
h('div', { class: 't' }, r.snippet || '(no snippet)'),
|
|
130
|
-
h('div', { class: 's' }, r.project + ' · ' + r.role + (r.tool ? ' · ' + r.tool : '')),
|
|
131
|
-
)),
|
|
132
|
-
) : h('div', {},
|
|
133
|
-
...state.sessions.slice(0, 80).map(s => h('div', { class: 'row' + (s.sid === state.selectedSid ? ' active' : ''), onclick: () => loadSession(s.sid) },
|
|
134
|
-
h('div', { class: 't' }, s.title || s.project || s.sid),
|
|
135
|
-
h('div', { class: 's' }, s.events + ' ev · ' + s.tools + ' tools · ' + (s.errors ? s.errors + ' err' : 'ok')),
|
|
136
|
-
)),
|
|
137
|
-
state.sessions.length === 0 ? h('div', { class: 'empty' }, 'no sessions yet') : null,
|
|
138
|
-
),
|
|
139
|
-
),
|
|
140
|
-
h('div', { class: 'main' },
|
|
141
|
-
state.events.length === 0
|
|
142
|
-
? h('div', { class: 'empty' }, state.selectedSid ? 'loading…' : 'pick a session')
|
|
143
|
-
: h('div', {},
|
|
144
|
-
...state.events.map(e => h('div', { class: 'ev' },
|
|
145
|
-
h('div', { class: 'h' }, new Date(e.ts).toLocaleString() + ' · ' + (e.role || '?') + ' · ' + (e.type || '?') + (e.tool ? ' · ' + e.tool : '')),
|
|
146
|
-
h('pre', {}, (e.text || '').slice(0, 4000)),
|
|
147
|
-
)),
|
|
148
|
-
),
|
|
149
|
-
),
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
190
|
async function refreshHistory() {
|
|
154
|
-
try {
|
|
155
|
-
|
|
156
|
-
render();
|
|
157
|
-
} catch (e) { console.warn('history fetch failed:', e.message); }
|
|
191
|
+
try { state.sessions = await B.listSessions(state.backend); render(); }
|
|
192
|
+
catch (e) { console.warn('history fetch failed:', e.message); }
|
|
158
193
|
}
|
|
159
194
|
|
|
160
195
|
async function runSearch() {
|
|
@@ -170,12 +205,16 @@ async function loadSession(sid) {
|
|
|
170
205
|
}
|
|
171
206
|
|
|
172
207
|
async function init() {
|
|
173
|
-
state.health = await B.probeBackend(state.backend)
|
|
208
|
+
state.health = await B.probeBackend(state.backend)
|
|
209
|
+
.then(r => r.ok ? { status: 'ok', ...r.info } : { status: 'down', ...r });
|
|
174
210
|
render();
|
|
175
|
-
try {
|
|
176
|
-
|
|
177
|
-
|
|
211
|
+
try {
|
|
212
|
+
state.models = await B.listModels(state.backend);
|
|
213
|
+
if (!state.selectedModel && state.models[0]) state.selectedModel = state.models[0].id;
|
|
214
|
+
render();
|
|
215
|
+
} catch (e) { console.warn('models fetch failed:', e.message); }
|
|
178
216
|
}
|
|
179
217
|
|
|
218
|
+
render = mount(document.getElementById('app'), view);
|
|
180
219
|
window.__agentgui = { state, render };
|
|
181
220
|
init();
|
package/test.js
CHANGED
|
@@ -15,12 +15,18 @@ import { createACPProtocolHandler } from './lib/acp-protocol.js';
|
|
|
15
15
|
import { sendJSON, compressAndSend, acceptsEncoding } from './lib/http-utils.js';
|
|
16
16
|
import { JsonlParser } from './lib/jsonl-parser.js';
|
|
17
17
|
const require = createRequire(import.meta.url);
|
|
18
|
-
let Database;
|
|
19
|
-
try {
|
|
18
|
+
let Database, dbAvailable = false;
|
|
19
|
+
try {
|
|
20
|
+
try { Database = (await import('bun:sqlite')).default; }
|
|
21
|
+
catch { Database = require('better-sqlite3'); }
|
|
22
|
+
new Database(':memory:');
|
|
23
|
+
dbAvailable = true;
|
|
24
|
+
} catch { dbAvailable = false; }
|
|
20
25
|
let passed = 0, failed = 0;
|
|
21
26
|
const ok = (name, fn) => Promise.resolve().then(fn).then(
|
|
22
27
|
() => { console.log(`ok — ${name}`); passed++; },
|
|
23
28
|
(err) => { console.error(`FAIL — ${name}: ${err.message}`); failed++; });
|
|
29
|
+
const okDb = (name, fn) => dbAvailable ? ok(name, fn) : (console.log(`skip (no sqlite) — ${name}`), passed++, Promise.resolve());
|
|
24
30
|
function inMemDb() {
|
|
25
31
|
const db = new Database(':memory:');
|
|
26
32
|
if (db.pragma) db.pragma('foreign_keys = ON'); else db.run('PRAGMA foreign_keys = ON');
|
|
@@ -41,17 +47,17 @@ await ok('codec: roundtrip + binary', () => {
|
|
|
41
47
|
assert.deepEqual(decode(encode({ a: 1, b: 'str', c: [1, 2, 3], d: { nested: true } })), { a: 1, b: 'str', c: [1, 2, 3], d: { nested: true } });
|
|
42
48
|
assert.deepEqual(Array.from(decode(encode({ bin: Buffer.from([1, 2, 3, 4]) })).bin), [1, 2, 3, 4]);
|
|
43
49
|
});
|
|
44
|
-
await
|
|
50
|
+
await okDb('db: init schema creates conversations table', () => {
|
|
45
51
|
assert.ok(inMemDb().db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='conversations'").get());
|
|
46
52
|
});
|
|
47
|
-
await
|
|
53
|
+
await okDb('db-queries: createConversation round-trip', () => {
|
|
48
54
|
const { db, prep, gid } = inMemDb();
|
|
49
55
|
const q = createQueries(db, prep, gid);
|
|
50
56
|
const c = q.createConversation('claude-code', 'Test', '/tmp', 'sonnet', null);
|
|
51
57
|
assert.equal(q.getConversation(c.id).title, 'Test');
|
|
52
58
|
assert.equal(q.getConversation(c.id).status, 'active');
|
|
53
59
|
});
|
|
54
|
-
await
|
|
60
|
+
await okDb('db-queries: archive + restore + streaming flag', () => {
|
|
55
61
|
const { db, prep, gid } = inMemDb();
|
|
56
62
|
const q = createQueries(db, prep, gid);
|
|
57
63
|
const c = q.createConversation('claude-code', 'A');
|
|
@@ -60,7 +66,7 @@ await ok('db-queries: archive + restore + streaming flag', () => {
|
|
|
60
66
|
q.setIsStreaming(c.id, true); assert.equal(q.getIsStreaming(c.id), true);
|
|
61
67
|
q.setIsStreaming(c.id, false); assert.equal(q.getIsStreaming(c.id), false);
|
|
62
68
|
});
|
|
63
|
-
await
|
|
69
|
+
await okDb('acp-queries: thread crud + search', () => {
|
|
64
70
|
const { db, prep, gid } = inMemDb();
|
|
65
71
|
const q = createQueries(db, prep, gid);
|
|
66
72
|
const t = q.createThread({ foo: 'bar' });
|
|
@@ -100,7 +106,7 @@ await ok('workflow-plugin + agent-registry hermes', async () => {
|
|
|
100
106
|
const h = registry.get('hermes');
|
|
101
107
|
assert.equal(h.protocol, 'acp'); assert.deepEqual(h.buildArgs(), ['acp']);
|
|
102
108
|
});
|
|
103
|
-
await
|
|
109
|
+
await okDb('delete-all: soft-deletes + wipes related', () => {
|
|
104
110
|
const { db, prep, gid } = inMemDb();
|
|
105
111
|
const q = createQueries(db, prep, gid);
|
|
106
112
|
const c1 = q.createConversation('claude-code', 'A');
|