pith-ui 0.0.0-stage → 0.1.1
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/AI.md +75 -0
- package/API.md +3688 -0
- package/LICENSE +661 -0
- package/README.md +80 -2
- package/dist/composer.d.ts +38 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +123 -0
- package/dist/composer.js.map +1 -0
- package/dist/content/conversation-reader.d.ts +19 -0
- package/dist/content/conversation-reader.d.ts.map +1 -0
- package/dist/content/conversation-reader.js +280 -0
- package/dist/content/conversation-reader.js.map +1 -0
- package/dist/content/conversation-view.d.ts +65 -0
- package/dist/content/conversation-view.d.ts.map +1 -0
- package/dist/content/conversation-view.js +140 -0
- package/dist/content/conversation-view.js.map +1 -0
- package/dist/content/image-viewer.d.ts +25 -0
- package/dist/content/image-viewer.d.ts.map +1 -0
- package/dist/content/image-viewer.js +114 -0
- package/dist/content/image-viewer.js.map +1 -0
- package/dist/content/markdown.d.ts +12 -0
- package/dist/content/markdown.d.ts.map +1 -0
- package/dist/content/markdown.js +68 -0
- package/dist/content/markdown.js.map +1 -0
- package/dist/content/paged-preview.d.ts +15 -0
- package/dist/content/paged-preview.d.ts.map +1 -0
- package/dist/content/paged-preview.js +108 -0
- package/dist/content/paged-preview.js.map +1 -0
- package/dist/content/views.d.ts +9 -0
- package/dist/content/views.d.ts.map +1 -0
- package/dist/content/views.js +53 -0
- package/dist/content/views.js.map +1 -0
- package/dist/content/welcome.d.ts +18 -0
- package/dist/content/welcome.d.ts.map +1 -0
- package/dist/content/welcome.js +54 -0
- package/dist/content/welcome.js.map +1 -0
- package/dist/core.d.ts +36 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +44 -0
- package/dist/core.js.map +1 -0
- package/dist/dom.d.ts +14 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +69 -0
- package/dist/dom.js.map +1 -0
- package/dist/files/panels.d.ts +100 -0
- package/dist/files/panels.d.ts.map +1 -0
- package/dist/files/panels.js +286 -0
- package/dist/files/panels.js.map +1 -0
- package/dist/files/systems.d.ts +91 -0
- package/dist/files/systems.d.ts.map +1 -0
- package/dist/files/systems.js +273 -0
- package/dist/files/systems.js.map +1 -0
- package/dist/forms/actions.d.ts +27 -0
- package/dist/forms/actions.d.ts.map +1 -0
- package/dist/forms/actions.js +39 -0
- package/dist/forms/actions.js.map +1 -0
- package/dist/forms/custom-connection.d.ts +62 -0
- package/dist/forms/custom-connection.d.ts.map +1 -0
- package/dist/forms/custom-connection.js +72 -0
- package/dist/forms/custom-connection.js.map +1 -0
- package/dist/forms/dialog-frame.d.ts +41 -0
- package/dist/forms/dialog-frame.d.ts.map +1 -0
- package/dist/forms/dialog-frame.js +95 -0
- package/dist/forms/dialog-frame.js.map +1 -0
- package/dist/forms/history.d.ts +16 -0
- package/dist/forms/history.d.ts.map +1 -0
- package/dist/forms/history.js +21 -0
- package/dist/forms/history.js.map +1 -0
- package/dist/forms/identity.d.ts +16 -0
- package/dist/forms/identity.d.ts.map +1 -0
- package/dist/forms/identity.js +53 -0
- package/dist/forms/identity.js.map +1 -0
- package/dist/forms/model-editor.d.ts +40 -0
- package/dist/forms/model-editor.d.ts.map +1 -0
- package/dist/forms/model-editor.js +89 -0
- package/dist/forms/model-editor.js.map +1 -0
- package/dist/forms/panels.d.ts +146 -0
- package/dist/forms/panels.d.ts.map +1 -0
- package/dist/forms/panels.js +339 -0
- package/dist/forms/panels.js.map +1 -0
- package/dist/forms/provider-login.d.ts +22 -0
- package/dist/forms/provider-login.d.ts.map +1 -0
- package/dist/forms/provider-login.js +116 -0
- package/dist/forms/provider-login.js.map +1 -0
- package/dist/forms/resource-editor.d.ts +27 -0
- package/dist/forms/resource-editor.d.ts.map +1 -0
- package/dist/forms/resource-editor.js +34 -0
- package/dist/forms/resource-editor.js.map +1 -0
- package/dist/foundations.d.ts +95 -0
- package/dist/foundations.d.ts.map +1 -0
- package/dist/foundations.js +315 -0
- package/dist/foundations.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation/context-menu.d.ts +26 -0
- package/dist/navigation/context-menu.d.ts.map +1 -0
- package/dist/navigation/context-menu.js +81 -0
- package/dist/navigation/context-menu.js.map +1 -0
- package/dist/navigation/navigation.d.ts +92 -0
- package/dist/navigation/navigation.d.ts.map +1 -0
- package/dist/navigation/navigation.js +368 -0
- package/dist/navigation/navigation.js.map +1 -0
- package/dist/primitives.d.ts +310 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +633 -0
- package/dist/primitives.js.map +1 -0
- package/dist/styles.css +853 -0
- package/dist/surface.d.ts +29 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +154 -0
- package/dist/surface.js.map +1 -0
- package/dist/tasks/approval.d.ts +25 -0
- package/dist/tasks/approval.d.ts.map +1 -0
- package/dist/tasks/approval.js +64 -0
- package/dist/tasks/approval.js.map +1 -0
- package/dist/tasks/permission.d.ts +37 -0
- package/dist/tasks/permission.d.ts.map +1 -0
- package/dist/tasks/permission.js +73 -0
- package/dist/tasks/permission.js.map +1 -0
- package/dist/tasks/runtime.d.ts +31 -0
- package/dist/tasks/runtime.d.ts.map +1 -0
- package/dist/tasks/runtime.js +34 -0
- package/dist/tasks/runtime.js.map +1 -0
- package/dist/theme.d.ts +4 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +6 -0
- package/dist/theme.js.map +1 -0
- package/dist/workspace.d.ts +92 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +288 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +27 -4
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { icon, setText } from '../dom.js';
|
|
2
|
+
import { adoptAction, adoptFeedback, adoptProductParts } from '../foundations.js';
|
|
3
|
+
const currency = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 6 });
|
|
4
|
+
const numbers = new Intl.NumberFormat();
|
|
5
|
+
export function formatCost(cost, latestTask = false) {
|
|
6
|
+
if (cost?.unavailable)
|
|
7
|
+
return 'Unavailable';
|
|
8
|
+
const count = latestTask ? cost?.runRequests : cost?.requestCount;
|
|
9
|
+
const unknown = (latestTask ? cost?.runUnknownRequests : cost?.unknownRequests) || 0;
|
|
10
|
+
if (!count)
|
|
11
|
+
return 'Not recorded';
|
|
12
|
+
if (count === unknown)
|
|
13
|
+
return 'Unknown';
|
|
14
|
+
return `~${currency.format((latestTask ? cost?.runTotal : cost?.total) || 0)}${unknown ? ' (partial)' : ''}`;
|
|
15
|
+
}
|
|
16
|
+
export function createCostLedger(options = {}) {
|
|
17
|
+
const element = options.container || document.createElement('div');
|
|
18
|
+
const rows = new Map();
|
|
19
|
+
let table;
|
|
20
|
+
let note;
|
|
21
|
+
let empty;
|
|
22
|
+
let destroyed = false;
|
|
23
|
+
function clear() { rows.clear(); table = undefined; note = undefined; empty = undefined; element.replaceChildren(); }
|
|
24
|
+
function ensure() {
|
|
25
|
+
if (table)
|
|
26
|
+
return;
|
|
27
|
+
element.innerHTML = '<p class="pui-cost-note"></p><div class="pui-cost-table"><table><thead><tr><th>Request</th><th>Input</th><th>Output</th><th>Cache read / write</th><th>Estimate</th></tr></thead><tbody></tbody></table></div>';
|
|
28
|
+
table = element.querySelector('tbody');
|
|
29
|
+
note = element.querySelector('.pui-cost-note');
|
|
30
|
+
empty = document.createElement('tr');
|
|
31
|
+
const cell = document.createElement('td');
|
|
32
|
+
cell.colSpan = 5;
|
|
33
|
+
cell.textContent = 'No recorded requests yet.';
|
|
34
|
+
empty.append(cell);
|
|
35
|
+
}
|
|
36
|
+
function makeRow(id) {
|
|
37
|
+
const row = document.createElement('tr');
|
|
38
|
+
row.innerHTML = '<td><strong data-purpose></strong><br><span data-identity></span><br><small data-time></small><details><summary>Price source and rates (USD / million tokens)</summary><p data-source></p><pre data-price></pre><p data-reasoning hidden></p></details></td><td></td><td></td><td></td><td></td>';
|
|
39
|
+
const details = row.querySelector('details');
|
|
40
|
+
details.dataset.costId = id;
|
|
41
|
+
return { element: row, purpose: row.querySelector('[data-purpose]'), identity: row.querySelector('[data-identity]'), time: row.querySelector('[data-time]'), details, source: row.querySelector('[data-source]'), price: row.querySelector('[data-price]'), reasoning: row.querySelector('[data-reasoning]'), cells: [...row.querySelectorAll('td')] };
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
element,
|
|
45
|
+
clear() { if (!destroyed)
|
|
46
|
+
clear(); },
|
|
47
|
+
loading() { if (!destroyed && !element.childElementCount)
|
|
48
|
+
element.textContent = 'Loading request breakdown…'; },
|
|
49
|
+
setError(message) { if (!destroyed) {
|
|
50
|
+
clear();
|
|
51
|
+
element.textContent = message;
|
|
52
|
+
} },
|
|
53
|
+
update(report) {
|
|
54
|
+
if (destroyed)
|
|
55
|
+
return;
|
|
56
|
+
const focused = document.activeElement;
|
|
57
|
+
ensure();
|
|
58
|
+
setText(note, `USD estimates for recorded requests, not a provider bill. Prices are saved per request; retries and context summaries are included when usage is reported. ${report.unknownRequests ? `${report.unknownRequests} request(s) have unknown prices or usage and are excluded. ` : ''}Older requests made before recording began are not reconstructed.`);
|
|
59
|
+
const requests = report.requests || [];
|
|
60
|
+
const keep = new Set(requests.map(request => request.id));
|
|
61
|
+
for (const [id, row] of rows)
|
|
62
|
+
if (!keep.has(id)) {
|
|
63
|
+
row.element.remove();
|
|
64
|
+
rows.delete(id);
|
|
65
|
+
}
|
|
66
|
+
if (!requests.length) {
|
|
67
|
+
if (!empty.parentElement)
|
|
68
|
+
table.append(empty);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
empty.remove();
|
|
72
|
+
let cursor = table.firstElementChild;
|
|
73
|
+
const n = (value) => numbers.format(value || 0);
|
|
74
|
+
for (const request of requests) {
|
|
75
|
+
let row = rows.get(request.id);
|
|
76
|
+
if (!row) {
|
|
77
|
+
row = makeRow(request.id);
|
|
78
|
+
rows.set(request.id, row);
|
|
79
|
+
}
|
|
80
|
+
setText(row.purpose, `${request.purpose} · ${request.status}`);
|
|
81
|
+
setText(row.identity, `${request.providerName || request.provider} / ${request.modelName || request.model}`);
|
|
82
|
+
setText(row.time, request.time);
|
|
83
|
+
setText(row.source, request.source);
|
|
84
|
+
setText(row.price, JSON.stringify(request.price, null, 2));
|
|
85
|
+
row.reasoning.hidden = request.usage.reasoning == null;
|
|
86
|
+
setText(row.reasoning, request.usage.reasoning == null ? '' : `Reasoning tokens: ${n(request.usage.reasoning)} (included in output)`);
|
|
87
|
+
setText(row.cells[1], n(request.usage.input));
|
|
88
|
+
setText(row.cells[2], n(request.usage.output));
|
|
89
|
+
setText(row.cells[3], `${n(request.usage.cacheRead)} / ${n(request.usage.cacheWrite)}`);
|
|
90
|
+
setText(row.cells[4], request.known ? currency.format(request.usage.cost.total) : 'Unknown');
|
|
91
|
+
if (row.element !== cursor)
|
|
92
|
+
table.insertBefore(row.element, cursor);
|
|
93
|
+
cursor = row.element.nextElementSibling;
|
|
94
|
+
}
|
|
95
|
+
if (focused instanceof HTMLElement && element.contains(focused) && document.activeElement !== focused)
|
|
96
|
+
focused.focus({ preventScroll: true });
|
|
97
|
+
},
|
|
98
|
+
destroy() { if (!destroyed)
|
|
99
|
+
clear(); destroyed = true; },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function createUpdatePanel(options = {}) {
|
|
103
|
+
const element = options.container || document.createElement('section');
|
|
104
|
+
if (!element.querySelector('[data-update-version]'))
|
|
105
|
+
element.innerHTML = '<p data-update-version></p><p data-update-message role="status"></p><div class="pui-feature-toolbar"><button type="button" class="pui-secondary-button" data-update-check>Check for updates</button><button type="button" class="pui-secondary-button" data-update-install hidden>Update and restart</button></div><progress max="100" hidden></progress>';
|
|
106
|
+
const version = element.querySelector('[data-update-version]');
|
|
107
|
+
const message = element.querySelector('[data-update-message]');
|
|
108
|
+
const check = element.querySelector('[data-update-check]');
|
|
109
|
+
const install = element.querySelector('[data-update-install]');
|
|
110
|
+
const progress = element.querySelector('progress');
|
|
111
|
+
const parts = adoptProductParts(element);
|
|
112
|
+
let state;
|
|
113
|
+
let pending = false, destroyed = false;
|
|
114
|
+
let error = '';
|
|
115
|
+
let retryCheck = false;
|
|
116
|
+
const checkAction = () => options.onCheck?.(), installAction = () => options.onInstall?.();
|
|
117
|
+
check.addEventListener('click', checkAction);
|
|
118
|
+
install.addEventListener('click', installAction);
|
|
119
|
+
function render() {
|
|
120
|
+
if (destroyed)
|
|
121
|
+
return;
|
|
122
|
+
if (!state) {
|
|
123
|
+
parts.action(check).update({ pending });
|
|
124
|
+
parts.action(install).update({ pending });
|
|
125
|
+
parts.feedback(message).update({ message: error, tone: 'info' });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
version.textContent = `${options.productName || 'Application'} ${state.version}`;
|
|
129
|
+
parts.feedback(message).update({ message: error || state.message, tone: 'info' });
|
|
130
|
+
const busy = ['checking', 'installing', 'restarting'].includes(state.phase);
|
|
131
|
+
parts.action(check).update({ disabled: !state.enabled || (busy && !retryCheck), pending });
|
|
132
|
+
install.hidden = !state.availableVersion;
|
|
133
|
+
parts.action(install).update({ disabled: busy, pending, label: 'Update and restart' });
|
|
134
|
+
progress.hidden = state.phase !== 'installing';
|
|
135
|
+
progress.value = state.progress;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
element,
|
|
139
|
+
update(value) { state = value; error = ''; retryCheck = false; render(); },
|
|
140
|
+
setPending(value) { pending = value; render(); },
|
|
141
|
+
setError(value, options = {}) { if (!destroyed) {
|
|
142
|
+
error = value;
|
|
143
|
+
retryCheck = !!options.allowCheckRetry;
|
|
144
|
+
render();
|
|
145
|
+
} },
|
|
146
|
+
destroy() { if (destroyed)
|
|
147
|
+
return; destroyed = true; parts.destroy(); check.removeEventListener('click', checkAction); install.removeEventListener('click', installAction); },
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export function historyStatusMarkup(status) {
|
|
151
|
+
if (status === 'approval')
|
|
152
|
+
return '<span class="pui-history-status pui-needs-approval" role="img" aria-label="Waiting for approval" title="Waiting for approval"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v6m0 4h.01"/></svg></span>';
|
|
153
|
+
if (status === 'running')
|
|
154
|
+
return '<span class="pui-history-status" role="img" aria-label="Running" title="Running"><i class="pui-history-spinner" aria-hidden="true"></i></span>';
|
|
155
|
+
if (status === 'unread')
|
|
156
|
+
return '<span class="pui-history-status" role="img" aria-label="Completed, unread" title="Completed, unread"><i class="pui-history-unread" aria-hidden="true"></i></span>';
|
|
157
|
+
return '<span class="pui-history-status" aria-hidden="true"></span>';
|
|
158
|
+
}
|
|
159
|
+
export function createCompletionNotices(options = {}) {
|
|
160
|
+
const element = options.container || document.createElement('div');
|
|
161
|
+
const parts = adoptProductParts(element);
|
|
162
|
+
const entries = new Map();
|
|
163
|
+
let destroyed = false;
|
|
164
|
+
const click = (event) => {
|
|
165
|
+
const target = event.target.closest('[data-conversation], [data-dismiss-completion]');
|
|
166
|
+
if (!target || !element.contains(target))
|
|
167
|
+
return;
|
|
168
|
+
if (target.dataset.conversation)
|
|
169
|
+
options.onOpen?.(target.dataset.conversation);
|
|
170
|
+
else if (target.dataset.dismissCompletion)
|
|
171
|
+
options.onDismiss?.(target.dataset.dismissCompletion);
|
|
172
|
+
};
|
|
173
|
+
if (options.onOpen || options.onDismiss)
|
|
174
|
+
element.addEventListener('click', click);
|
|
175
|
+
return {
|
|
176
|
+
element,
|
|
177
|
+
update(notices) {
|
|
178
|
+
if (destroyed)
|
|
179
|
+
return;
|
|
180
|
+
const focused = document.activeElement;
|
|
181
|
+
const keep = new Set(notices.map(notice => notice.runID));
|
|
182
|
+
for (const [id, entry] of entries)
|
|
183
|
+
if (!keep.has(id)) {
|
|
184
|
+
entry.element.remove();
|
|
185
|
+
entries.delete(id);
|
|
186
|
+
}
|
|
187
|
+
let cursor = element.firstElementChild;
|
|
188
|
+
for (const notice of notices) {
|
|
189
|
+
let entry = entries.get(notice.runID);
|
|
190
|
+
if (!entry) {
|
|
191
|
+
const article = document.createElement('article');
|
|
192
|
+
article.className = 'pui-completion-notice';
|
|
193
|
+
article.innerHTML = `<span class="pui-completion-check" aria-hidden="true">${icon('check')}</span><div class="pui-completion-content"><strong>Task completed</strong><p></p><button class="pui-text-button" type="button" data-conversation>Open conversation</button></div><button class="pui-quiet-icon pui-completion-dismiss" type="button" data-dismiss-completion aria-label="Dismiss completion notification">${icon('close')}</button>`;
|
|
194
|
+
entry = { element: article, text: article.querySelector('p'), open: article.querySelector('[data-conversation]'), dismiss: article.querySelector('[data-dismiss-completion]') };
|
|
195
|
+
entries.set(notice.runID, entry);
|
|
196
|
+
}
|
|
197
|
+
setText(entry.text, `${notice.workspace} · ${notice.title}`);
|
|
198
|
+
parts.action(entry.open).update({ label: 'Open conversation' });
|
|
199
|
+
parts.action(entry.dismiss).update({ label: 'Dismiss completion notification' });
|
|
200
|
+
if (entry.open.dataset.conversation !== notice.id)
|
|
201
|
+
entry.open.dataset.conversation = notice.id;
|
|
202
|
+
if (entry.dismiss.dataset.dismissCompletion !== notice.runID)
|
|
203
|
+
entry.dismiss.dataset.dismissCompletion = notice.runID;
|
|
204
|
+
if (entry.element !== cursor)
|
|
205
|
+
element.insertBefore(entry.element, cursor);
|
|
206
|
+
cursor = entry.element.nextElementSibling;
|
|
207
|
+
}
|
|
208
|
+
parts.update();
|
|
209
|
+
if (focused instanceof HTMLElement && element.contains(focused) && document.activeElement !== focused)
|
|
210
|
+
focused.focus({ preventScroll: true });
|
|
211
|
+
},
|
|
212
|
+
destroy() { if (destroyed)
|
|
213
|
+
return; destroyed = true; parts.destroy(); entries.clear(); element.removeEventListener?.('click', click); element.replaceChildren(); },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
export function createCopyFeedback(options) {
|
|
217
|
+
let destroyed = false;
|
|
218
|
+
const notice = adoptFeedback(options.status, { presentation: 'inline', autoHide: false });
|
|
219
|
+
const entries = new Map();
|
|
220
|
+
const release = (button, entry) => {
|
|
221
|
+
if (entry.timer)
|
|
222
|
+
clearTimeout(entry.timer);
|
|
223
|
+
if (entry.displayed && button.isConnected) {
|
|
224
|
+
button.replaceChildren(...entry.original);
|
|
225
|
+
if (entry.label === null)
|
|
226
|
+
button.removeAttribute('aria-label');
|
|
227
|
+
else
|
|
228
|
+
button.setAttribute('aria-label', entry.label);
|
|
229
|
+
button.title = entry.title;
|
|
230
|
+
}
|
|
231
|
+
delete button.dataset.copyPending;
|
|
232
|
+
entry.controller.update({ disabled: options.isDisabled(button) });
|
|
233
|
+
entry.controller.destroy();
|
|
234
|
+
entries.delete(button);
|
|
235
|
+
};
|
|
236
|
+
return {
|
|
237
|
+
async copy(button, action, announcement) {
|
|
238
|
+
if (destroyed || button.dataset.copyPending === 'true')
|
|
239
|
+
return;
|
|
240
|
+
const entry = { controller: adoptAction(button), original: [...button.childNodes], label: button.getAttribute('aria-label'), title: button.title, displayed: false };
|
|
241
|
+
entries.set(button, entry);
|
|
242
|
+
notice.update({ message: '', tone: 'info' });
|
|
243
|
+
button.dataset.copyPending = 'true';
|
|
244
|
+
entry.controller.update({ disabled: options.isDisabled(button) });
|
|
245
|
+
try {
|
|
246
|
+
await action();
|
|
247
|
+
if (destroyed)
|
|
248
|
+
return;
|
|
249
|
+
notice.update({ message: announcement, tone: 'info' });
|
|
250
|
+
if (!button.isConnected) {
|
|
251
|
+
release(button, entry);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
button.innerHTML = button.classList.contains('pui-message-action') ? icon('check') : 'Copied';
|
|
255
|
+
button.setAttribute('aria-label', announcement);
|
|
256
|
+
button.title = announcement;
|
|
257
|
+
entry.displayed = true;
|
|
258
|
+
entry.timer = setTimeout(() => { if (!destroyed && entries.get(button) === entry)
|
|
259
|
+
release(button, entry); }, 1500);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (destroyed)
|
|
263
|
+
return;
|
|
264
|
+
release(button, entry);
|
|
265
|
+
options.onError(error);
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
destroy() { if (destroyed)
|
|
269
|
+
return; destroyed = true; for (const [button, entry] of entries)
|
|
270
|
+
release(button, entry); notice.destroy(); },
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=systems.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systems.js","sourceRoot":"","sources":["../../src/files/systems.ts"],"names":[],"mappings":"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","sourcesContent":["import { icon, setText } from '../dom.js';\nimport type { UIBlock } from '../core.js';\nimport { adoptAction, adoptFeedback, adoptProductParts } from '../foundations.js';\nimport type { ActionController } from '../foundations.js';\n\nconst currency = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 6 });\nconst numbers = new Intl.NumberFormat();\nexport interface CostSummaryDisplay { unavailable?: boolean; requestCount: number; unknownRequests: number; runRequests: number; runUnknownRequests: number; total: number; runTotal: number }\nexport function formatCost(cost: CostSummaryDisplay | undefined, latestTask = false): string {\n if (cost?.unavailable) return 'Unavailable';\n const count = latestTask ? cost?.runRequests : cost?.requestCount;\n const unknown = (latestTask ? cost?.runUnknownRequests : cost?.unknownRequests) || 0;\n if (!count) return 'Not recorded';\n if (count === unknown) return 'Unknown';\n return `~${currency.format((latestTask ? cost?.runTotal : cost?.total) || 0)}${unknown ? ' (partial)' : ''}`;\n}\nexport interface CostRequestDisplay {\n id: string; purpose: string; status: string; provider: string; providerName?: string; model: string; modelName?: string;\n time: string; source: string; price: unknown; known: boolean;\n usage: { input: number; output: number; cacheRead: number; cacheWrite: number; reasoning?: number; cost: { total: number } };\n}\nexport interface CostLedgerState { unknownRequests: number; requests: readonly CostRequestDisplay[] | null }\nexport function createCostLedger(options: { container?: HTMLElement } = {}) {\n const element = options.container || document.createElement('div');\n type Row = { element: HTMLTableRowElement; purpose: HTMLElement; identity: HTMLElement; time: HTMLElement; details: HTMLDetailsElement; source: HTMLElement; price: HTMLElement; reasoning: HTMLElement; cells: HTMLTableCellElement[] };\n const rows = new Map<string, Row>();\n let table: HTMLTableSectionElement | undefined;\n let note: HTMLElement | undefined;\n let empty: HTMLTableRowElement | undefined;\n let destroyed = false;\n function clear(): void { rows.clear(); table = undefined; note = undefined; empty = undefined; element.replaceChildren(); }\n function ensure(): void {\n if (table) return;\n element.innerHTML = '<p class=\"pui-cost-note\"></p><div class=\"pui-cost-table\"><table><thead><tr><th>Request</th><th>Input</th><th>Output</th><th>Cache read / write</th><th>Estimate</th></tr></thead><tbody></tbody></table></div>';\n table = element.querySelector('tbody')!; note = element.querySelector<HTMLElement>('.pui-cost-note')!;\n empty = document.createElement('tr'); const cell = document.createElement('td'); cell.colSpan = 5; cell.textContent = 'No recorded requests yet.'; empty.append(cell);\n }\n function makeRow(id: string): Row {\n const row = document.createElement('tr');\n row.innerHTML = '<td><strong data-purpose></strong><br><span data-identity></span><br><small data-time></small><details><summary>Price source and rates (USD / million tokens)</summary><p data-source></p><pre data-price></pre><p data-reasoning hidden></p></details></td><td></td><td></td><td></td><td></td>';\n const details = row.querySelector('details')!; details.dataset.costId = id;\n return { element: row, purpose: row.querySelector('[data-purpose]')!, identity: row.querySelector('[data-identity]')!, time: row.querySelector('[data-time]')!, details, source: row.querySelector('[data-source]')!, price: row.querySelector('[data-price]')!, reasoning: row.querySelector('[data-reasoning]')!, cells: [...row.querySelectorAll('td')] };\n }\n return {\n element,\n clear(): void { if (!destroyed) clear(); },\n loading(): void { if (!destroyed && !element.childElementCount) element.textContent = 'Loading request breakdown…'; },\n setError(message: string): void { if (!destroyed) { clear(); element.textContent = message; } },\n update(report: Readonly<CostLedgerState>): void {\n if (destroyed) return;\n const focused = document.activeElement;\n ensure();\n setText(note!, `USD estimates for recorded requests, not a provider bill. Prices are saved per request; retries and context summaries are included when usage is reported. ${report.unknownRequests ? `${report.unknownRequests} request(s) have unknown prices or usage and are excluded. ` : ''}Older requests made before recording began are not reconstructed.`);\n const requests = report.requests || [];\n const keep = new Set(requests.map(request => request.id));\n for (const [id, row] of rows) if (!keep.has(id)) { row.element.remove(); rows.delete(id); }\n if (!requests.length) { if (!empty!.parentElement) table!.append(empty!); return; }\n empty!.remove();\n let cursor = table!.firstElementChild;\n const n = (value: number) => numbers.format(value || 0);\n for (const request of requests) {\n let row = rows.get(request.id);\n if (!row) { row = makeRow(request.id); rows.set(request.id, row); }\n setText(row.purpose, `${request.purpose} · ${request.status}`);\n setText(row.identity, `${request.providerName || request.provider} / ${request.modelName || request.model}`);\n setText(row.time, request.time); setText(row.source, request.source); setText(row.price, JSON.stringify(request.price, null, 2));\n row.reasoning.hidden = request.usage.reasoning == null;\n setText(row.reasoning, request.usage.reasoning == null ? '' : `Reasoning tokens: ${n(request.usage.reasoning)} (included in output)`);\n setText(row.cells[1]!, n(request.usage.input)); setText(row.cells[2]!, n(request.usage.output));\n setText(row.cells[3]!, `${n(request.usage.cacheRead)} / ${n(request.usage.cacheWrite)}`);\n setText(row.cells[4]!, request.known ? currency.format(request.usage.cost.total) : 'Unknown');\n if (row.element !== cursor) table!.insertBefore(row.element, cursor);\n cursor = row.element.nextElementSibling;\n }\n if (focused instanceof HTMLElement && element.contains(focused) && document.activeElement !== focused) focused.focus({ preventScroll: true });\n },\n destroy(): void { if (!destroyed) clear(); destroyed = true; },\n };\n}\n\nexport interface UpdatePanelState { version: string; enabled: boolean; phase: string; availableVersion: string; progress: number; message: string }\nexport function createUpdatePanel(options: { container?: HTMLElement; productName?: string; onCheck?: () => void; onInstall?: () => void } = {}) {\n const element = options.container || document.createElement('section');\n if (!element.querySelector('[data-update-version]')) element.innerHTML = '<p data-update-version></p><p data-update-message role=\"status\"></p><div class=\"pui-feature-toolbar\"><button type=\"button\" class=\"pui-secondary-button\" data-update-check>Check for updates</button><button type=\"button\" class=\"pui-secondary-button\" data-update-install hidden>Update and restart</button></div><progress max=\"100\" hidden></progress>';\n const version = element.querySelector<HTMLElement>('[data-update-version]')!;\n const message = element.querySelector<HTMLElement>('[data-update-message]')!;\n const check = element.querySelector<HTMLButtonElement>('[data-update-check]')!;\n const install = element.querySelector<HTMLButtonElement>('[data-update-install]')!;\n const progress = element.querySelector<HTMLProgressElement>('progress')!;\n const parts = adoptProductParts(element);\n let state: Readonly<UpdatePanelState> | undefined;\n let pending = false, destroyed = false;\n let error = '';\n let retryCheck = false;\n const checkAction = () => options.onCheck?.(), installAction = () => options.onInstall?.();\n check.addEventListener('click', checkAction); install.addEventListener('click', installAction);\n function render(): void {\n if (destroyed) return;\n if (!state) { parts.action(check).update({pending}); parts.action(install).update({pending}); parts.feedback(message).update({message:error,tone:'info'}); return; }\n version.textContent = `${options.productName || 'Application'} ${state.version}`;\n parts.feedback(message).update({message:error || state.message,tone:'info'});\n const busy = ['checking', 'installing', 'restarting'].includes(state.phase);\n parts.action(check).update({disabled:!state.enabled || (busy && !retryCheck),pending});\n install.hidden = !state.availableVersion; parts.action(install).update({disabled:busy,pending,label:'Update and restart'});\n progress.hidden = state.phase !== 'installing'; progress.value = state.progress;\n }\n return {\n element,\n update(value: Readonly<UpdatePanelState>): void { state = value; error = ''; retryCheck = false; render(); },\n setPending(value: boolean): void { pending = value; render(); },\n setError(value: string, options: { allowCheckRetry?: boolean } = {}): void { if (!destroyed) { error = value; retryCheck = !!options.allowCheckRetry; render(); } },\n destroy(): void { if (destroyed) return; destroyed = true; parts.destroy(); check.removeEventListener('click', checkAction); install.removeEventListener('click', installAction); },\n };\n}\n\nexport interface CompletionNoticeDisplay { id: string; runID: string; title: string; workspace: string }\nexport function historyStatusMarkup(status: 'approval' | 'running' | 'unread' | 'idle'): string {\n if (status === 'approval') return '<span class=\"pui-history-status pui-needs-approval\" role=\"img\" aria-label=\"Waiting for approval\" title=\"Waiting for approval\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v6m0 4h.01\"/></svg></span>';\n if (status === 'running') return '<span class=\"pui-history-status\" role=\"img\" aria-label=\"Running\" title=\"Running\"><i class=\"pui-history-spinner\" aria-hidden=\"true\"></i></span>';\n if (status === 'unread') return '<span class=\"pui-history-status\" role=\"img\" aria-label=\"Completed, unread\" title=\"Completed, unread\"><i class=\"pui-history-unread\" aria-hidden=\"true\"></i></span>';\n return '<span class=\"pui-history-status\" aria-hidden=\"true\"></span>';\n}\nexport function createCompletionNotices(options: { container?: HTMLElement; onOpen?: (id: string) => void; onDismiss?: (runID: string) => void } = {}): UIBlock<readonly CompletionNoticeDisplay[]> {\n const element = options.container || document.createElement('div');\n const parts = adoptProductParts(element);\n const entries = new Map<string, { element: HTMLElement; text: HTMLElement; open: HTMLButtonElement; dismiss: HTMLButtonElement }>();\n let destroyed = false;\n const click = (event: Event) => {\n const target = (event.target as Element).closest<HTMLElement>('[data-conversation], [data-dismiss-completion]');\n if (!target || !element.contains(target)) return;\n if (target.dataset.conversation) options.onOpen?.(target.dataset.conversation);\n else if (target.dataset.dismissCompletion) options.onDismiss?.(target.dataset.dismissCompletion);\n };\n if (options.onOpen || options.onDismiss) element.addEventListener('click', click);\n return {\n element,\n update(notices): void {\n if (destroyed) return;\n const focused = document.activeElement;\n const keep = new Set(notices.map(notice => notice.runID));\n for (const [id, entry] of entries) if (!keep.has(id)) { entry.element.remove(); entries.delete(id); }\n let cursor = element.firstElementChild;\n for (const notice of notices) {\n let entry = entries.get(notice.runID);\n if (!entry) {\n const article = document.createElement('article'); article.className = 'pui-completion-notice';\n article.innerHTML = `<span class=\"pui-completion-check\" aria-hidden=\"true\">${icon('check')}</span><div class=\"pui-completion-content\"><strong>Task completed</strong><p></p><button class=\"pui-text-button\" type=\"button\" data-conversation>Open conversation</button></div><button class=\"pui-quiet-icon pui-completion-dismiss\" type=\"button\" data-dismiss-completion aria-label=\"Dismiss completion notification\">${icon('close')}</button>`;\n entry = { element: article, text: article.querySelector('p')!, open: article.querySelector('[data-conversation]')!, dismiss: article.querySelector('[data-dismiss-completion]')! };\n entries.set(notice.runID, entry);\n }\n setText(entry.text, `${notice.workspace} · ${notice.title}`);\n parts.action(entry.open).update({label:'Open conversation'});\n parts.action(entry.dismiss).update({label:'Dismiss completion notification'});\n if (entry.open.dataset.conversation !== notice.id) entry.open.dataset.conversation = notice.id;\n if (entry.dismiss.dataset.dismissCompletion !== notice.runID) entry.dismiss.dataset.dismissCompletion = notice.runID;\n if (entry.element !== cursor) element.insertBefore(entry.element, cursor);\n cursor = entry.element.nextElementSibling;\n }\n parts.update();\n if (focused instanceof HTMLElement && element.contains(focused) && document.activeElement !== focused) focused.focus({ preventScroll: true });\n },\n destroy(): void { if (destroyed) return; destroyed = true; parts.destroy(); entries.clear(); element.removeEventListener?.('click', click); element.replaceChildren(); },\n };\n}\n\nexport function createCopyFeedback(options: { status: HTMLElement; isDisabled: (button: HTMLButtonElement) => boolean; onError: (error: unknown) => void }) {\n let destroyed = false;\n const notice = adoptFeedback(options.status, {presentation:'inline',autoHide:false});\n type CopyEntry = { controller: ActionController; original: ChildNode[]; label: string | null; title: string; displayed: boolean; timer?: ReturnType<typeof setTimeout> };\n const entries = new Map<HTMLButtonElement, CopyEntry>();\n const release = (button: HTMLButtonElement, entry: CopyEntry): void => {\n if (entry.timer) clearTimeout(entry.timer);\n if (entry.displayed && button.isConnected) {\n button.replaceChildren(...entry.original);\n if (entry.label === null) button.removeAttribute('aria-label'); else button.setAttribute('aria-label', entry.label);\n button.title = entry.title;\n }\n delete button.dataset.copyPending;\n entry.controller.update({disabled:options.isDisabled(button)});\n entry.controller.destroy();\n entries.delete(button);\n };\n return {\n async copy(button: HTMLButtonElement, action: () => Promise<void>, announcement: string): Promise<void> {\n if (destroyed || button.dataset.copyPending === 'true') return;\n const entry: CopyEntry = { controller:adoptAction(button), original:[...button.childNodes], label:button.getAttribute('aria-label'), title:button.title, displayed:false };\n entries.set(button, entry);\n notice.update({message:'',tone:'info'}); button.dataset.copyPending = 'true'; entry.controller.update({disabled:options.isDisabled(button)});\n try {\n await action();\n if (destroyed) return;\n notice.update({message:announcement,tone:'info'});\n if (!button.isConnected) { release(button, entry); return; }\n button.innerHTML = button.classList.contains('pui-message-action') ? icon('check') : 'Copied';\n button.setAttribute('aria-label', announcement); button.title = announcement;\n entry.displayed = true;\n entry.timer = setTimeout(() => { if (!destroyed && entries.get(button) === entry) release(button, entry); }, 1500);\n } catch (error) {\n if (destroyed) return;\n release(button, entry); options.onError(error);\n }\n },\n destroy(): void { if (destroyed) return; destroyed = true; for (const [button, entry] of entries) release(button, entry); notice.destroy(); },\n };\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { UIBlock, UIAction } from '../core.js';
|
|
2
|
+
export interface ProviderActionsState {
|
|
3
|
+
id: string;
|
|
4
|
+
oauth: boolean;
|
|
5
|
+
signedIn: boolean;
|
|
6
|
+
custom: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ResourceActionsState {
|
|
9
|
+
kind: string;
|
|
10
|
+
resource: {
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
};
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function providerActionsMarkup(provider: ProviderActionsState): string;
|
|
17
|
+
export declare function resourceActionsMarkup(kind: string, resource: {
|
|
18
|
+
name: string;
|
|
19
|
+
path: string;
|
|
20
|
+
}, workspaceId: string): string;
|
|
21
|
+
export interface FeatureActionOptions {
|
|
22
|
+
onAction?: (action: string, target: DOMStringMap) => ReturnType<UIAction>;
|
|
23
|
+
onError?: (message: string) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function createProviderActions(state: ProviderActionsState, options?: FeatureActionOptions): UIBlock<ProviderActionsState>;
|
|
26
|
+
export declare function createResourceActions(state: ResourceActionsState, options?: FeatureActionOptions): UIBlock<ResourceActionsState>;
|
|
27
|
+
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/forms/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGpD,MAAM,WAAW,oBAAoB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC;AACtG,MAAM,WAAW,oBAAoB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC;AACjH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,CAA+lB;AAC5qB,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAGvH;AACD,MAAM,WAAW,oBAAoB;IAAE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,KAAK,UAAU,CAAC,QAAQ,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAC;AAiBtJ,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAyD;AAC9L,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAmH"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { escape } from '../dom.js';
|
|
2
|
+
import { adoptAction } from '../foundations.js';
|
|
3
|
+
export function providerActionsMarkup(provider) { return `<div class="pui-feature-toolbar">${provider.oauth ? `<button type="button" class="pui-secondary-button" data-sdk="${provider.signedIn ? 'logout' : 'login'}" data-id="${escape(provider.id)}">${provider.signedIn ? 'Sign out' : 'Sign in with provider'}</button>` : ''}${provider.custom ? `<button type="button" class="pui-secondary-button" data-sdk="custom" data-id="${escape(provider.id)}">Edit models and prices</button><button type="button" class="pui-secondary-button pui-destructive-button" data-sdk="remove-connection" data-id="${escape(provider.id)}">Remove connection</button>` : ''}</div>`; }
|
|
4
|
+
export function resourceActionsMarkup(kind, resource, workspaceId) {
|
|
5
|
+
const command = kind === 'skill' ? `/skill:${resource.name} ` : `/${resource.name} `;
|
|
6
|
+
return `<div class="pui-file-actions">${kind !== 'instructions' ? `<button class="pui-secondary-button" data-sdk="use-resource" data-command="${escape(command)}">Use</button>` : ''}<button class="pui-secondary-button" data-sdk="resource" data-resource-workspace="${escape(workspaceId)}" data-kind="${kind}" data-path="${escape(resource.path)}">View / edit</button></div>`;
|
|
7
|
+
}
|
|
8
|
+
function actions(initial, markup, options) {
|
|
9
|
+
const element = document.createElement('div');
|
|
10
|
+
element.className = 'pui-feature-actions';
|
|
11
|
+
let destroyed = false, signature = '';
|
|
12
|
+
let handles = [];
|
|
13
|
+
const update = (state) => {
|
|
14
|
+
if (destroyed)
|
|
15
|
+
return;
|
|
16
|
+
const next = markup(state);
|
|
17
|
+
if (next === signature)
|
|
18
|
+
return;
|
|
19
|
+
signature = next;
|
|
20
|
+
handles.forEach(handle => handle.destroy());
|
|
21
|
+
handles = [];
|
|
22
|
+
element.innerHTML = next;
|
|
23
|
+
if (options.onAction)
|
|
24
|
+
for (const button of element.querySelectorAll('[data-sdk]')) {
|
|
25
|
+
// Stop before the owned callback runs: it may synchronously replace or
|
|
26
|
+
// destroy this block, removing listeners further up the bubbling path.
|
|
27
|
+
const stopDelegation = (event) => event.stopPropagation();
|
|
28
|
+
button.addEventListener('click', stopDelegation);
|
|
29
|
+
const handle = adoptAction(button, { onAction: () => options.onAction(button.dataset.sdk, button.dataset), onError: options.onError });
|
|
30
|
+
handles.push({ ...handle, destroy() { button.removeEventListener('click', stopDelegation); handle.destroy(); } });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
update(initial);
|
|
34
|
+
return { element, update, destroy() { if (destroyed)
|
|
35
|
+
return; destroyed = true; handles.forEach(handle => handle.destroy()); handles = []; element.remove(); } };
|
|
36
|
+
}
|
|
37
|
+
export function createProviderActions(state, options = {}) { return actions(state, providerActionsMarkup, options); }
|
|
38
|
+
export function createResourceActions(state, options = {}) { return actions(state, (state) => resourceActionsMarkup(state.kind, state.resource, state.workspaceId), options); }
|
|
39
|
+
//# sourceMappingURL=actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/forms/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock, UIAction } from '../core.js';\nimport { escape } from '../dom.js';\nimport {adoptAction, type ActionController} from '../foundations.js';\nexport interface ProviderActionsState {id: string; oauth: boolean; signedIn: boolean; custom: boolean}\nexport interface ResourceActionsState {kind: string; resource: {name: string; path: string}; workspaceId: string}\nexport function providerActionsMarkup(provider: ProviderActionsState): string {return `<div class=\"pui-feature-toolbar\">${provider.oauth ? `<button type=\"button\" class=\"pui-secondary-button\" data-sdk=\"${provider.signedIn ? 'logout' : 'login'}\" data-id=\"${escape(provider.id)}\">${provider.signedIn ? 'Sign out' : 'Sign in with provider'}</button>` : ''}${provider.custom ? `<button type=\"button\" class=\"pui-secondary-button\" data-sdk=\"custom\" data-id=\"${escape(provider.id)}\">Edit models and prices</button><button type=\"button\" class=\"pui-secondary-button pui-destructive-button\" data-sdk=\"remove-connection\" data-id=\"${escape(provider.id)}\">Remove connection</button>` : ''}</div>`;}\nexport function resourceActionsMarkup(kind: string, resource: {name: string; path: string}, workspaceId: string): string {\n const command = kind === 'skill' ? `/skill:${resource.name} ` : `/${resource.name} `;\n return `<div class=\"pui-file-actions\">${kind !== 'instructions' ? `<button class=\"pui-secondary-button\" data-sdk=\"use-resource\" data-command=\"${escape(command)}\">Use</button>` : ''}<button class=\"pui-secondary-button\" data-sdk=\"resource\" data-resource-workspace=\"${escape(workspaceId)}\" data-kind=\"${kind}\" data-path=\"${escape(resource.path)}\">View / edit</button></div>`;\n}\nexport interface FeatureActionOptions {onAction?: (action: string, target: DOMStringMap) => ReturnType<UIAction>; onError?: (message: string) => void}\nfunction actions<State>(initial: State, markup: (state: State) => string, options: FeatureActionOptions): UIBlock<State> {\n const element = document.createElement('div'); element.className = 'pui-feature-actions'; let destroyed = false, signature = ''; let handles: ActionController[] = [];\n const update = (state: Readonly<State>) => {\n if (destroyed) return; const next = markup(state); if (next === signature) return; signature = next;\n handles.forEach(handle => handle.destroy()); handles = []; element.innerHTML = next;\n if (options.onAction) for (const button of element.querySelectorAll<HTMLButtonElement>('[data-sdk]')) {\n // Stop before the owned callback runs: it may synchronously replace or\n // destroy this block, removing listeners further up the bubbling path.\n const stopDelegation = (event: Event) => event.stopPropagation();\n button.addEventListener('click',stopDelegation);\n const handle = adoptAction(button, {onAction: () => options.onAction!(button.dataset.sdk!, button.dataset), onError: options.onError});\n handles.push({...handle,destroy() {button.removeEventListener('click',stopDelegation);handle.destroy();}});\n }\n }; update(initial);\n return {element, update, destroy() {if (destroyed) return; destroyed = true; handles.forEach(handle => handle.destroy()); handles = []; element.remove();}};\n}\nexport function createProviderActions(state: ProviderActionsState, options: FeatureActionOptions = {}): UIBlock<ProviderActionsState> {return actions(state, providerActionsMarkup, options);}\nexport function createResourceActions(state: ResourceActionsState, options: FeatureActionOptions = {}): UIBlock<ResourceActionsState> {return actions(state, (state) => resourceActionsMarkup(state.kind, state.resource, state.workspaceId), options);}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ActionResult, UIBlock } from '../core.js';
|
|
2
|
+
export interface CustomModelValue {
|
|
3
|
+
id: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
contextWindow?: number;
|
|
6
|
+
maxTokens?: number;
|
|
7
|
+
reasoning?: boolean;
|
|
8
|
+
input?: readonly string[];
|
|
9
|
+
cost?: {
|
|
10
|
+
input: number;
|
|
11
|
+
output: number;
|
|
12
|
+
cacheRead: number;
|
|
13
|
+
cacheWrite: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface CustomConnectionState {
|
|
17
|
+
name: string;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
api: string;
|
|
20
|
+
editing: boolean;
|
|
21
|
+
models: readonly CustomModelValue[];
|
|
22
|
+
error?: string;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface CustomModelDraft {
|
|
26
|
+
sourceIndex: number;
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
contextWindow: number;
|
|
30
|
+
maxTokens: number;
|
|
31
|
+
reasoning: boolean;
|
|
32
|
+
images: boolean;
|
|
33
|
+
prices: {
|
|
34
|
+
input: string;
|
|
35
|
+
output: string;
|
|
36
|
+
cacheRead: string;
|
|
37
|
+
cacheWrite: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface CustomConnectionDraft {
|
|
41
|
+
name: string;
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
api: string;
|
|
44
|
+
apiKey: string;
|
|
45
|
+
models: CustomModelDraft[];
|
|
46
|
+
}
|
|
47
|
+
export interface CustomModelRowState extends CustomModelValue {
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare function createCustomModelRow(model: CustomModelRowState, index?: number): UIBlock<CustomModelRowState> & {
|
|
52
|
+
read(): CustomModelDraft;
|
|
53
|
+
reset(model: CustomModelValue): void;
|
|
54
|
+
};
|
|
55
|
+
export declare function createCustomConnectionEditor(state: CustomConnectionState, options?: {
|
|
56
|
+
idPrefix?: string;
|
|
57
|
+
onSubmit?: (draft: CustomConnectionDraft) => ActionResult | Promise<ActionResult>;
|
|
58
|
+
}): UIBlock<CustomConnectionState> & {
|
|
59
|
+
read(): CustomConnectionDraft;
|
|
60
|
+
readonly form: HTMLFormElement;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=custom-connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-connection.d.ts","sourceRoot":"","sources":["../../src/forms/custom-connection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,YAAY,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC;AACxO,MAAM,WAAW,qBAAqB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AAC9K,MAAM,WAAW,gBAAgB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC;AAChP,MAAM,WAAW,qBAAqB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAC;AAG/H,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC;AAClG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG;IAAC,IAAI,IAAI,gBAAgB,CAAC;IAAC,KAAK,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAC,CAe3K;AACD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,GAAE;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;CAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,GAAG;IAAC,IAAI,IAAI,qBAAqB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAC,CAcjS"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { scopeIds, localField, bindFormSubmission } from './identity.js';
|
|
2
|
+
import { escape, uniqueId } from '../dom.js';
|
|
3
|
+
import { adoptProductParts } from '../foundations.js';
|
|
4
|
+
const protocols = ['openai-completions', 'openai-responses', 'anthropic-messages', 'google-generative-ai', 'mistral-conversations'];
|
|
5
|
+
function modelRowMarkup(model, index) { return `<fieldset class="pui-custom-model" data-model-index="${index}"><legend>Model ${index + 1}</legend><label>Model ID<input name="id" required value="${escape(model.id)}" /></label><label>Display name<input name="name" value="${escape(model.name || '')}" /></label><div class="pui-sdk-grid"><label>Context tokens<input name="contextWindow" type="number" min="1" required value="${escape(model.contextWindow)}" /></label><label>Max output tokens<input name="maxTokens" type="number" min="1" required value="${escape(model.maxTokens)}" /></label></div><div class="pui-sdk-grid"><label class="pui-checkbox-field"><input name="reasoning" type="checkbox" ${model.reasoning ? 'checked' : ''} />Thinking effort</label><label class="pui-checkbox-field"><input name="images" type="checkbox" ${model.input?.includes('image') ? 'checked' : ''} />Images</label></div><details class="pui-provider-advanced"><summary>Price estimate (optional)</summary><div class="pui-sdk-grid">${['input', 'output', 'cacheRead', 'cacheWrite'].map((rate) => `<label>${{ input: "Input", output: "Output", cacheRead: "Cache read", cacheWrite: "Cache write" }[rate]}<input name="price-${rate}" type="number" min="0" step="any" value="${escape(model.cost?.[rate] ?? '')}" /></label>`).join('')}</div></details><button type="button" class="pui-secondary-button pui-destructive-button" data-remove-model>Remove model</button></fieldset>`; }
|
|
6
|
+
export function createCustomModelRow(model, index = 0) {
|
|
7
|
+
const element = document.createElement('div');
|
|
8
|
+
element.className = 'pui-custom-model-row';
|
|
9
|
+
element.innerHTML = modelRowMarkup(model, index);
|
|
10
|
+
const field = element.querySelector('fieldset');
|
|
11
|
+
const error = document.createElement('p');
|
|
12
|
+
error.className = 'pui-form-error';
|
|
13
|
+
error.setAttribute('role', 'alert');
|
|
14
|
+
element.append(error);
|
|
15
|
+
const parts = adoptProductParts(element);
|
|
16
|
+
let destroyed = false;
|
|
17
|
+
const input = (name) => field.querySelector(`[name="${name}"]`);
|
|
18
|
+
const reset = (value) => {
|
|
19
|
+
if (destroyed)
|
|
20
|
+
return;
|
|
21
|
+
parts.control(input('id')).reset(value.id);
|
|
22
|
+
parts.control(input('name')).reset(value.name || '');
|
|
23
|
+
parts.control(input('contextWindow')).reset(value.contextWindow === undefined ? '' : String(value.contextWindow));
|
|
24
|
+
parts.control(input('maxTokens')).reset(value.maxTokens === undefined ? '' : String(value.maxTokens));
|
|
25
|
+
parts.control(input('reasoning')).reset(!!value.reasoning);
|
|
26
|
+
parts.control(input('images')).reset(!!value.input?.includes('image'));
|
|
27
|
+
for (const rate of ['input', 'output', 'cacheRead', 'cacheWrite'])
|
|
28
|
+
parts.control(input('price-' + rate)).reset(value.cost?.[rate] === undefined ? '' : String(value.cost[rate]));
|
|
29
|
+
};
|
|
30
|
+
const value = (name) => parts.control(input(name)).getValue();
|
|
31
|
+
const read = () => ({ sourceIndex: index, id: value('id').trim(), name: value('name').trim(), contextWindow: Number(value('contextWindow')), maxTokens: Number(value('maxTokens')), reasoning: parts.control(input('reasoning')).getChecked(), images: parts.control(input('images')).getChecked(), prices: { input: value('price-input'), output: value('price-output'), cacheRead: value('price-cacheRead'), cacheWrite: value('price-cacheWrite') } });
|
|
32
|
+
const update = (state) => { if (destroyed)
|
|
33
|
+
return; if (state.disabled !== undefined)
|
|
34
|
+
field.disabled = state.disabled; if (state.error !== undefined)
|
|
35
|
+
parts.feedback(error).update({ message: state.error, tone: 'error' }); };
|
|
36
|
+
update(model);
|
|
37
|
+
return { element, read, reset, update, destroy() { if (destroyed)
|
|
38
|
+
return; destroyed = true; parts.destroy(); element.remove(); } };
|
|
39
|
+
}
|
|
40
|
+
export function createCustomConnectionEditor(state, options = {}) {
|
|
41
|
+
const element = document.createElement('div');
|
|
42
|
+
element.className = 'pui-custom-connection-editor';
|
|
43
|
+
element.innerHTML = `<p class="pui-modal-description">Give this endpoint its own name. It can coexist with official providers and other compatible endpoints.</p><form id="custom-form"><label class="pui-field-label">Connection name<input id="custom-name" required value="${escape(state.name)}" /></label><label class="pui-field-label">API base URL<input id="custom-url" type="url" required value="${escape(state.baseUrl)}" placeholder="https://example.com/v1" /></label><label class="pui-field-label">API protocol<select id="custom-api" class="pui-feature-select">${protocols.map((p) => `<option ${state.api === p ? 'selected' : ''}>${p}</option>`).join('')}</select></label><label class="pui-field-label">API key<input id="custom-key" type="password" autocomplete="new-password" placeholder="${state.editing ? 'Leave blank to keep the key at the same endpoint' : 'API key (optional for local endpoints)'}" /></label><div id="custom-models"></div><button type="button" class="pui-secondary-button" id="add-custom-model">Add model</button><p class="pui-field-hint">Limits and capabilities are provided by you. Prices are USD per million tokens. Fill all four rates (0 for free/unused), or leave all four blank for unknown prices.</p><p class="pui-form-error" data-custom-error role="alert"></p><div class="pui-modal-footer"><button type="button" class="pui-secondary-button" data-close="sdk-dialog">Cancel</button><button class="pui-primary-button" type="submit">Save connection</button></div></form>`;
|
|
44
|
+
const prefix = options.idPrefix ?? uniqueId('pui-custom') + '-';
|
|
45
|
+
scopeIds(element, prefix);
|
|
46
|
+
const $ = (id) => localField(element, prefix + id);
|
|
47
|
+
const form = $('custom-form');
|
|
48
|
+
const parts = adoptProductParts(element), rows = new Map();
|
|
49
|
+
let nextIndex = 0, destroyed = false, pending = false;
|
|
50
|
+
const abort = new AbortController();
|
|
51
|
+
let current = state;
|
|
52
|
+
const add = (model) => { const index = nextIndex++; const row = createCustomModelRow(model, index); rows.set(index, row); $('custom-models').append(row.element); if (current.disabled || pending)
|
|
53
|
+
for (const button of row.element.querySelectorAll('button'))
|
|
54
|
+
button.disabled = true; };
|
|
55
|
+
state.models.forEach(add);
|
|
56
|
+
$('add-custom-model').addEventListener('click', () => { if (!current.disabled && !pending)
|
|
57
|
+
add({ id: '', contextWindow: 128000, maxTokens: 8192 }); }, { signal: abort.signal });
|
|
58
|
+
$('custom-models').addEventListener('click', event => { const target = event.target.closest('[data-remove-model]'); if (!target || target.disabled || current.disabled || pending)
|
|
59
|
+
return; const index = Number(target.closest('[data-model-index]')?.dataset.modelIndex); rows.get(index)?.destroy(); rows.delete(index); }, { signal: abort.signal });
|
|
60
|
+
const read = () => ({ name: parts.control($('custom-name')).getValue(), baseUrl: parts.control($('custom-url')).getValue(), api: parts.control($('custom-api')).getValue(), apiKey: parts.control($('custom-key')).getValue(), models: [...rows.values()].map(row => row.read()) });
|
|
61
|
+
const update = (next) => { if (destroyed)
|
|
62
|
+
return; current = next; if (next.error !== undefined)
|
|
63
|
+
parts.feedback(element.querySelector('[data-custom-error]')).update({ message: next.error, tone: 'error' }); parts.update(); for (const button of form.querySelectorAll('button'))
|
|
64
|
+
parts.action(button).update({ disabled: next.disabled, pending: button.hasAttribute('data-close') ? false : pending }); };
|
|
65
|
+
const submission = bindFormSubmission(form, { read, unavailable: () => !!current.disabled, onSubmit: options.onSubmit, onPending(value) { pending = value; update(current); }, onError(error) { update({ ...current, error }); } });
|
|
66
|
+
update(state);
|
|
67
|
+
return { element, form, read, update, destroy() { if (destroyed)
|
|
68
|
+
return; destroyed = true; submission.destroy(); abort.abort(); for (const row of rows.values())
|
|
69
|
+
row.destroy(); rows.clear(); for (const input of element.querySelectorAll('input[type="password"]'))
|
|
70
|
+
parts.control(input).reset(''); parts.destroy(); element.remove(); } };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=custom-connection.js.map
|