stableclaw 2026.5.2 → 2026.5.3

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.
Files changed (46) hide show
  1. package/dist/.buildstamp +1 -1
  2. package/dist/control-ui/apple-touch-icon.png +0 -0
  3. package/dist/control-ui/assets/agents-DIJiVfPj.js +813 -0
  4. package/dist/control-ui/assets/anthropic-BnQLajET.js +37 -0
  5. package/dist/control-ui/assets/azure-openai-responses-D6oH5P8v.js +2 -0
  6. package/dist/control-ui/assets/channel-config-extras-Cu8rP5sC.js +2 -0
  7. package/dist/control-ui/assets/channels-DMte0OdA.js +349 -0
  8. package/dist/control-ui/assets/cron-hM6tj-cg.js +928 -0
  9. package/dist/control-ui/assets/de-BzA7Smom.js +2 -0
  10. package/dist/control-ui/assets/debug-ChdgbieB.js +94 -0
  11. package/dist/control-ui/assets/directive-C6NBp6xJ.js +2 -0
  12. package/dist/control-ui/assets/es--sAce87o.js +2 -0
  13. package/dist/control-ui/assets/event-stream-B8X6sYaV.js +2 -0
  14. package/dist/control-ui/assets/format-nUIQxx1z.js +2 -0
  15. package/dist/control-ui/assets/github-copilot-headers-cUjskhp6.js +2 -0
  16. package/dist/control-ui/assets/google-DDYMjR2f.js +2 -0
  17. package/dist/control-ui/assets/google-gemini-cli-BBZpF1Bz.js +3 -0
  18. package/dist/control-ui/assets/google-shared-Brxly9jR.js +12 -0
  19. package/dist/control-ui/assets/google-vertex-moPkJqQt.js +2 -0
  20. package/dist/control-ui/assets/hash-BN8UQrrC.js +2 -0
  21. package/dist/control-ui/assets/index-DOMg2RvO.css +1 -0
  22. package/dist/control-ui/assets/index-hSu8pNmQ.js +4841 -0
  23. package/dist/control-ui/assets/instances-BO-5LU4G.js +57 -0
  24. package/dist/control-ui/assets/lit-zdTgzAJI.js +3 -0
  25. package/dist/control-ui/assets/logs-CaFT90eM.js +74 -0
  26. package/dist/control-ui/assets/mistral-yMnz8nsP.js +8 -0
  27. package/dist/control-ui/assets/nodes-6XxETMb5.js +430 -0
  28. package/dist/control-ui/assets/openai-CQsomflW.js +17 -0
  29. package/dist/control-ui/assets/openai-codex-responses-DXqDuiSK.js +8 -0
  30. package/dist/control-ui/assets/openai-completions-Bme8q7yw.js +6 -0
  31. package/dist/control-ui/assets/openai-responses-DpESo9k8.js +2 -0
  32. package/dist/control-ui/assets/openai-responses-shared-CjacPL_h.js +11 -0
  33. package/dist/control-ui/assets/preload-helper-xBbMyY7u.js +1 -0
  34. package/dist/control-ui/assets/preview-Ca6p7-4-.js +2 -0
  35. package/dist/control-ui/assets/pt-BR-DkjnRLn3.js +2 -0
  36. package/dist/control-ui/assets/sessions-USutdtjY.js +236 -0
  37. package/dist/control-ui/assets/skills-DLY8KTEh.js +216 -0
  38. package/dist/control-ui/assets/skills-shared-DUfo2UBp.js +11 -0
  39. package/dist/control-ui/assets/transform-messages-Lu1Q3cQf.js +2 -0
  40. package/dist/control-ui/assets/zh-CN-Di7IMlSu.js +2 -0
  41. package/dist/control-ui/assets/zh-TW-yENTnmx1.js +2 -0
  42. package/dist/control-ui/favicon-32.png +0 -0
  43. package/dist/control-ui/favicon.ico +0 -0
  44. package/dist/control-ui/favicon.svg +66 -0
  45. package/dist/control-ui/index.html +75 -0
  46. package/package.json +1 -1
