agentgui 1.0.927 → 1.0.929

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/AGENTS.md CHANGED
@@ -104,3 +104,13 @@ Paired changes:
104
104
  - better-sqlite3 bumped ^12.6.2 → ^12.9.0
105
105
 
106
106
  bun start was already working (bun has native sqlite support via `bun:sqlite`). The node path was broken due to the missing native binding. Only compile from source fixes the node path.
107
+
108
+ ## webjsx applyDiff Array Keying (2026-05-04)
109
+
110
+ **Children arrays that mix keyed VElements with raw text/numbers crash in `vendor/webjsx/applyDiff.js`.**
111
+
112
+ `webjsx` requires all siblings in an array prop (children, right, left, breadcrumbs, etc.) to either ALL be VElements with keys or ALL be non-keyed. Passing `Crumb({ right: [h('span', { key: 'a' }, 'A'), h('span', { key: 'b' }, 'B'), '● connected'] })` crashes on render with `TypeError: Cannot read properties of undefined (reading 'key')` at line 247420.js when the render loop tries to read `.key` on the bare string.
113
+
114
+ Fix: wrap any bare strings as keyed VElements: `h('span', { key: 'dot' }, '● connected')`. Rule: if ANY sibling in an array has a key, ALL siblings must be VElements (no raw strings or numbers).
115
+
116
+ Surfaced 2026-05-04 while validating the chat surface in `site/app/`. Fix applied to crumbRight construction in `site/app/js/app.js` view().
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.927",
3
+ "version": "1.0.929",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -35,7 +35,7 @@ function navTo(tab) {
35
35
 
36
36
  function view() {
37
37
  const ok = state.health.status === 'ok';
38
- const dot = ok ? '● connected' : '○ offline';
38
+ const dot = h('span', { key: 'dot' }, ok ? '● connected' : '○ offline');
39
39
 
40
40
  const topbar = Topbar({
41
41
  brand: 'agentgui',
@@ -45,10 +45,28 @@ function view() {
45
45
  onNav: (label) => navTo(label),
46
46
  });
47
47
 
48
+ const crumbRight = state.tab === 'chat'
49
+ ? [
50
+ h('select', {
51
+ key: 'modelsel',
52
+ onchange: (e) => { state.selectedModel = e.target.value; render(); },
53
+ },
54
+ h('option', { key: '__', value: '' }, '— model —'),
55
+ ...state.models.map(m =>
56
+ h('option', { key: m.id, value: m.id, selected: m.id === state.selectedModel }, m.id)
57
+ ),
58
+ ),
59
+ state.chat.busy
60
+ ? h('a', { key: 'stop', onclick: cancelChat, style: 'cursor:pointer' }, '◼ stop')
61
+ : h('a', { key: 'new', onclick: newChat, style: 'cursor:pointer' }, '+ new'),
62
+ dot,
63
+ ]
64
+ : [dot];
65
+
48
66
  const crumb = Crumb({
49
67
  trail: ['agentgui'],
50
68
  leaf: state.tab,
51
- right: [dot],
69
+ right: crumbRight,
52
70
  });
53
71
 
54
72
  const navSide = Side({
@@ -92,26 +110,6 @@ function chatMain() {
92
110
  parts: [{ kind: 'text', text: m.content || '' }],
93
111
  }));
94
112
 
95
- const modelPanel = Panel({
96
- title: 'model',
97
- children: h('div', { class: 'ds-section' },
98
- h('select', {
99
- value: state.selectedModel,
100
- onchange: (e) => { state.selectedModel = e.target.value; render(); },
101
- },
102
- h('option', { value: '' }, '— choose model —'),
103
- ...state.models.map(m =>
104
- h('option', { value: m.id, selected: m.id === state.selectedModel }, m.id)
105
- ),
106
- ),
107
- h('p', { class: 'lede' },
108
- state.chat.busy
109
- ? h('button', { onclick: cancelChat }, '◼ stop')
110
- : h('button', { onclick: newChat }, '+ new chat'),
111
- ),
112
- ),
113
- });
114
-
115
113
  const composer = ChatComposer({
116
114
  value: state.chat.draft,
117
115
  disabled: state.chat.busy,
@@ -121,21 +119,12 @@ function chatMain() {
121
119
  });
122
120
 
123
121
  return [
124
- h('div', { class: 'ds-section' },
125
- h('h1', {}, '# ' + (state.selectedModel || 'agent')),
126
- h('p', { class: 'lede' },
127
- state.chat.messages.length
128
- ? state.chat.messages.length + ' messages in this thread'
129
- : 'start a conversation with the selected model.',
130
- ),
131
- modelPanel,
132
- Chat({
133
- title: state.selectedModel || 'agent',
134
- sub: state.chat.busy ? 'streaming…' : (state.chat.messages.length + ' messages'),
135
- messages: msgs,
136
- composer,
137
- }),
138
- ),
122
+ Chat({
123
+ title: state.selectedModel || 'agent',
124
+ sub: state.chat.busy ? 'streaming…' : (state.chat.messages.length + ' messages'),
125
+ messages: msgs,
126
+ composer,
127
+ }),
139
128
  ];
140
129
  }
141
130