pith-ui 0.1.0 → 0.1.4
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 +20 -1
- package/API.md +834 -272
- package/README.md +3 -1
- package/dist/composer.d.ts.map +1 -1
- package/dist/composer.js +48 -29
- package/dist/composer.js.map +1 -1
- package/dist/content/conversation-reader.d.ts.map +1 -1
- package/dist/content/conversation-reader.js +8 -1
- package/dist/content/conversation-reader.js.map +1 -1
- package/dist/content/conversation-view.d.ts +21 -4
- package/dist/content/conversation-view.d.ts.map +1 -1
- package/dist/content/conversation-view.js +72 -13
- package/dist/content/conversation-view.js.map +1 -1
- package/dist/content/image-viewer.d.ts +4 -2
- package/dist/content/image-viewer.d.ts.map +1 -1
- package/dist/content/image-viewer.js +36 -15
- package/dist/content/image-viewer.js.map +1 -1
- package/dist/content/paged-preview.d.ts +1 -1
- package/dist/content/paged-preview.d.ts.map +1 -1
- package/dist/content/paged-preview.js +10 -5
- package/dist/content/paged-preview.js.map +1 -1
- package/dist/content/views.d.ts +3 -0
- package/dist/content/views.d.ts.map +1 -1
- package/dist/content/views.js +110 -41
- package/dist/content/views.js.map +1 -1
- package/dist/content/welcome.d.ts.map +1 -1
- package/dist/content/welcome.js +19 -7
- package/dist/content/welcome.js.map +1 -1
- package/dist/dom.js +1 -1
- package/dist/dom.js.map +1 -1
- package/dist/files/panels.d.ts +8 -1
- package/dist/files/panels.d.ts.map +1 -1
- package/dist/files/panels.js +235 -120
- package/dist/files/panels.js.map +1 -1
- package/dist/files/systems.d.ts.map +1 -1
- package/dist/files/systems.js +81 -91
- package/dist/files/systems.js.map +1 -1
- package/dist/forms/actions.d.ts +28 -7
- package/dist/forms/actions.d.ts.map +1 -1
- package/dist/forms/actions.js +59 -11
- package/dist/forms/actions.js.map +1 -1
- package/dist/forms/custom-connection.d.ts +2 -1
- package/dist/forms/custom-connection.d.ts.map +1 -1
- package/dist/forms/custom-connection.js +36 -28
- package/dist/forms/custom-connection.js.map +1 -1
- package/dist/forms/dialog-frame.d.ts +2 -0
- package/dist/forms/dialog-frame.d.ts.map +1 -1
- package/dist/forms/dialog-frame.js +46 -26
- package/dist/forms/dialog-frame.js.map +1 -1
- package/dist/forms/history.d.ts +1 -1
- package/dist/forms/history.d.ts.map +1 -1
- package/dist/forms/history.js +78 -15
- package/dist/forms/history.js.map +1 -1
- package/dist/forms/identity.d.ts +12 -0
- package/dist/forms/identity.d.ts.map +1 -1
- package/dist/forms/identity.js +16 -0
- package/dist/forms/identity.js.map +1 -1
- package/dist/forms/model-editor.d.ts +8 -3
- package/dist/forms/model-editor.d.ts.map +1 -1
- package/dist/forms/model-editor.js +73 -62
- package/dist/forms/model-editor.js.map +1 -1
- package/dist/forms/panels.d.ts +103 -7
- package/dist/forms/panels.d.ts.map +1 -1
- package/dist/forms/panels.js +183 -77
- package/dist/forms/panels.js.map +1 -1
- package/dist/forms/provider-login.d.ts.map +1 -1
- package/dist/forms/provider-login.js +25 -39
- package/dist/forms/provider-login.js.map +1 -1
- package/dist/forms/resource-editor.d.ts +9 -5
- package/dist/forms/resource-editor.d.ts.map +1 -1
- package/dist/forms/resource-editor.js +20 -9
- package/dist/forms/resource-editor.js.map +1 -1
- package/dist/foundations.d.ts +95 -0
- package/dist/foundations.d.ts.map +1 -0
- package/dist/foundations.js +299 -0
- package/dist/foundations.js.map +1 -0
- package/dist/navigation/context-menu.d.ts +8 -1
- package/dist/navigation/context-menu.d.ts.map +1 -1
- package/dist/navigation/context-menu.js +67 -50
- package/dist/navigation/context-menu.js.map +1 -1
- package/dist/navigation/navigation.d.ts +55 -7
- package/dist/navigation/navigation.d.ts.map +1 -1
- package/dist/navigation/navigation.js +167 -18
- package/dist/navigation/navigation.js.map +1 -1
- package/dist/operation.d.ts +12 -0
- package/dist/operation.d.ts.map +1 -0
- package/dist/operation.js +49 -0
- package/dist/operation.js.map +1 -0
- package/dist/primitives.d.ts +11 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +164 -301
- package/dist/primitives.js.map +1 -1
- package/dist/reconcile.d.ts +11 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +36 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/select.d.ts +14 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +304 -0
- package/dist/select.js.map +1 -0
- package/dist/styles.css +452 -382
- package/dist/surface.d.ts +60 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +344 -0
- package/dist/surface.js.map +1 -0
- package/dist/tasks/approval.d.ts.map +1 -1
- package/dist/tasks/approval.js +86 -45
- package/dist/tasks/approval.js.map +1 -1
- package/dist/tasks/permission-element.d.ts +3 -0
- package/dist/tasks/permission-element.d.ts.map +1 -0
- package/dist/tasks/permission-element.js +10 -0
- package/dist/tasks/permission-element.js.map +1 -0
- package/dist/tasks/permission.d.ts +5 -3
- package/dist/tasks/permission.d.ts.map +1 -1
- package/dist/tasks/permission.js +47 -22
- package/dist/tasks/permission.js.map +1 -1
- package/dist/tasks/runtime.d.ts.map +1 -1
- package/dist/tasks/runtime.js +30 -13
- package/dist/tasks/runtime.js.map +1 -1
- package/dist/workspace.d.ts +58 -4
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +202 -44
- package/dist/workspace.js.map +1 -1
- package/package.json +1 -1
package/dist/workspace.d.ts
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ActionResult } from './core.js';
|
|
2
2
|
export interface ComposerViewState {
|
|
3
3
|
placeholder?: string;
|
|
4
4
|
disabled?: boolean;
|
|
5
5
|
readOnly?: boolean;
|
|
6
6
|
action?: 'send' | 'queue' | 'stop';
|
|
7
7
|
actionDisabled?: boolean;
|
|
8
|
+
model?: {
|
|
9
|
+
label: string;
|
|
10
|
+
description: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
thinking?: {
|
|
14
|
+
options: readonly {
|
|
15
|
+
value: string;
|
|
16
|
+
label: string;
|
|
17
|
+
}[];
|
|
18
|
+
value: string;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
};
|
|
8
21
|
}
|
|
9
22
|
export interface ComposerViewOptions {
|
|
10
23
|
prefix?: string;
|
|
11
24
|
onSubmit?: (text: string) => void | ActionResult | Promise<void | ActionResult>;
|
|
12
25
|
onStop?: () => void | ActionResult | Promise<void | ActionResult>;
|
|
13
26
|
onInput?: (text: string) => void;
|
|
27
|
+
onModel?: () => void;
|
|
28
|
+
onAttach?: () => void;
|
|
29
|
+
onImages?: (files: File[]) => void;
|
|
30
|
+
onThinkingChange?: (value: string) => void;
|
|
14
31
|
}
|
|
15
32
|
export declare function createComposerView(options?: ComposerViewOptions): {
|
|
16
33
|
element: HTMLFormElement;
|
|
@@ -20,19 +37,56 @@ export declare function createComposerView(options?: ComposerViewOptions): {
|
|
|
20
37
|
reset(value: string): void;
|
|
21
38
|
focus: () => void;
|
|
22
39
|
resize: () => void;
|
|
40
|
+
pickImages(): void;
|
|
23
41
|
destroy(): void;
|
|
24
42
|
};
|
|
43
|
+
export type WorkspaceDialogName = 'model' | 'settings' | 'workspace' | 'permissions' | 'delete' | 'rename' | 'queue-edit' | 'message-edit' | 'resources' | 'connections' | 'preview' | 'image';
|
|
44
|
+
export interface ActionScope {
|
|
45
|
+
kind: 'global' | 'conversation' | 'workspace' | 'active';
|
|
46
|
+
id?: string;
|
|
47
|
+
}
|
|
25
48
|
export interface WorkspaceShellOptions {
|
|
26
49
|
brand: Node;
|
|
27
50
|
prefix?: string;
|
|
51
|
+
composer?: ComposerViewOptions;
|
|
52
|
+
onDialogClose?: (name: WorkspaceDialogName) => void;
|
|
53
|
+
onSearch?: (query: string) => void;
|
|
54
|
+
onBusyAction?: (key: string) => void;
|
|
28
55
|
}
|
|
29
56
|
export interface WorkspaceShellState {
|
|
30
57
|
workspace?: string;
|
|
31
58
|
conversation?: string;
|
|
32
59
|
reconnecting?: boolean;
|
|
60
|
+
error?: {
|
|
61
|
+
message: string;
|
|
62
|
+
hidden?: boolean;
|
|
63
|
+
};
|
|
64
|
+
busy?: {
|
|
65
|
+
key: string;
|
|
66
|
+
message: string;
|
|
67
|
+
actionLabel: string;
|
|
68
|
+
} | null;
|
|
33
69
|
}
|
|
34
|
-
export declare function createWorkspaceShell(options: WorkspaceShellOptions):
|
|
35
|
-
|
|
36
|
-
|
|
70
|
+
export declare function createWorkspaceShell(options: WorkspaceShellOptions): {
|
|
71
|
+
element: HTMLDivElement;
|
|
72
|
+
composer: {
|
|
73
|
+
element: HTMLFormElement;
|
|
74
|
+
input: HTMLTextAreaElement;
|
|
75
|
+
update: (state: ComposerViewState) => void;
|
|
76
|
+
getValue: () => string;
|
|
77
|
+
reset(value: string): void;
|
|
78
|
+
focus: () => void;
|
|
79
|
+
resize: () => void;
|
|
80
|
+
pickImages(): void;
|
|
81
|
+
destroy(): void;
|
|
82
|
+
};
|
|
83
|
+
part: <T extends HTMLElement = HTMLElement>(name: string) => T;
|
|
84
|
+
update(state: Readonly<WorkspaceShellState>): void;
|
|
85
|
+
setSidebarOpen: (open: boolean) => void;
|
|
86
|
+
openDialog(name: WorkspaceDialogName): void;
|
|
87
|
+
closeDialog(name: WorkspaceDialogName): void;
|
|
88
|
+
isDialogOpen(name: WorkspaceDialogName): boolean;
|
|
89
|
+
updateActionAvailability(unavailable: (scope: ActionScope) => boolean, root?: ParentNode): void;
|
|
90
|
+
destroy(): void;
|
|
37
91
|
};
|
|
38
92
|
//# sourceMappingURL=workspace.d.ts.map
|
package/dist/workspace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
|
package/dist/workspace.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { icon } from './dom.js';
|
|
1
|
+
import {} from './core.js';
|
|
2
|
+
import { focusableElements, icon } from './dom.js';
|
|
3
|
+
import { controlDisabled } from './core.js';
|
|
4
|
+
import { adoptProductParts, reconcileSelectOptions } from './foundations.js';
|
|
5
|
+
import { installDialogLifecycle } from './surface.js';
|
|
6
|
+
import { permissionControlElement } from './tasks/permission-element.js';
|
|
7
|
+
import { createOperation } from './operation.js';
|
|
3
8
|
let sequence = 0;
|
|
4
9
|
function identify(root, prefix) {
|
|
5
10
|
if (!prefix)
|
|
@@ -21,66 +26,73 @@ export function createComposerView(options = {}) {
|
|
|
21
26
|
<div class="pui-composer-toolbar">
|
|
22
27
|
<div class="pui-composer-context">
|
|
23
28
|
<button id="attach-images" type="button" class="pui-quiet-icon pui-attach-images" data-action="attach-images" aria-label="Attach images" title="Attach images">${icon('image')}</button>
|
|
24
|
-
<
|
|
29
|
+
<span data-permission-slot></span>
|
|
25
30
|
</div>
|
|
26
31
|
<div class="pui-composer-actions"><button id="composer-model" type="button" class="pui-composer-model" data-action="model" data-idle-action data-global-idle aria-label="Choose model">Choose model</button><label class="pui-composer-thinking"><span class="pui-sr-only">Thinking effort</span><select id="composer-thinking" aria-label="Thinking effort"></select></label><button id="send-button" class="pui-send-button" type="submit" aria-label="Send message">${icon('arrow')}</button></div>
|
|
27
32
|
</div>
|
|
28
33
|
</form>`;
|
|
29
34
|
const element = holder.firstElementChild;
|
|
35
|
+
const permission = permissionControlElement();
|
|
36
|
+
permission.id = 'permission-control';
|
|
37
|
+
const permissionMode = permission.querySelector('select');
|
|
38
|
+
permissionMode.id = 'permission-mode';
|
|
39
|
+
permissionMode.setAttribute('aria-describedby', 'permission-description');
|
|
40
|
+
element.querySelector('[data-permission-slot]').replaceWith(permission);
|
|
30
41
|
const input = element.querySelector('textarea');
|
|
31
42
|
const action = element.querySelector('[type="submit"]');
|
|
43
|
+
const model = element.querySelector('[data-action="model"]');
|
|
44
|
+
const thinking = element.querySelector('[aria-label="Thinking effort"]');
|
|
45
|
+
const thinkingLabel = thinking.closest('label');
|
|
46
|
+
const imagePicker = element.querySelector('[type="file"]');
|
|
32
47
|
identify(element, options.prefix ?? 'pui-composer-' + ++sequence + '-');
|
|
33
|
-
const
|
|
34
|
-
|
|
48
|
+
const parts = adoptProductParts(element);
|
|
49
|
+
parts.control(element.querySelector('[id$="permission-mode"]'));
|
|
50
|
+
parts.control(thinking);
|
|
51
|
+
let destroyed = false;
|
|
52
|
+
let last = {}, lastAction = 'send';
|
|
35
53
|
const error = document.createElement('div');
|
|
36
54
|
error.className = 'pui-form-error';
|
|
37
55
|
error.setAttribute('role', 'alert');
|
|
38
56
|
error.hidden = true;
|
|
39
57
|
element.insertBefore(error, element.firstChild);
|
|
58
|
+
const feedback = parts.feedback(error);
|
|
59
|
+
const setError = (message) => { feedback.update({ message, tone: 'error' }); error.hidden = !message; };
|
|
40
60
|
const resize = () => { input.style.height = 'auto'; input.style.height = Math.min(input.scrollHeight, 180) + 'px'; };
|
|
41
61
|
const update = (state) => {
|
|
62
|
+
if (destroyed)
|
|
63
|
+
return;
|
|
42
64
|
last = state;
|
|
43
|
-
|
|
44
|
-
input.placeholder = state.placeholder;
|
|
45
|
-
input.disabled = !!state.disabled;
|
|
46
|
-
input.readOnly = !!state.readOnly;
|
|
65
|
+
parts.control(input).update({ disabled: !!state.disabled, readOnly: !!state.readOnly, ...(state.placeholder !== undefined ? { placeholder: state.placeholder } : {}) });
|
|
47
66
|
if (state.action && state.action !== lastAction) {
|
|
48
67
|
lastAction = state.action;
|
|
49
68
|
action.type = state.action === 'stop' ? 'button' : 'submit';
|
|
50
69
|
action.innerHTML = icon(state.action === 'stop' ? 'stop' : 'arrow');
|
|
51
70
|
action.classList.toggle('pui-is-stop', state.action === 'stop');
|
|
52
|
-
action.setAttribute('aria-label', state.action === 'stop' ? 'Stop agent' : state.action === 'queue' ? 'Queue message' : 'Send message');
|
|
53
71
|
}
|
|
54
|
-
|
|
72
|
+
const actionLabel = lastAction === 'stop' ? 'Stop agent' : lastAction === 'queue' ? 'Queue message' : 'Send message';
|
|
73
|
+
action.setAttribute('aria-label', actionLabel);
|
|
74
|
+
action.title = actionLabel;
|
|
75
|
+
parts.action(action).update({ disabled: !!(state.actionDisabled || state.disabled), pending: operation.pending });
|
|
76
|
+
if (state.model) {
|
|
77
|
+
parts.action(model).update({ label: state.model.label, title: state.model.description, disabled: !!state.model.disabled });
|
|
78
|
+
}
|
|
79
|
+
if (state.thinking) {
|
|
80
|
+
const { options: choices, value, disabled } = state.thinking;
|
|
81
|
+
reconcileSelectOptions(thinking, choices, value);
|
|
82
|
+
thinkingLabel.hidden = choices.length < 2;
|
|
83
|
+
parts.control(thinking).update({ disabled: !!disabled });
|
|
84
|
+
}
|
|
85
|
+
parts.update();
|
|
55
86
|
};
|
|
87
|
+
const operation = createOperation({ unavailable: () => destroyed || action.disabled, onPending: () => update(last), onError: setError });
|
|
56
88
|
const onInput = () => { resize(); options.onInput?.(input.value); };
|
|
57
|
-
const run =
|
|
58
|
-
if (!callback ||
|
|
89
|
+
const run = (callback, textSubmission = true) => {
|
|
90
|
+
if (!callback || (textSubmission && (input.disabled || input.readOnly)))
|
|
59
91
|
return;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
update(last);
|
|
65
|
-
try {
|
|
66
|
-
const result = await callback();
|
|
67
|
-
if (generation.current(seq) && result && !result.ok) {
|
|
68
|
-
error.textContent = result.error;
|
|
69
|
-
error.hidden = false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch (reason) {
|
|
73
|
-
if (generation.current(seq)) {
|
|
74
|
-
error.textContent = reason instanceof Error ? reason.message : String(reason);
|
|
75
|
-
error.hidden = false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
if (generation.current(seq)) {
|
|
80
|
-
pending = false;
|
|
81
|
-
update(last);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
92
|
+
operation.run(() => { setError(''); return callback(); }, result => {
|
|
93
|
+
if (result && !result.ok)
|
|
94
|
+
setError(result.error);
|
|
95
|
+
});
|
|
84
96
|
};
|
|
85
97
|
const submit = (event) => { if (options.onSubmit) {
|
|
86
98
|
event.preventDefault();
|
|
@@ -88,20 +100,41 @@ export function createComposerView(options = {}) {
|
|
|
88
100
|
void run(() => options.onSubmit(text));
|
|
89
101
|
} };
|
|
90
102
|
const stop = () => { if (action.type === 'button')
|
|
91
|
-
void run(options.onStop); };
|
|
103
|
+
void run(options.onStop, false); };
|
|
92
104
|
const keydown = (event) => {
|
|
93
|
-
if (options.onSubmit && event.key === 'Enter' && !event.shiftKey && !event.isComposing
|
|
105
|
+
if (options.onSubmit && event.key === 'Enter' && !event.shiftKey && !event.isComposing) {
|
|
94
106
|
event.preventDefault();
|
|
95
|
-
|
|
107
|
+
if (action.type === 'submit')
|
|
108
|
+
element.requestSubmit();
|
|
96
109
|
}
|
|
97
110
|
};
|
|
111
|
+
const click = (event) => {
|
|
112
|
+
const button = event.target.closest('button');
|
|
113
|
+
if (!button || button.disabled)
|
|
114
|
+
return;
|
|
115
|
+
const callback = button === model ? options.onModel : button.hasAttribute('data-action') && button.dataset.action === 'attach-images' ? options.onAttach : undefined;
|
|
116
|
+
if (callback) {
|
|
117
|
+
event.stopPropagation();
|
|
118
|
+
callback();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const chooseThinking = () => options.onThinkingChange?.(thinking.value);
|
|
122
|
+
const images = () => { const files = Array.from(imagePicker.files ?? []); imagePicker.value = ''; options.onImages?.(files); };
|
|
123
|
+
element.addEventListener('click', click);
|
|
124
|
+
thinking.addEventListener('change', chooseThinking);
|
|
125
|
+
imagePicker.addEventListener('change', images);
|
|
98
126
|
input.addEventListener('input', onInput);
|
|
99
127
|
input.addEventListener('keydown', keydown);
|
|
100
128
|
element.addEventListener('submit', submit);
|
|
101
129
|
action.addEventListener('click', stop);
|
|
102
130
|
return { element, input, update, getValue: () => input.value,
|
|
103
|
-
reset(value) {
|
|
104
|
-
|
|
131
|
+
reset(value) { if (destroyed)
|
|
132
|
+
return; operation.invalidate(); setError(''); input.value = value; update(last); resize(); }, focus: () => { if (!destroyed)
|
|
133
|
+
input.focus(); }, resize,
|
|
134
|
+
pickImages() { if (!destroyed)
|
|
135
|
+
imagePicker.click(); },
|
|
136
|
+
destroy() { if (destroyed)
|
|
137
|
+
return; destroyed = true; operation.destroy(); parts.destroy(); input.removeEventListener('input', onInput); input.removeEventListener('keydown', keydown); element.removeEventListener('submit', submit); action.removeEventListener('click', stop); element.removeEventListener('click', click); thinking.removeEventListener('change', chooseThinking); imagePicker.removeEventListener('change', images); element.remove(); } };
|
|
105
138
|
}
|
|
106
139
|
export function createWorkspaceShell(options) {
|
|
107
140
|
const element = document.createElement('div');
|
|
@@ -168,16 +201,141 @@ export function createWorkspaceShell(options) {
|
|
|
168
201
|
`;
|
|
169
202
|
element.querySelector('[data-brand-slot]').replaceWith(options.brand);
|
|
170
203
|
const prefix = options.prefix ?? 'pui-workspace-' + ++sequence + '-';
|
|
171
|
-
const composer = createComposerView({ prefix: '' });
|
|
204
|
+
const composer = createComposerView({ ...options.composer, prefix: '' });
|
|
172
205
|
element.querySelector('[data-composer-slot]').replaceWith(composer.element);
|
|
173
206
|
identify(element, prefix);
|
|
174
207
|
const part = (name) => element.querySelector('[id="' + prefix + name + '"]');
|
|
208
|
+
let destroyed = false;
|
|
209
|
+
const parts = adoptProductParts(element);
|
|
210
|
+
const dialogs = new Map(Array.from(element.querySelectorAll('dialog'), dialog => {
|
|
211
|
+
const name = dialog.id.slice(prefix.length).replace(/-dialog$/, '');
|
|
212
|
+
return [name, installDialogLifecycle(dialog, { onClose: () => options.onDialogClose?.(name) })];
|
|
213
|
+
}));
|
|
214
|
+
const sidebar = part('sidebar'), scrim = part('sidebar-scrim');
|
|
215
|
+
const main = element.querySelector('.pui-main');
|
|
216
|
+
const sidebarTrigger = element.querySelector('.pui-mobile-menu');
|
|
217
|
+
const narrow = matchMedia('(max-width: 720px)');
|
|
218
|
+
let sidebarOpen = false;
|
|
219
|
+
sidebarTrigger.setAttribute('aria-controls', sidebar.id);
|
|
220
|
+
scrim.setAttribute('aria-hidden', 'true');
|
|
221
|
+
const sidebarControls = () => focusableElements(sidebar);
|
|
222
|
+
const syncSidebar = () => {
|
|
223
|
+
if (destroyed)
|
|
224
|
+
return;
|
|
225
|
+
const open = narrow.matches && sidebarOpen;
|
|
226
|
+
main.inert = open;
|
|
227
|
+
sidebar.inert = narrow.matches && !open;
|
|
228
|
+
sidebarTrigger.setAttribute('aria-expanded', String(sidebarOpen));
|
|
229
|
+
sidebar.classList.toggle('pui-open', sidebarOpen);
|
|
230
|
+
scrim.classList.toggle('pui-visible', sidebarOpen);
|
|
231
|
+
};
|
|
232
|
+
const setSidebarOpen = (open) => {
|
|
233
|
+
if (destroyed)
|
|
234
|
+
return;
|
|
235
|
+
const wasOpen = sidebarOpen;
|
|
236
|
+
sidebarOpen = open;
|
|
237
|
+
if (!open && narrow.matches && sidebar.contains(document.activeElement)) {
|
|
238
|
+
main.inert = false;
|
|
239
|
+
sidebarTrigger.focus({ preventScroll: true });
|
|
240
|
+
}
|
|
241
|
+
syncSidebar();
|
|
242
|
+
if (narrow.matches && open && !wasOpen)
|
|
243
|
+
sidebarControls()[0]?.focus({ preventScroll: true });
|
|
244
|
+
};
|
|
245
|
+
const onBreakpoint = () => {
|
|
246
|
+
if (narrow.matches && !sidebarOpen && sidebar.contains(document.activeElement)) {
|
|
247
|
+
main.inert = false;
|
|
248
|
+
sidebarTrigger.focus({ preventScroll: true });
|
|
249
|
+
}
|
|
250
|
+
syncSidebar();
|
|
251
|
+
};
|
|
252
|
+
const sidebarKeydown = (event) => {
|
|
253
|
+
if (!narrow.matches || !sidebarOpen || event.defaultPrevented || element.querySelector('dialog[open]'))
|
|
254
|
+
return;
|
|
255
|
+
if (event.key === 'Escape') {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
event.stopPropagation();
|
|
258
|
+
setSidebarOpen(false);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (event.key !== 'Tab')
|
|
262
|
+
return;
|
|
263
|
+
const controls = sidebarControls(), first = controls[0], last = controls.at(-1);
|
|
264
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
last?.focus();
|
|
267
|
+
}
|
|
268
|
+
else if (!event.shiftKey && document.activeElement === last) {
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
first?.focus();
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
const sidebarClick = (event) => { const target = event.target; if (target === scrim || target.closest('[data-action="menu"]')) {
|
|
274
|
+
setSidebarOpen(target !== scrim && !sidebarOpen);
|
|
275
|
+
event.stopPropagation();
|
|
276
|
+
} };
|
|
277
|
+
narrow.addEventListener('change', onBreakpoint);
|
|
278
|
+
element.addEventListener('keydown', sidebarKeydown);
|
|
279
|
+
syncSidebar();
|
|
280
|
+
const search = part('history-search');
|
|
281
|
+
const onSearch = () => options.onSearch?.(search.value);
|
|
282
|
+
search.addEventListener('input', onSearch);
|
|
283
|
+
element.addEventListener('click', sidebarClick);
|
|
284
|
+
const busy = part('workspace-busy');
|
|
285
|
+
const onBusy = (event) => { if (event.target.closest('button') && busy.dataset.key) {
|
|
286
|
+
event.stopPropagation();
|
|
287
|
+
options.onBusyAction?.(busy.dataset.key);
|
|
288
|
+
} };
|
|
289
|
+
busy.addEventListener('click', onBusy);
|
|
175
290
|
return { element, composer, part, update(state) {
|
|
291
|
+
if (destroyed)
|
|
292
|
+
return;
|
|
176
293
|
if (state.workspace !== undefined)
|
|
177
294
|
part('workspace-label').textContent = state.workspace;
|
|
178
295
|
if (state.conversation !== undefined)
|
|
179
296
|
part('conversation-label').textContent = state.conversation;
|
|
180
297
|
part('connection-status').hidden = !state.reconnecting;
|
|
181
|
-
|
|
298
|
+
if (state.error) {
|
|
299
|
+
part('inline-error').textContent = state.error.message;
|
|
300
|
+
part('inline-error').hidden = !!state.error.hidden || !state.error.message;
|
|
301
|
+
}
|
|
302
|
+
if (state.busy !== undefined) {
|
|
303
|
+
busy.hidden = !state.busy;
|
|
304
|
+
if (state.busy) {
|
|
305
|
+
if (!busy.firstChild) {
|
|
306
|
+
busy.append(document.createElement('span'), document.createElement('button'));
|
|
307
|
+
const button = busy.lastElementChild;
|
|
308
|
+
button.type = 'button';
|
|
309
|
+
button.className = 'pui-text-button';
|
|
310
|
+
}
|
|
311
|
+
busy.dataset.key = state.busy.key;
|
|
312
|
+
if (busy.firstElementChild.textContent !== state.busy.message)
|
|
313
|
+
busy.firstElementChild.textContent = state.busy.message;
|
|
314
|
+
if (busy.lastElementChild.textContent !== state.busy.actionLabel)
|
|
315
|
+
busy.lastElementChild.textContent = state.busy.actionLabel;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
parts.update();
|
|
319
|
+
}, setSidebarOpen,
|
|
320
|
+
openDialog(name) { if (!destroyed) {
|
|
321
|
+
setSidebarOpen(false);
|
|
322
|
+
dialogs.get(name)?.open();
|
|
323
|
+
} },
|
|
324
|
+
closeDialog(name) { if (!destroyed)
|
|
325
|
+
dialogs.get(name)?.close(); },
|
|
326
|
+
isDialogOpen(name) { return !destroyed && !!dialogs.get(name)?.isOpen(); },
|
|
327
|
+
updateActionAvailability(unavailable, root = element) {
|
|
328
|
+
if (destroyed)
|
|
329
|
+
return;
|
|
330
|
+
for (const button of root.querySelectorAll('[data-idle-action], [data-global-idle], [data-mcp-edit], [data-action="new-mcp"]')) {
|
|
331
|
+
const scope = button.hasAttribute('data-global-idle') || button.hasAttribute('data-mcp-edit') || button.dataset.action === 'new-mcp' ? { kind: 'global' } : button.dataset.idleConversation ? { kind: 'conversation', id: button.dataset.idleConversation } : button.dataset.idleWorkspace ? { kind: 'workspace', id: button.dataset.idleWorkspace } : { kind: 'active' };
|
|
332
|
+
button.disabled = controlDisabled(button, unavailable(scope));
|
|
333
|
+
}
|
|
334
|
+
for (const link of root.querySelectorAll('a[data-download-conversation]'))
|
|
335
|
+
link.setAttribute('aria-disabled', String(unavailable({ kind: 'conversation', id: link.dataset.downloadConversation })));
|
|
336
|
+
},
|
|
337
|
+
destroy() { if (destroyed)
|
|
338
|
+
return; destroyed = true; narrow.removeEventListener('change', onBreakpoint); element.removeEventListener('keydown', sidebarKeydown); sidebar.inert = false; main.inert = false; for (const dialog of dialogs.values())
|
|
339
|
+
dialog.destroy(); parts.destroy(); search.removeEventListener('input', onSearch); element.removeEventListener('click', sidebarClick); busy.removeEventListener('click', onBusy); composer.destroy(); element.remove(); } };
|
|
182
340
|
}
|
|
183
341
|
//# sourceMappingURL=workspace.js.map
|
package/dist/workspace.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["import { Generation, type UIBlock, type ActionResult } from './core.js';\nimport { icon } from './dom.js';\n\nexport interface ComposerViewState { placeholder?: string; disabled?: boolean; readOnly?: boolean; action?: 'send' | 'queue' | 'stop'; actionDisabled?: boolean; }\nexport interface ComposerViewOptions { prefix?: string; onSubmit?: (text: string) => void | ActionResult | Promise<void | ActionResult>; onStop?: () => void | ActionResult | Promise<void | ActionResult>; onInput?: (text: string) => void; }\nlet sequence = 0;\nfunction identify(root: HTMLElement, prefix: string): void {\n if (!prefix) return;\n const attributes = ['id', 'for', 'aria-labelledby', 'aria-describedby', 'aria-controls', 'data-close'];\n for (const node of [root, ...root.querySelectorAll<HTMLElement>('*')]) for (const attribute of attributes) {\n const value = node.getAttribute(attribute); if (value) node.setAttribute(attribute, value.split(' ').map(part => prefix + part).join(' '));\n }\n}\nexport function createComposerView(options: ComposerViewOptions = {}) {\n const holder = document.createElement('div'); holder.innerHTML = `<form id=\"composer-form\" class=\"pui-composer\">\n <div id=\"draft-images\" class=\"pui-draft-images\" aria-label=\"Image attachments\" hidden></div>\n <input id=\"image-picker\" type=\"file\" accept=\"image/png,image/jpeg,image/gif,image/webp\" multiple hidden />\n <textarea id=\"composer-input\" rows=\"1\" placeholder=\"Ask Pith to help with your work…\" aria-label=\"Message Pith\"></textarea>\n <div class=\"pui-composer-toolbar\">\n <div class=\"pui-composer-context\">\n <button id=\"attach-images\" type=\"button\" class=\"pui-quiet-icon pui-attach-images\" data-action=\"attach-images\" aria-label=\"Attach images\" title=\"Attach images\">${icon('image')}</button>\n <label class=\"pui-permission-control\" id=\"permission-control\">${icon('shield')}<span class=\"pui-sr-only\">Conversation permissions</span><select id=\"permission-mode\" aria-describedby=\"permission-description\"><option value=\"ask\">Ask before changes</option><option value=\"workspace-write\">Allow workspace changes</option><option value=\"full-access\">Full access</option></select>${icon('down')}</label>\n </div>\n <div class=\"pui-composer-actions\"><button id=\"composer-model\" type=\"button\" class=\"pui-composer-model\" data-action=\"model\" data-idle-action data-global-idle aria-label=\"Choose model\">Choose model</button><label class=\"pui-composer-thinking\"><span class=\"pui-sr-only\">Thinking effort</span><select id=\"composer-thinking\" aria-label=\"Thinking effort\"></select></label><button id=\"send-button\" class=\"pui-send-button\" type=\"submit\" aria-label=\"Send message\">${icon('arrow')}</button></div>\n </div>\n </form>`;\n const element = holder.firstElementChild as HTMLFormElement;\n const input = element.querySelector<HTMLTextAreaElement>('textarea')!;\n const action = element.querySelector<HTMLButtonElement>('[type=\"submit\"]')!;\n identify(element, options.prefix ?? 'pui-composer-' + ++sequence + '-');\n const generation = new Generation();\n let pending = false, last: ComposerViewState = {}, lastAction = 'send';\n const error = document.createElement('div'); error.className = 'pui-form-error'; error.setAttribute('role','alert'); error.hidden = true; element.insertBefore(error, element.firstChild);\n const resize = () => { input.style.height = 'auto'; input.style.height = Math.min(input.scrollHeight, 180) + 'px'; };\n const update = (state: ComposerViewState) => {\n last = state;\n if (state.placeholder !== undefined) input.placeholder = state.placeholder;\n input.disabled = !!state.disabled; input.readOnly = !!state.readOnly;\n if (state.action && state.action !== lastAction) { lastAction = state.action; action.type = state.action === 'stop' ? 'button' : 'submit'; action.innerHTML = icon(state.action === 'stop' ? 'stop' : 'arrow'); action.classList.toggle('pui-is-stop', state.action === 'stop'); action.setAttribute('aria-label', state.action === 'stop' ? 'Stop agent' : state.action === 'queue' ? 'Queue message' : 'Send message'); }\n action.disabled = !!(state.actionDisabled || state.disabled || pending);\n };\n const onInput = () => { resize(); options.onInput?.(input.value); };\n const run = async (callback: (() => void | ActionResult | Promise<void | ActionResult>) | undefined) => {\n if (!callback || pending || action.disabled || input.disabled || input.readOnly) return;\n const seq = generation.next(); pending = true; error.hidden = true; error.textContent = ''; update(last);\n try {\n const result = await callback();\n if (generation.current(seq) && result && !result.ok) { error.textContent = result.error; error.hidden = false; }\n } catch (reason) {\n if (generation.current(seq)) { error.textContent = reason instanceof Error ? reason.message : String(reason); error.hidden = false; }\n } finally { if (generation.current(seq)) { pending = false; update(last); } }\n };\n const submit = (event: SubmitEvent) => { if (options.onSubmit) { event.preventDefault(); const text = input.value; void run(() => options.onSubmit!(text)); } };\n const stop = () => { if (action.type === 'button') void run(options.onStop); };\n const keydown = (event: KeyboardEvent) => {\n if (options.onSubmit && event.key === 'Enter' && !event.shiftKey && !event.isComposing && action.type === 'submit') { event.preventDefault(); element.requestSubmit(); }\n };\n input.addEventListener('input', onInput); input.addEventListener('keydown', keydown); element.addEventListener('submit', submit); action.addEventListener('click', stop);\n return { element, input, update, getValue: () => input.value,\n reset(value: string) { generation.invalidate(); pending = false; error.hidden = true; error.textContent = ''; input.value = value; update(last); resize(); }, focus: () => input.focus(), resize,\n destroy() { generation.destroy(); input.removeEventListener('input', onInput); input.removeEventListener('keydown', keydown); element.removeEventListener('submit', submit); action.removeEventListener('click', stop); element.remove(); } };\n\n}\n\nexport interface WorkspaceShellOptions { brand: Node; prefix?: string; }\nexport interface WorkspaceShellState { workspace?: string; conversation?: string; reconnecting?: boolean; }\nexport function createWorkspaceShell(options: WorkspaceShellOptions): UIBlock<WorkspaceShellState> & { composer: ReturnType<typeof createComposerView>; part<T extends HTMLElement = HTMLElement>(name: string): T } {\n const element = document.createElement('div'); element.className = 'pui-app';\n element.innerHTML = `\n <aside class=\"pui-sidebar\" id=\"sidebar\">\n <div class=\"pui-brand\"><span data-brand-slot></span></div>\n <div class=\"pui-sidebar-section-label\">WORKSPACES <button class=\"pui-quiet-icon\" data-action=\"workspace\" aria-label=\"Manage workspaces\">${icon('plus')}</button></div>\n <label class=\"pui-history-search\">${icon('search')}<span class=\"pui-sr-only\">Search conversation titles</span><input id=\"history-search\" type=\"search\" placeholder=\"Search conversations\" autocomplete=\"off\" /></label>\n <nav id=\"history-list\" class=\"pui-history-list\" aria-label=\"Workspaces and conversations\"></nav>\n <div class=\"pui-sidebar-bottom\">\n <button class=\"pui-settings-button\" data-action=\"resources\">${icon('file')}<span>Workspace resources</span></button>\n <button class=\"pui-settings-button\" data-action=\"connections\">${icon('plug')}<span>Connections</span></button>\n <button class=\"pui-settings-button\" data-action=\"settings\">${icon('settings')}<span>Settings</span></button>\n <div id=\"connection-status\" class=\"pui-local-status\" role=\"status\" hidden><span class=\"pui-status-dot pui-reconnecting\" aria-hidden=\"true\"></span><span>Reconnecting…</span></div>\n </div>\n </aside>\n <div id=\"conversation-menu\" class=\"pui-sidebar-conversation-menu\" role=\"menu\" hidden></div>\n <div class=\"pui-sidebar-scrim\" id=\"sidebar-scrim\"></div>\n <main class=\"pui-main\">\n <header class=\"pui-topbar\">\n <button class=\"pui-quiet-icon pui-mobile-menu\" data-action=\"menu\" aria-label=\"Open sidebar\">${icon('menu')}</button>\n <div class=\"pui-breadcrumb\">${icon('folder')}<span id=\"workspace-label\">No workspace</span>${icon('chevron', 'pui-breadcrumb-chevron')}<span class=\"pui-breadcrumb-current\" id=\"conversation-label\">New conversation</span></div>\n <div class=\"pui-conversation-actions\"><button class=\"pui-quiet-icon pui-compact-action\" data-sdk=\"compact\" data-sdk-idle title=\"Compress context by summarizing older messages\" aria-label=\"Compress context\">${icon('compress')}<span>Compact</span></button><div id=\"artifacts-control\" class=\"pui-artifacts-control\" hidden><button id=\"artifacts-toggle\" type=\"button\" class=\"pui-quiet-icon pui-artifacts-toggle\" aria-label=\"Conversation files\" title=\"Conversation files\" aria-expanded=\"false\" aria-controls=\"artifacts\">${icon('file')}<span id=\"artifacts-count\" class=\"pui-artifacts-count\" aria-hidden=\"true\"></span></button><section id=\"artifacts\" class=\"pui-artifacts-panel\" aria-labelledby=\"artifacts-title\" tabindex=\"-1\" hidden></section></div></div>\n </header>\n <section id=\"conversation-find\" class=\"pui-conversation-find\" aria-label=\"Find in conversation\" hidden>\n <input type=\"search\" aria-label=\"Find in this conversation\" placeholder=\"Find in this conversation\" autocomplete=\"off\" />\n <span data-find-count role=\"status\" aria-live=\"polite\"></span>\n <button type=\"button\" class=\"pui-quiet-icon pui-find-previous\" data-find-previous aria-label=\"Previous match\" title=\"Previous match (Shift+Enter)\">${icon('down')}</button>\n <button type=\"button\" class=\"pui-quiet-icon\" data-find-next aria-label=\"Next match\" title=\"Next match (Enter)\">${icon('down')}</button>\n <button type=\"button\" class=\"pui-quiet-icon\" data-find-close aria-label=\"Close search\" title=\"Close (Esc)\">${icon('close')}</button>\n </section>\n <div class=\"pui-conversation-region\"><section id=\"chat-scroll\" class=\"pui-chat-scroll\" aria-label=\"Conversation\" tabindex=\"-1\">\n <div id=\"welcome\" class=\"pui-welcome\"></div>\n <div id=\"messages\" class=\"pui-messages\" aria-live=\"polite\" aria-relevant=\"additions text\"></div>\n </section><button id=\"back-to-latest\" type=\"button\" class=\"pui-secondary-button pui-back-to-latest\" hidden>${icon('down')}<span>Back to latest</span></button></div>\n <div class=\"pui-composer-region\">\n <div class=\"pui-composer-panels\">\n <div id=\"approval\" class=\"pui-approval-region\"></div>\n <div id=\"workspace-busy\" class=\"pui-workspace-busy\" hidden></div><div id=\"inline-error\" class=\"pui-inline-error\" role=\"alert\" hidden></div>\n <section id=\"task-failure\" class=\"pui-task-failure\" role=\"status\" hidden></section>\n <details id=\"run-status\" class=\"pui-run-status\" hidden><summary id=\"run-status-summary\"></summary><div id=\"run-status-details\"><div id=\"runtime-values\"></div><details id=\"cost-requests\" class=\"pui-cost-requests\" hidden><summary>Request breakdown</summary><div id=\"cost-ledger\"></div></details></div></details>\n <section id=\"queued-messages\" class=\"pui-queued-messages\" aria-label=\"Pending messages\" aria-live=\"polite\" hidden></section>\n </div>\n <div data-composer-slot></div>\n <p id=\"image-guidance\" class=\"pui-composer-note pui-image-guidance\" hidden></p>\n <p class=\"pui-composer-note\" id=\"permission-description\">Pith can read workspace files. Changes and commands require your approval.</p>\n </div>\n </main>\n <section id=\"completion-notices\" class=\"pui-completion-notices\" aria-label=\"Completed tasks\" aria-live=\"polite\"></section>\n <span id=\"copy-status\" class=\"pui-sr-only\" role=\"status\" aria-live=\"polite\"></span>\n <dialog id=\"model-dialog\" class=\"pui-modal pui-model-modal\" aria-labelledby=\"model-title\"><div id=\"model-content\"></div></dialog>\n <dialog id=\"settings-dialog\" class=\"pui-modal\" aria-labelledby=\"settings-title\"><div id=\"settings-content\"></div></dialog>\n <dialog id=\"workspace-dialog\" class=\"pui-modal\" aria-labelledby=\"workspace-title\"><div id=\"workspace-content\"></div></dialog>\n <dialog id=\"permissions-dialog\" class=\"pui-modal pui-permission-modal\" aria-labelledby=\"full-access-title\"><div id=\"permissions-content\"></div></dialog>\n <dialog id=\"delete-dialog\" class=\"pui-modal\" aria-labelledby=\"delete-title\"><div id=\"delete-content\"></div></dialog>\n <dialog id=\"rename-dialog\" class=\"pui-modal\" aria-labelledby=\"rename-title\"><div id=\"rename-content\"></div></dialog>\n <dialog id=\"queue-edit-dialog\" class=\"pui-modal\" aria-labelledby=\"queue-edit-title\"><div id=\"queue-edit-content\"></div></dialog>\n <dialog id=\"message-edit-dialog\" class=\"pui-modal\" aria-labelledby=\"message-edit-title\"><div id=\"message-edit-content\"></div></dialog>\n <dialog id=\"resources-dialog\" class=\"pui-modal pui-feature-modal\" aria-labelledby=\"resources-title\"><div id=\"resources-content\"></div></dialog>\n <dialog id=\"connections-dialog\" class=\"pui-modal pui-feature-modal\" aria-labelledby=\"connections-title\"><div id=\"connections-content\"></div></dialog>\n <dialog id=\"preview-dialog\" class=\"pui-modal pui-file-preview-modal\" aria-labelledby=\"preview-title\"><div id=\"preview-content\"></div></dialog>\n <dialog id=\"image-dialog\"></dialog>\n`;\n element.querySelector('[data-brand-slot]')!.replaceWith(options.brand);\n const prefix = options.prefix ?? 'pui-workspace-' + ++sequence + '-';\n const composer = createComposerView({ prefix: '' }); element.querySelector('[data-composer-slot]')!.replaceWith(composer.element);\n identify(element, prefix);\n const part = <T extends HTMLElement = HTMLElement>(name: string) => element.querySelector<T>('[id=\"' + prefix + name + '\"]')!;\n return { element, composer, part, update(state) {\n if (state.workspace !== undefined) part('workspace-label').textContent = state.workspace;\n if (state.conversation !== undefined) part('conversation-label').textContent = state.conversation;\n part('connection-status').hidden = !state.reconnecting;\n }, destroy() { composer.destroy(); element.remove(); } };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["import { type UIBlock, type ActionResult } from './core.js';\nimport { focusableElements, icon } from './dom.js';\nimport { controlDisabled } from './core.js';\nimport { adoptProductParts, reconcileSelectOptions } from './foundations.js';\nimport { installDialogLifecycle } from './surface.js';\nimport { permissionControlElement } from './tasks/permission-element.js';\nimport { createOperation } from './operation.js';\n\nexport interface ComposerViewState {\n placeholder?: string; disabled?: boolean; readOnly?: boolean;\n action?: 'send' | 'queue' | 'stop'; actionDisabled?: boolean;\n model?: { label: string; description: string; disabled?: boolean };\n thinking?: { options: readonly { value: string; label: string }[]; value: string; disabled?: boolean };\n}\nexport interface ComposerViewOptions {\n prefix?: string;\n onSubmit?: (text: string) => void | ActionResult | Promise<void | ActionResult>;\n onStop?: () => void | ActionResult | Promise<void | ActionResult>;\n onInput?: (text: string) => void;\n onModel?: () => void;\n onAttach?: () => void;\n onImages?: (files: File[]) => void;\n onThinkingChange?: (value: string) => void;\n}\nlet sequence = 0;\nfunction identify(root: HTMLElement, prefix: string): void {\n if (!prefix) return;\n const attributes = ['id', 'for', 'aria-labelledby', 'aria-describedby', 'aria-controls', 'data-close'];\n for (const node of [root, ...root.querySelectorAll<HTMLElement>('*')]) for (const attribute of attributes) {\n const value = node.getAttribute(attribute); if (value) node.setAttribute(attribute, value.split(' ').map(part => prefix + part).join(' '));\n }\n}\nexport function createComposerView(options: ComposerViewOptions = {}) {\n const holder = document.createElement('div'); holder.innerHTML = `<form id=\"composer-form\" class=\"pui-composer\">\n <div id=\"draft-images\" class=\"pui-draft-images\" aria-label=\"Image attachments\" hidden></div>\n <input id=\"image-picker\" type=\"file\" accept=\"image/png,image/jpeg,image/gif,image/webp\" multiple hidden />\n <textarea id=\"composer-input\" rows=\"1\" placeholder=\"Ask Pith to help with your work…\" aria-label=\"Message Pith\"></textarea>\n <div class=\"pui-composer-toolbar\">\n <div class=\"pui-composer-context\">\n <button id=\"attach-images\" type=\"button\" class=\"pui-quiet-icon pui-attach-images\" data-action=\"attach-images\" aria-label=\"Attach images\" title=\"Attach images\">${icon('image')}</button>\n <span data-permission-slot></span>\n </div>\n <div class=\"pui-composer-actions\"><button id=\"composer-model\" type=\"button\" class=\"pui-composer-model\" data-action=\"model\" data-idle-action data-global-idle aria-label=\"Choose model\">Choose model</button><label class=\"pui-composer-thinking\"><span class=\"pui-sr-only\">Thinking effort</span><select id=\"composer-thinking\" aria-label=\"Thinking effort\"></select></label><button id=\"send-button\" class=\"pui-send-button\" type=\"submit\" aria-label=\"Send message\">${icon('arrow')}</button></div>\n </div>\n </form>`;\n const element = holder.firstElementChild as HTMLFormElement;\n const permission = permissionControlElement(); permission.id = 'permission-control';\n const permissionMode = permission.querySelector('select')!; permissionMode.id = 'permission-mode'; permissionMode.setAttribute('aria-describedby', 'permission-description');\n element.querySelector('[data-permission-slot]')!.replaceWith(permission);\n const input = element.querySelector<HTMLTextAreaElement>('textarea')!;\n const action = element.querySelector<HTMLButtonElement>('[type=\"submit\"]')!;\n const model = element.querySelector<HTMLButtonElement>('[data-action=\"model\"]')!;\n const thinking = element.querySelector<HTMLSelectElement>('[aria-label=\"Thinking effort\"]')!;\n const thinkingLabel = thinking.closest<HTMLLabelElement>('label')!;\n const imagePicker = element.querySelector<HTMLInputElement>('[type=\"file\"]')!;\n identify(element, options.prefix ?? 'pui-composer-' + ++sequence + '-');\n const parts = adoptProductParts(element);\n parts.control(element.querySelector<HTMLSelectElement>('[id$=\"permission-mode\"]')!);\n parts.control(thinking);\n let destroyed = false;\n let last: ComposerViewState = {}, lastAction = 'send';\n const error = document.createElement('div'); error.className = 'pui-form-error'; error.setAttribute('role','alert'); error.hidden = true; element.insertBefore(error, element.firstChild);\n const feedback = parts.feedback(error);\n const setError = (message:string) => {feedback.update({message,tone:'error'});error.hidden=!message;};\n const resize = () => { input.style.height = 'auto'; input.style.height = Math.min(input.scrollHeight, 180) + 'px'; };\n const update = (state: ComposerViewState) => {\n if (destroyed) return;\n last = state;\n parts.control(input).update({ disabled: !!state.disabled, readOnly: !!state.readOnly, ...(state.placeholder !== undefined ? { placeholder: state.placeholder } : {}) });\n if (state.action && state.action !== lastAction) { lastAction = state.action; action.type = state.action === 'stop' ? 'button' : 'submit'; action.innerHTML = icon(state.action === 'stop' ? 'stop' : 'arrow'); action.classList.toggle('pui-is-stop', state.action === 'stop'); }\n const actionLabel = lastAction === 'stop' ? 'Stop agent' : lastAction === 'queue' ? 'Queue message' : 'Send message';\n action.setAttribute('aria-label', actionLabel); action.title = actionLabel;\n parts.action(action).update({ disabled: !!(state.actionDisabled || state.disabled), pending: operation.pending });\n if (state.model) {\n parts.action(model).update({ label: state.model.label, title: state.model.description, disabled: !!state.model.disabled });\n }\n if (state.thinking) {\n const { options: choices, value, disabled } = state.thinking;\n reconcileSelectOptions(thinking, choices, value);\n thinkingLabel.hidden = choices.length < 2; parts.control(thinking).update({ disabled: !!disabled });\n }\n parts.update();\n };\n const operation = createOperation({unavailable: () => destroyed || action.disabled, onPending: () => update(last), onError: setError});\n const onInput = () => { resize(); options.onInput?.(input.value); };\n const run = (callback: (() => void | ActionResult | Promise<void | ActionResult>) | undefined, textSubmission = true) => {\n if (!callback || (textSubmission && (input.disabled || input.readOnly))) return;\n operation.run(() => {setError('');return callback();}, result => {\n if (result && !result.ok) setError(result.error);\n });\n };\n const submit = (event: SubmitEvent) => { if (options.onSubmit) { event.preventDefault(); const text = input.value; void run(() => options.onSubmit!(text)); } };\n const stop = () => { if (action.type === 'button') void run(options.onStop, false); };\n const keydown = (event: KeyboardEvent) => {\n if (options.onSubmit && event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n if (action.type === 'submit') element.requestSubmit();\n }\n };\n const click = (event: MouseEvent) => {\n const button = (event.target as Element).closest<HTMLButtonElement>('button');\n if (!button || button.disabled) return;\n const callback = button === model ? options.onModel : button.hasAttribute('data-action') && button.dataset.action === 'attach-images' ? options.onAttach : undefined;\n if (callback) { event.stopPropagation(); callback(); }\n };\n const chooseThinking = () => options.onThinkingChange?.(thinking.value);\n const images = () => { const files = Array.from(imagePicker.files ?? []); imagePicker.value = ''; options.onImages?.(files); };\n element.addEventListener('click', click); thinking.addEventListener('change', chooseThinking); imagePicker.addEventListener('change', images);\n input.addEventListener('input', onInput); input.addEventListener('keydown', keydown); element.addEventListener('submit', submit); action.addEventListener('click', stop);\n return { element, input, update, getValue: () => input.value,\n reset(value: string) { if (destroyed) return; operation.invalidate(); setError(''); input.value = value; update(last); resize(); }, focus: () => { if (!destroyed) input.focus(); }, resize,\n pickImages() { if (!destroyed) imagePicker.click(); },\n destroy() { if (destroyed) return; destroyed = true; operation.destroy(); parts.destroy(); input.removeEventListener('input', onInput); input.removeEventListener('keydown', keydown); element.removeEventListener('submit', submit); action.removeEventListener('click', stop); element.removeEventListener('click', click); thinking.removeEventListener('change', chooseThinking); imagePicker.removeEventListener('change', images); element.remove(); } };\n\n}\n\nexport type WorkspaceDialogName = 'model' | 'settings' | 'workspace' | 'permissions' | 'delete' | 'rename' | 'queue-edit' | 'message-edit' | 'resources' | 'connections' | 'preview' | 'image';\nexport interface ActionScope { kind: 'global' | 'conversation' | 'workspace' | 'active'; id?: string; }\nexport interface WorkspaceShellOptions { brand: Node; prefix?: string; composer?: ComposerViewOptions; onDialogClose?: (name: WorkspaceDialogName) => void; onSearch?: (query: string) => void; onBusyAction?: (key: string) => void; }\nexport interface WorkspaceShellState { workspace?: string; conversation?: string; reconnecting?: boolean; error?: { message: string; hidden?: boolean }; busy?: { key: string; message: string; actionLabel: string } | null; }\nexport function createWorkspaceShell(options: WorkspaceShellOptions) {\n const element = document.createElement('div'); element.className = 'pui-app';\n element.innerHTML = `\n <aside class=\"pui-sidebar\" id=\"sidebar\">\n <div class=\"pui-brand\"><span data-brand-slot></span></div>\n <div class=\"pui-sidebar-section-label\">WORKSPACES <button class=\"pui-quiet-icon\" data-action=\"workspace\" aria-label=\"Manage workspaces\">${icon('plus')}</button></div>\n <label class=\"pui-history-search\">${icon('search')}<span class=\"pui-sr-only\">Search conversation titles</span><input id=\"history-search\" type=\"search\" placeholder=\"Search conversations\" autocomplete=\"off\" /></label>\n <nav id=\"history-list\" class=\"pui-history-list\" aria-label=\"Workspaces and conversations\"></nav>\n <div class=\"pui-sidebar-bottom\">\n <button class=\"pui-settings-button\" data-action=\"resources\">${icon('file')}<span>Workspace resources</span></button>\n <button class=\"pui-settings-button\" data-action=\"connections\">${icon('plug')}<span>Connections</span></button>\n <button class=\"pui-settings-button\" data-action=\"settings\">${icon('settings')}<span>Settings</span></button>\n <div id=\"connection-status\" class=\"pui-local-status\" role=\"status\" hidden><span class=\"pui-status-dot pui-reconnecting\" aria-hidden=\"true\"></span><span>Reconnecting…</span></div>\n </div>\n </aside>\n <div id=\"conversation-menu\" class=\"pui-sidebar-conversation-menu\" role=\"menu\" hidden></div>\n <div class=\"pui-sidebar-scrim\" id=\"sidebar-scrim\"></div>\n <main class=\"pui-main\">\n <header class=\"pui-topbar\">\n <button class=\"pui-quiet-icon pui-mobile-menu\" data-action=\"menu\" aria-label=\"Open sidebar\">${icon('menu')}</button>\n <div class=\"pui-breadcrumb\">${icon('folder')}<span id=\"workspace-label\">No workspace</span>${icon('chevron', 'pui-breadcrumb-chevron')}<span class=\"pui-breadcrumb-current\" id=\"conversation-label\">New conversation</span></div>\n <div class=\"pui-conversation-actions\"><button class=\"pui-quiet-icon pui-compact-action\" data-sdk=\"compact\" data-sdk-idle title=\"Compress context by summarizing older messages\" aria-label=\"Compress context\">${icon('compress')}<span>Compact</span></button><div id=\"artifacts-control\" class=\"pui-artifacts-control\" hidden><button id=\"artifacts-toggle\" type=\"button\" class=\"pui-quiet-icon pui-artifacts-toggle\" aria-label=\"Conversation files\" title=\"Conversation files\" aria-expanded=\"false\" aria-controls=\"artifacts\">${icon('file')}<span id=\"artifacts-count\" class=\"pui-artifacts-count\" aria-hidden=\"true\"></span></button><section id=\"artifacts\" class=\"pui-artifacts-panel\" aria-labelledby=\"artifacts-title\" tabindex=\"-1\" hidden></section></div></div>\n </header>\n <section id=\"conversation-find\" class=\"pui-conversation-find\" aria-label=\"Find in conversation\" hidden>\n <input type=\"search\" aria-label=\"Find in this conversation\" placeholder=\"Find in this conversation\" autocomplete=\"off\" />\n <span data-find-count role=\"status\" aria-live=\"polite\"></span>\n <button type=\"button\" class=\"pui-quiet-icon pui-find-previous\" data-find-previous aria-label=\"Previous match\" title=\"Previous match (Shift+Enter)\">${icon('down')}</button>\n <button type=\"button\" class=\"pui-quiet-icon\" data-find-next aria-label=\"Next match\" title=\"Next match (Enter)\">${icon('down')}</button>\n <button type=\"button\" class=\"pui-quiet-icon\" data-find-close aria-label=\"Close search\" title=\"Close (Esc)\">${icon('close')}</button>\n </section>\n <div class=\"pui-conversation-region\"><section id=\"chat-scroll\" class=\"pui-chat-scroll\" aria-label=\"Conversation\" tabindex=\"-1\">\n <div id=\"welcome\" class=\"pui-welcome\"></div>\n <div id=\"messages\" class=\"pui-messages\" aria-live=\"polite\" aria-relevant=\"additions text\"></div>\n </section><button id=\"back-to-latest\" type=\"button\" class=\"pui-secondary-button pui-back-to-latest\" hidden>${icon('down')}<span>Back to latest</span></button></div>\n <div class=\"pui-composer-region\">\n <div class=\"pui-composer-panels\">\n <div id=\"approval\" class=\"pui-approval-region\"></div>\n <div id=\"workspace-busy\" class=\"pui-workspace-busy\" hidden></div><div id=\"inline-error\" class=\"pui-inline-error\" role=\"alert\" hidden></div>\n <section id=\"task-failure\" class=\"pui-task-failure\" role=\"status\" hidden></section>\n <details id=\"run-status\" class=\"pui-run-status\" hidden><summary id=\"run-status-summary\"></summary><div id=\"run-status-details\"><div id=\"runtime-values\"></div><details id=\"cost-requests\" class=\"pui-cost-requests\" hidden><summary>Request breakdown</summary><div id=\"cost-ledger\"></div></details></div></details>\n <section id=\"queued-messages\" class=\"pui-queued-messages\" aria-label=\"Pending messages\" aria-live=\"polite\" hidden></section>\n </div>\n <div data-composer-slot></div>\n <p id=\"image-guidance\" class=\"pui-composer-note pui-image-guidance\" hidden></p>\n <p class=\"pui-composer-note\" id=\"permission-description\">Pith can read workspace files. Changes and commands require your approval.</p>\n </div>\n </main>\n <section id=\"completion-notices\" class=\"pui-completion-notices\" aria-label=\"Completed tasks\" aria-live=\"polite\"></section>\n <span id=\"copy-status\" class=\"pui-sr-only\" role=\"status\" aria-live=\"polite\"></span>\n <dialog id=\"model-dialog\" class=\"pui-modal pui-model-modal\" aria-labelledby=\"model-title\"><div id=\"model-content\"></div></dialog>\n <dialog id=\"settings-dialog\" class=\"pui-modal\" aria-labelledby=\"settings-title\"><div id=\"settings-content\"></div></dialog>\n <dialog id=\"workspace-dialog\" class=\"pui-modal\" aria-labelledby=\"workspace-title\"><div id=\"workspace-content\"></div></dialog>\n <dialog id=\"permissions-dialog\" class=\"pui-modal pui-permission-modal\" aria-labelledby=\"full-access-title\"><div id=\"permissions-content\"></div></dialog>\n <dialog id=\"delete-dialog\" class=\"pui-modal\" aria-labelledby=\"delete-title\"><div id=\"delete-content\"></div></dialog>\n <dialog id=\"rename-dialog\" class=\"pui-modal\" aria-labelledby=\"rename-title\"><div id=\"rename-content\"></div></dialog>\n <dialog id=\"queue-edit-dialog\" class=\"pui-modal\" aria-labelledby=\"queue-edit-title\"><div id=\"queue-edit-content\"></div></dialog>\n <dialog id=\"message-edit-dialog\" class=\"pui-modal\" aria-labelledby=\"message-edit-title\"><div id=\"message-edit-content\"></div></dialog>\n <dialog id=\"resources-dialog\" class=\"pui-modal pui-feature-modal\" aria-labelledby=\"resources-title\"><div id=\"resources-content\"></div></dialog>\n <dialog id=\"connections-dialog\" class=\"pui-modal pui-feature-modal\" aria-labelledby=\"connections-title\"><div id=\"connections-content\"></div></dialog>\n <dialog id=\"preview-dialog\" class=\"pui-modal pui-file-preview-modal\" aria-labelledby=\"preview-title\"><div id=\"preview-content\"></div></dialog>\n <dialog id=\"image-dialog\"></dialog>\n`;\n element.querySelector('[data-brand-slot]')!.replaceWith(options.brand);\n const prefix = options.prefix ?? 'pui-workspace-' + ++sequence + '-';\n const composer = createComposerView({ ...options.composer, prefix: '' }); element.querySelector('[data-composer-slot]')!.replaceWith(composer.element);\n identify(element, prefix);\n const part = <T extends HTMLElement = HTMLElement>(name: string) => element.querySelector<T>('[id=\"' + prefix + name + '\"]')!;\n let destroyed = false;\n const parts = adoptProductParts(element);\n const dialogs = new Map(Array.from(element.querySelectorAll<HTMLDialogElement>('dialog'), dialog => {\n const name = dialog.id.slice(prefix.length).replace(/-dialog$/, '') as WorkspaceDialogName;\n return [name, installDialogLifecycle(dialog, { onClose: () => options.onDialogClose?.(name) })] as const;\n }));\n const sidebar = part('sidebar'), scrim = part('sidebar-scrim');\n const main = element.querySelector<HTMLElement>('.pui-main')!;\n const sidebarTrigger = element.querySelector<HTMLButtonElement>('.pui-mobile-menu')!;\n const narrow = matchMedia('(max-width: 720px)');\n let sidebarOpen = false;\n sidebarTrigger.setAttribute('aria-controls', sidebar.id);\n scrim.setAttribute('aria-hidden','true');\n const sidebarControls = () => focusableElements(sidebar);\n const syncSidebar = () => {\n if (destroyed) return;\n const open = narrow.matches && sidebarOpen;\n main.inert = open;\n sidebar.inert = narrow.matches && !open;\n sidebarTrigger.setAttribute('aria-expanded',String(sidebarOpen));\n sidebar.classList.toggle('pui-open', sidebarOpen); scrim.classList.toggle('pui-visible', sidebarOpen);\n };\n const setSidebarOpen = (open: boolean) => {\n if (destroyed) return;\n const wasOpen = sidebarOpen; sidebarOpen = open;\n if (!open && narrow.matches && sidebar.contains(document.activeElement)) {main.inert=false;sidebarTrigger.focus({preventScroll:true});}\n syncSidebar();\n if (narrow.matches && open && !wasOpen) sidebarControls()[0]?.focus({preventScroll:true});\n };\n const onBreakpoint = () => {\n if (narrow.matches && !sidebarOpen && sidebar.contains(document.activeElement)) {main.inert=false;sidebarTrigger.focus({preventScroll:true});}\n syncSidebar();\n };\n const sidebarKeydown = (event: KeyboardEvent) => {\n if (!narrow.matches || !sidebarOpen || event.defaultPrevented || element.querySelector('dialog[open]')) return;\n if (event.key === 'Escape') {event.preventDefault();event.stopPropagation();setSidebarOpen(false);return;}\n if (event.key !== 'Tab') return;\n const controls=sidebarControls(), first=controls[0],last=controls.at(-1);\n if (event.shiftKey && document.activeElement===first) {event.preventDefault();last?.focus();}\n else if (!event.shiftKey && document.activeElement===last) {event.preventDefault();first?.focus();}\n };\n const sidebarClick = (event: MouseEvent) => { const target = event.target as Element; if (target === scrim || target.closest('[data-action=\"menu\"]')) { setSidebarOpen(target !== scrim && !sidebarOpen); event.stopPropagation(); } };\n narrow.addEventListener('change',onBreakpoint); element.addEventListener('keydown',sidebarKeydown); syncSidebar();\n const search = part<HTMLInputElement>('history-search'); const onSearch = () => options.onSearch?.(search.value);\n search.addEventListener('input', onSearch); element.addEventListener('click', sidebarClick);\n const busy = part('workspace-busy');\n const onBusy = (event: MouseEvent) => { if ((event.target as Element).closest('button') && busy.dataset.key) { event.stopPropagation(); options.onBusyAction?.(busy.dataset.key); } };\n busy.addEventListener('click', onBusy);\n return { element, composer, part, update(state: Readonly<WorkspaceShellState>) {\n if (destroyed) return;\n if (state.workspace !== undefined) part('workspace-label').textContent = state.workspace;\n if (state.conversation !== undefined) part('conversation-label').textContent = state.conversation;\n part('connection-status').hidden = !state.reconnecting;\n if (state.error) { part('inline-error').textContent = state.error.message; part('inline-error').hidden = !!state.error.hidden || !state.error.message; }\n if (state.busy !== undefined) {\n busy.hidden = !state.busy;\n if (state.busy) {\n if (!busy.firstChild) { busy.append(document.createElement('span'), document.createElement('button')); const button = busy.lastElementChild as HTMLButtonElement; button.type = 'button'; button.className = 'pui-text-button'; }\n busy.dataset.key = state.busy.key;\n if (busy.firstElementChild!.textContent !== state.busy.message) busy.firstElementChild!.textContent = state.busy.message;\n if (busy.lastElementChild!.textContent !== state.busy.actionLabel) busy.lastElementChild!.textContent = state.busy.actionLabel;\n }\n }\n parts.update();\n }, setSidebarOpen,\n openDialog(name: WorkspaceDialogName) { if (!destroyed) { setSidebarOpen(false); dialogs.get(name)?.open(); } },\n closeDialog(name: WorkspaceDialogName) { if (!destroyed) dialogs.get(name)?.close(); },\n isDialogOpen(name: WorkspaceDialogName) { return !destroyed && !!dialogs.get(name)?.isOpen(); },\n updateActionAvailability(unavailable: (scope: ActionScope) => boolean, root: ParentNode = element) {\n if (destroyed) return;\n for (const button of root.querySelectorAll<HTMLButtonElement>('[data-idle-action], [data-global-idle], [data-mcp-edit], [data-action=\"new-mcp\"]')) {\n const scope: ActionScope = button.hasAttribute('data-global-idle') || button.hasAttribute('data-mcp-edit') || button.dataset.action === 'new-mcp' ? { kind: 'global' } : button.dataset.idleConversation ? { kind: 'conversation', id: button.dataset.idleConversation } : button.dataset.idleWorkspace ? { kind: 'workspace', id: button.dataset.idleWorkspace } : { kind: 'active' };\n button.disabled = controlDisabled(button, unavailable(scope));\n }\n for (const link of root.querySelectorAll<HTMLAnchorElement>('a[data-download-conversation]')) link.setAttribute('aria-disabled', String(unavailable({ kind: 'conversation', id: link.dataset.downloadConversation })));\n },\n destroy() { if (destroyed) return; destroyed = true; narrow.removeEventListener('change',onBreakpoint);element.removeEventListener('keydown',sidebarKeydown);sidebar.inert=false;main.inert=false;for (const dialog of dialogs.values()) dialog.destroy(); parts.destroy(); search.removeEventListener('input', onSearch); element.removeEventListener('click', sidebarClick); busy.removeEventListener('click', onBusy); composer.destroy(); element.remove(); } };\n}\n"]}
|