@@ -0,0 +1,430 @@
1
+ import{i as e,n as t}from"./lit-zdTgzAJI.js";import{l as n,r,t as i}from"./format-nUIQxx1z.js";function a(e){let t=e?.agents??{},n=Array.isArray(t.list)?t.list:[],r=[];return n.forEach((e,t)=>{if(!e||typeof e!=`object`)return;let n=e,i=typeof n.id==`string`?n.id.trim():``;if(!i)return;let a=typeof n.name==`string`?n.name.trim():void 0,o=n.default===!0;r.push({id:i,name:a||void 0,isDefault:o,index:t,record:n})}),r}function o(e,t){let n=new Set(t),r=[];for(let t of e){if(!(Array.isArray(t.commands)?t.commands:[]).some(e=>n.has(String(e))))continue;let e=typeof t.nodeId==`string`?t.nodeId.trim():``;if(!e)continue;let i=typeof t.displayName==`string`&&t.displayName.trim()?t.displayName.trim():e;r.push({id:e,label:i===e?e:`${i} · ${e}`})}return r.sort((e,t)=>e.label.localeCompare(t.label)),r}var s=`__defaults__`,c=[{value:`deny`,label:`Deny`},{value:`allowlist`,label:`Allowlist`},{value:`full`,label:`Full`}],l=[{value:`off`,label:`Off`},{value:`on-miss`,label:`On miss`},{value:`always`,label:`Always`}];function u(e){return e===`allowlist`||e===`full`||e===`deny`?e:`deny`}function d(e){return e===`always`||e===`off`||e===`on-miss`?e:`on-miss`}function f(e){let t=e?.defaults??{};return{security:u(t.security),ask:d(t.ask),askFallback:u(t.askFallback??`deny`),autoAllowSkills:!!(t.autoAllowSkills??!1)}}function p(e){return a(e).map(e=>({id:e.id,name:e.name,isDefault:e.isDefault}))}function m(e,t){let n=p(e),r=Object.keys(t?.agents??{}),i=new Map;n.forEach(e=>i.set(e.id,e)),r.forEach(e=>{i.has(e)||i.set(e,{id:e})});let a=Array.from(i.values());return a.length===0&&a.push({id:`main`,isDefault:!0}),a.sort((e,t)=>{if(e.isDefault&&!t.isDefault)return-1;if(!e.isDefault&&t.isDefault)return 1;let n=e.name?.trim()?e.name:e.id,r=t.name?.trim()?t.name:t.id;return n.localeCompare(r)}),a}function h(e,t){return e===s?s:e&&t.some(t=>t.id===e)?e:s}function g(e){let t=e.execApprovalsForm??e.execApprovalsSnapshot?.file??null,n=!!t,r=f(t),i=m(e.configForm,t),a=C(e.nodes),o=e.execApprovalsTarget,c=o===`node`&&e.execApprovalsTargetNodeId?e.execApprovalsTargetNodeId:null;o===`node`&&c&&!a.some(e=>e.id===c)&&(c=null);let l=h(e.execApprovalsSelectedAgent,i),u=l===s?null:(t?.agents??{})[l]??null,d=Array.isArray(u?.allowlist)?u.allowlist??[]:[];return{ready:n,disabled:e.execApprovalsSaving||e.execApprovalsLoading,dirty:e.execApprovalsDirty,loading:e.execApprovalsLoading,saving:e.execApprovalsSaving,form:t,defaults:r,selectedScope:l,selectedAgent:u,agents:i,allowlist:d,target:o,targetNodeId:c,targetNodes:a,onSelectScope:e.onExecApprovalsSelectAgent,onSelectTarget:e.onExecApprovalsTargetChange,onPatch:e.onExecApprovalsPatch,onRemove:e.onExecApprovalsRemove,onLoad:e.onLoadExecApprovals,onSave:e.onSaveExecApprovals}}function _(n){let r=n.ready,i=n.target!==`node`||!!n.targetNodeId;return e`
2
+ <section class="card">
3
+ <div class="row" style="justify-content: space-between; align-items: center;">
4
+ <div>
5
+ <div class="card-title">Exec approvals</div>
6
+ <div class="card-sub">
7
+ Allowlist and approval policy for <span class="mono">exec host=gateway/node</span>.
8
+ </div>
9
+ </div>
10
+ <button
11
+ class="btn"
12
+ ?disabled=${n.disabled||!n.dirty||!i}
13
+ @click=${n.onSave}
14
+ >
15
+ ${n.saving?`Saving…`:`Save`}
16
+ </button>
17
+ </div>
18
+
19
+ ${v(n)}
20
+ ${r?e`
21
+ ${y(n)} ${b(n)}
22
+ ${n.selectedScope===s?t:x(n)}
23
+ `:e`<div class="row" style="margin-top: 12px; gap: 12px;">
24
+ <div class="muted">Load exec approvals to edit allowlists.</div>
25
+ <button class="btn" ?disabled=${n.loading||!i} @click=${n.onLoad}>
26
+ ${n.loading?`Loading…`:`Load approvals`}
27
+ </button>
28
+ </div>`}
29
+ </section>
30
+ `}function v(n){let r=n.targetNodes.length>0,i=n.targetNodeId??``;return e`
31
+ <div class="list" style="margin-top: 12px;">
32
+ <div class="list-item">
33
+ <div class="list-main">
34
+ <div class="list-title">Target</div>
35
+ <div class="list-sub">Gateway edits local approvals; node edits the selected node.</div>
36
+ </div>
37
+ <div class="list-meta">
38
+ <label class="field">
39
+ <span>Host</span>
40
+ <select
41
+ ?disabled=${n.disabled}
42
+ @change=${e=>{if(e.target.value===`node`){let e=n.targetNodes[0]?.id??null;n.onSelectTarget(`node`,i||e)}else n.onSelectTarget(`gateway`,null)}}
43
+ >
44
+ <option value="gateway" ?selected=${n.target===`gateway`}>Gateway</option>
45
+ <option value="node" ?selected=${n.target===`node`}>Node</option>
46
+ </select>
47
+ </label>
48
+ ${n.target===`node`?e`
49
+ <label class="field">
50
+ <span>Node</span>
51
+ <select
52
+ ?disabled=${n.disabled||!r}
53
+ @change=${e=>{let t=e.target.value.trim();n.onSelectTarget(`node`,t||null)}}
54
+ >
55
+ <option value="" ?selected=${i===``}>Select node</option>
56
+ ${n.targetNodes.map(t=>e`<option value=${t.id} ?selected=${i===t.id}>
57
+ ${t.label}
58
+ </option>`)}
59
+ </select>
60
+ </label>
61
+ `:t}
62
+ </div>
63
+ </div>
64
+ ${n.target===`node`&&!r?e` <div class="muted">No nodes advertise exec approvals yet.</div> `:t}
65
+ </div>
66
+ `}function y(t){return e`
67
+ <div class="row" style="margin-top: 12px; gap: 8px; flex-wrap: wrap;">
68
+ <span class="label">Scope</span>
69
+ <div class="row" style="gap: 8px; flex-wrap: wrap;">
70
+ <button
71
+ class="btn btn--sm ${t.selectedScope===s?`active`:``}"
72
+ @click=${()=>t.onSelectScope(s)}
73
+ >
74
+ Defaults
75
+ </button>
76
+ ${t.agents.map(n=>{let r=n.name?.trim()?`${n.name} (${n.id})`:n.id;return e`
77
+ <button
78
+ class="btn btn--sm ${t.selectedScope===n.id?`active`:``}"
79
+ @click=${()=>t.onSelectScope(n.id)}
80
+ >
81
+ ${r}
82
+ </button>
83
+ `})}
84
+ </div>
85
+ </div>
86
+ `}function b(n){let r=n.selectedScope===s,i=n.defaults,a=n.selectedAgent??{},o=r?[`defaults`]:[`agents`,n.selectedScope],u=typeof a.security==`string`?a.security:void 0,d=typeof a.ask==`string`?a.ask:void 0,f=typeof a.askFallback==`string`?a.askFallback:void 0,p=r?i.security:u??`__default__`,m=r?i.ask:d??`__default__`,h=r?i.askFallback:f??`__default__`,g=typeof a.autoAllowSkills==`boolean`?a.autoAllowSkills:void 0,_=g??i.autoAllowSkills,v=g==null;return e`
87
+ <div class="list" style="margin-top: 16px;">
88
+ <div class="list-item">
89
+ <div class="list-main">
90
+ <div class="list-title">Security</div>
91
+ <div class="list-sub">
92
+ ${r?`Default security mode.`:`Default: ${i.security}.`}
93
+ </div>
94
+ </div>
95
+ <div class="list-meta">
96
+ <label class="field">
97
+ <span>Mode</span>
98
+ <select
99
+ ?disabled=${n.disabled}
100
+ @change=${e=>{let t=e.target.value;!r&&t===`__default__`?n.onRemove([...o,`security`]):n.onPatch([...o,`security`],t)}}
101
+ >
102
+ ${r?t:e`<option value="__default__" ?selected=${p===`__default__`}>
103
+ Use default (${i.security})
104
+ </option>`}
105
+ ${c.map(t=>e`<option value=${t.value} ?selected=${p===t.value}>
106
+ ${t.label}
107
+ </option>`)}
108
+ </select>
109
+ </label>
110
+ </div>
111
+ </div>
112
+
113
+ <div class="list-item">
114
+ <div class="list-main">
115
+ <div class="list-title">Ask</div>
116
+ <div class="list-sub">
117
+ ${r?`Default prompt policy.`:`Default: ${i.ask}.`}
118
+ </div>
119
+ </div>
120
+ <div class="list-meta">
121
+ <label class="field">
122
+ <span>Mode</span>
123
+ <select
124
+ ?disabled=${n.disabled}
125
+ @change=${e=>{let t=e.target.value;!r&&t===`__default__`?n.onRemove([...o,`ask`]):n.onPatch([...o,`ask`],t)}}
126
+ >
127
+ ${r?t:e`<option value="__default__" ?selected=${m===`__default__`}>
128
+ Use default (${i.ask})
129
+ </option>`}
130
+ ${l.map(t=>e`<option value=${t.value} ?selected=${m===t.value}>
131
+ ${t.label}
132
+ </option>`)}
133
+ </select>
134
+ </label>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="list-item">
139
+ <div class="list-main">
140
+ <div class="list-title">Ask fallback</div>
141
+ <div class="list-sub">
142
+ ${r?`Applied when the UI prompt is unavailable.`:`Default: ${i.askFallback}.`}
143
+ </div>
144
+ </div>
145
+ <div class="list-meta">
146
+ <label class="field">
147
+ <span>Fallback</span>
148
+ <select
149
+ ?disabled=${n.disabled}
150
+ @change=${e=>{let t=e.target.value;!r&&t===`__default__`?n.onRemove([...o,`askFallback`]):n.onPatch([...o,`askFallback`],t)}}
151
+ >
152
+ ${r?t:e`<option value="__default__" ?selected=${h===`__default__`}>
153
+ Use default (${i.askFallback})
154
+ </option>`}
155
+ ${c.map(t=>e`<option value=${t.value} ?selected=${h===t.value}>
156
+ ${t.label}
157
+ </option>`)}
158
+ </select>
159
+ </label>
160
+ </div>
161
+ </div>
162
+
163
+ <div class="list-item">
164
+ <div class="list-main">
165
+ <div class="list-title">Auto-allow skill CLIs</div>
166
+ <div class="list-sub">
167
+ ${r?`Allow skill executables listed by the Gateway.`:v?`Using default (${i.autoAllowSkills?`on`:`off`}).`:`Override (${_?`on`:`off`}).`}
168
+ </div>
169
+ </div>
170
+ <div class="list-meta">
171
+ <label class="field">
172
+ <span>Enabled</span>
173
+ <input
174
+ type="checkbox"
175
+ ?disabled=${n.disabled}
176
+ .checked=${_}
177
+ @change=${e=>{let t=e.target;n.onPatch([...o,`autoAllowSkills`],t.checked)}}
178
+ />
179
+ </label>
180
+ ${!r&&!v?e`<button
181
+ class="btn btn--sm"
182
+ ?disabled=${n.disabled}
183
+ @click=${()=>n.onRemove([...o,`autoAllowSkills`])}
184
+ >
185
+ Use default
186
+ </button>`:t}
187
+ </div>
188
+ </div>
189
+ </div>
190
+ `}function x(t){let n=[`agents`,t.selectedScope,`allowlist`],r=t.allowlist;return e`
191
+ <div class="row" style="margin-top: 18px; justify-content: space-between;">
192
+ <div>
193
+ <div class="card-title">Allowlist</div>
194
+ <div class="card-sub">Case-insensitive glob patterns.</div>
195
+ </div>
196
+ <button
197
+ class="btn btn--sm"
198
+ ?disabled=${t.disabled}
199
+ @click=${()=>{let e=[...r,{pattern:``}];t.onPatch(n,e)}}
200
+ >
201
+ Add pattern
202
+ </button>
203
+ </div>
204
+ <div class="list" style="margin-top: 12px;">
205
+ ${r.length===0?e` <div class="muted">No allowlist entries yet.</div> `:r.map((e,n)=>S(t,e,n))}
206
+ </div>
207
+ `}function S(r,a,o){let s=a.lastUsedAt?n(a.lastUsedAt):`never`,c=a.lastUsedCommand?i(a.lastUsedCommand,120):null,l=a.lastResolvedPath?i(a.lastResolvedPath,120):null;return e`
208
+ <div class="list-item">
209
+ <div class="list-main">
210
+ <div class="list-title">${a.pattern?.trim()?a.pattern:`New pattern`}</div>
211
+ <div class="list-sub">Last used: ${s}</div>
212
+ ${c?e`<div class="list-sub mono">${c}</div>`:t}
213
+ ${l?e`<div class="list-sub mono">${l}</div>`:t}
214
+ </div>
215
+ <div class="list-meta">
216
+ <label class="field">
217
+ <span>Pattern</span>
218
+ <input
219
+ type="text"
220
+ .value=${a.pattern??``}
221
+ ?disabled=${r.disabled}
222
+ @input=${e=>{let t=e.target;r.onPatch([`agents`,r.selectedScope,`allowlist`,o,`pattern`],t.value)}}
223
+ />
224
+ </label>
225
+ <button
226
+ class="btn btn--sm danger"
227
+ ?disabled=${r.disabled}
228
+ @click=${()=>{if(r.allowlist.length<=1){r.onRemove([`agents`,r.selectedScope,`allowlist`]);return}r.onRemove([`agents`,r.selectedScope,`allowlist`,o])}}
229
+ >
230
+ Remove
231
+ </button>
232
+ </div>
233
+ </div>
234
+ `}function C(e){return o(e,[`system.execApprovals.get`,`system.execApprovals.set`])}function w(t){let n=k(t);return e`
235
+ ${_(g(t))} ${A(n)} ${T(t)}
236
+ <section class="card">
237
+ <div class="row" style="justify-content: space-between;">
238
+ <div>
239
+ <div class="card-title">Nodes</div>
240
+ <div class="card-sub">Paired devices and live links.</div>
241
+ </div>
242
+ <button class="btn" ?disabled=${t.loading} @click=${t.onRefresh}>
243
+ ${t.loading?`Loading…`:`Refresh`}
244
+ </button>
245
+ </div>
246
+ <div class="list" style="margin-top: 16px;">
247
+ ${t.nodes.length===0?e` <div class="muted">No nodes found.</div> `:t.nodes.map(e=>P(e))}
248
+ </div>
249
+ </section>
250
+ `}function T(n){let r=n.devicesList??{pending:[],paired:[]},i=Array.isArray(r.pending)?r.pending:[],a=Array.isArray(r.paired)?r.paired:[];return e`
251
+ <section class="card">
252
+ <div class="row" style="justify-content: space-between;">
253
+ <div>
254
+ <div class="card-title">Devices</div>
255
+ <div class="card-sub">Pairing requests + role tokens.</div>
256
+ </div>
257
+ <button class="btn" ?disabled=${n.devicesLoading} @click=${n.onDevicesRefresh}>
258
+ ${n.devicesLoading?`Loading…`:`Refresh`}
259
+ </button>
260
+ </div>
261
+ ${n.devicesError?e`<div class="callout danger" style="margin-top: 12px;">${n.devicesError}</div>`:t}
262
+ <div class="list" style="margin-top: 16px;">
263
+ ${i.length>0?e`
264
+ <div class="muted" style="margin-bottom: 8px;">Pending</div>
265
+ ${i.map(e=>E(e,n))}
266
+ `:t}
267
+ ${a.length>0?e`
268
+ <div class="muted" style="margin-top: 12px; margin-bottom: 8px;">Paired</div>
269
+ ${a.map(e=>D(e,n))}
270
+ `:t}
271
+ ${i.length===0&&a.length===0?e` <div class="muted">No paired devices.</div> `:t}
272
+ </div>
273
+ </section>
274
+ `}function E(t,i){let a=t.displayName?.trim()||t.deviceId,o=typeof t.ts==`number`?n(t.ts):`n/a`,s=t.role?.trim()||r(t.roles),c=r(t.scopes),l=t.isRepair?` · repair`:``,u=t.remoteIp?` · ${t.remoteIp}`:``;return e`
275
+ <div class="list-item">
276
+ <div class="list-main">
277
+ <div class="list-title">${a}</div>
278
+ <div class="list-sub">${t.deviceId}${u}</div>
279
+ <div class="muted" style="margin-top: 6px;">
280
+ role: ${s} · scopes: ${c} · requested ${o}${l}
281
+ </div>
282
+ </div>
283
+ <div class="list-meta">
284
+ <div class="row" style="justify-content: flex-end; gap: 8px; flex-wrap: wrap;">
285
+ <button class="btn btn--sm primary" @click=${()=>i.onDeviceApprove(t.requestId)}>
286
+ Approve
287
+ </button>
288
+ <button class="btn btn--sm" @click=${()=>i.onDeviceReject(t.requestId)}>
289
+ Reject
290
+ </button>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ `}function D(t,n){let i=t.displayName?.trim()||t.deviceId,a=t.remoteIp?` · ${t.remoteIp}`:``,o=`roles: ${r(t.roles)}`,s=`scopes: ${r(t.scopes)}`,c=Array.isArray(t.tokens)?t.tokens:[];return e`
295
+ <div class="list-item">
296
+ <div class="list-main">
297
+ <div class="list-title">${i}</div>
298
+ <div class="list-sub">${t.deviceId}${a}</div>
299
+ <div class="muted" style="margin-top: 6px;">${o} · ${s}</div>
300
+ ${c.length===0?e` <div class="muted" style="margin-top: 6px">Tokens: none</div> `:e`
301
+ <div class="muted" style="margin-top: 10px;">Tokens</div>
302
+ <div style="display: flex; flex-direction: column; gap: 8px; margin-top: 6px;">
303
+ ${c.map(e=>O(t.deviceId,e,n))}
304
+ </div>
305
+ `}
306
+ </div>
307
+ </div>
308
+ `}function O(i,a,o){let s=a.revokedAtMs?`revoked`:`active`,c=`scopes: ${r(a.scopes)}`,l=n(a.rotatedAtMs??a.createdAtMs??a.lastUsedAtMs??null);return e`
309
+ <div class="row" style="justify-content: space-between; gap: 8px;">
310
+ <div class="list-sub">${a.role} · ${s} · ${c} · ${l}</div>
311
+ <div class="row" style="justify-content: flex-end; gap: 6px; flex-wrap: wrap;">
312
+ <button
313
+ class="btn btn--sm"
314
+ @click=${()=>o.onDeviceRotate(i,a.role,a.scopes)}
315
+ >
316
+ Rotate
317
+ </button>
318
+ ${a.revokedAtMs?t:e`
319
+ <button
320
+ class="btn btn--sm danger"
321
+ @click=${()=>o.onDeviceRevoke(i,a.role)}
322
+ >
323
+ Revoke
324
+ </button>
325
+ `}
326
+ </div>
327
+ </div>
328
+ `}function k(e){let t=e.configForm,n=M(e.nodes),{defaultBinding:r,agents:i}=N(t);return{ready:!!t,disabled:e.configSaving||e.configFormMode===`raw`,configDirty:e.configDirty,configLoading:e.configLoading,configSaving:e.configSaving,defaultBinding:r,agents:i,nodes:n,onBindDefault:e.onBindDefault,onBindAgent:e.onBindAgent,onSave:e.onSaveBindings,onLoadConfig:e.onLoadConfig,formMode:e.configFormMode}}function A(n){let r=n.nodes.length>0,i=n.defaultBinding??``;return e`
329
+ <section class="card">
330
+ <div class="row" style="justify-content: space-between; align-items: center;">
331
+ <div>
332
+ <div class="card-title">Exec node binding</div>
333
+ <div class="card-sub">
334
+ Pin agents to a specific node when using <span class="mono">exec host=node</span>.
335
+ </div>
336
+ </div>
337
+ <button
338
+ class="btn"
339
+ ?disabled=${n.disabled||!n.configDirty}
340
+ @click=${n.onSave}
341
+ >
342
+ ${n.configSaving?`Saving…`:`Save`}
343
+ </button>
344
+ </div>
345
+
346
+ ${n.formMode===`raw`?e`
347
+ <div class="callout warn" style="margin-top: 12px">
348
+ Switch the Config tab to <strong>Form</strong> mode to edit bindings here.
349
+ </div>
350
+ `:t}
351
+ ${n.ready?e`
352
+ <div class="list" style="margin-top: 16px;">
353
+ <div class="list-item">
354
+ <div class="list-main">
355
+ <div class="list-title">Default binding</div>
356
+ <div class="list-sub">Used when agents do not override a node binding.</div>
357
+ </div>
358
+ <div class="list-meta">
359
+ <label class="field">
360
+ <span>Node</span>
361
+ <select
362
+ ?disabled=${n.disabled||!r}
363
+ @change=${e=>{let t=e.target.value.trim();n.onBindDefault(t||null)}}
364
+ >
365
+ <option value="" ?selected=${i===``}>Any node</option>
366
+ ${n.nodes.map(t=>e`<option value=${t.id} ?selected=${i===t.id}>
367
+ ${t.label}
368
+ </option>`)}
369
+ </select>
370
+ </label>
371
+ ${r?t:e` <div class="muted">No nodes with system.run available.</div> `}
372
+ </div>
373
+ </div>
374
+
375
+ ${n.agents.length===0?e` <div class="muted">No agents found.</div> `:n.agents.map(e=>j(e,n))}
376
+ </div>
377
+ `:e`<div class="row" style="margin-top: 12px; gap: 12px;">
378
+ <div class="muted">Load config to edit bindings.</div>
379
+ <button class="btn" ?disabled=${n.configLoading} @click=${n.onLoadConfig}>
380
+ ${n.configLoading?`Loading…`:`Load config`}
381
+ </button>
382
+ </div>`}
383
+ </section>
384
+ `}function j(t,n){let r=t.binding??`__default__`,i=t.name?.trim()?`${t.name} (${t.id})`:t.id,a=n.nodes.length>0;return e`
385
+ <div class="list-item">
386
+ <div class="list-main">
387
+ <div class="list-title">${i}</div>
388
+ <div class="list-sub">
389
+ ${t.isDefault?`default agent`:`agent`} ·
390
+ ${r===`__default__`?`uses default (${n.defaultBinding??`any`})`:`override: ${t.binding}`}
391
+ </div>
392
+ </div>
393
+ <div class="list-meta">
394
+ <label class="field">
395
+ <span>Binding</span>
396
+ <select
397
+ ?disabled=${n.disabled||!a}
398
+ @change=${e=>{let r=e.target.value.trim();n.onBindAgent(t.index,r===`__default__`?null:r)}}
399
+ >
400
+ <option value="__default__" ?selected=${r===`__default__`}>
401
+ Use default
402
+ </option>
403
+ ${n.nodes.map(t=>e`<option value=${t.id} ?selected=${r===t.id}>
404
+ ${t.label}
405
+ </option>`)}
406
+ </select>
407
+ </label>
408
+ </div>
409
+ </div>
410
+ `}function M(e){return o(e,[`system.run`])}function N(e){let t={id:`main`,name:void 0,index:0,isDefault:!0,binding:null};if(!e||typeof e!=`object`)return{defaultBinding:null,agents:[t]};let n=(e.tools??{}).exec??{},r=typeof n.node==`string`&&n.node.trim()?n.node.trim():null,i=e.agents??{};if(!Array.isArray(i.list)||i.list.length===0)return{defaultBinding:r,agents:[t]};let o=a(e).map(e=>{let t=(e.record.tools??{}).exec??{},n=typeof t.node==`string`&&t.node.trim()?t.node.trim():null;return{id:e.id,name:e.name,index:e.index,isDefault:e.isDefault,binding:n}});return o.length===0&&o.push(t),{defaultBinding:r,agents:o}}function P(t){let n=!!t.connected,r=!!t.paired,i=typeof t.displayName==`string`&&t.displayName.trim()||(typeof t.nodeId==`string`?t.nodeId:`unknown`),a=Array.isArray(t.caps)?t.caps:[],o=Array.isArray(t.commands)?t.commands:[];return e`
411
+ <div class="list-item">
412
+ <div class="list-main">
413
+ <div class="list-title">${i}</div>
414
+ <div class="list-sub">
415
+ ${typeof t.nodeId==`string`?t.nodeId:``}
416
+ ${typeof t.remoteIp==`string`?` · ${t.remoteIp}`:``}
417
+ ${typeof t.version==`string`?` · ${t.version}`:``}
418
+ </div>
419
+ <div class="chip-row" style="margin-top: 6px;">
420
+ <span class="chip">${r?`paired`:`unpaired`}</span>
421
+ <span class="chip ${n?`chip-ok`:`chip-warn`}">
422
+ ${n?`connected`:`offline`}
423
+ </span>
424
+ ${a.slice(0,12).map(t=>e`<span class="chip">${String(t)}</span>`)}
425
+ ${o.slice(0,8).map(t=>e`<span class="chip">${String(t)}</span>`)}
426
+ </div>
427
+ </div>
428
+ </div>
429
+ `}export{w as renderNodes};
430
+ //# sourceMappingURL=nodes-6XxETMb5.js.map