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.
Files changed (124) hide show
  1. package/AI.md +20 -1
  2. package/API.md +834 -272
  3. package/README.md +3 -1
  4. package/dist/composer.d.ts.map +1 -1
  5. package/dist/composer.js +48 -29
  6. package/dist/composer.js.map +1 -1
  7. package/dist/content/conversation-reader.d.ts.map +1 -1
  8. package/dist/content/conversation-reader.js +8 -1
  9. package/dist/content/conversation-reader.js.map +1 -1
  10. package/dist/content/conversation-view.d.ts +21 -4
  11. package/dist/content/conversation-view.d.ts.map +1 -1
  12. package/dist/content/conversation-view.js +72 -13
  13. package/dist/content/conversation-view.js.map +1 -1
  14. package/dist/content/image-viewer.d.ts +4 -2
  15. package/dist/content/image-viewer.d.ts.map +1 -1
  16. package/dist/content/image-viewer.js +36 -15
  17. package/dist/content/image-viewer.js.map +1 -1
  18. package/dist/content/paged-preview.d.ts +1 -1
  19. package/dist/content/paged-preview.d.ts.map +1 -1
  20. package/dist/content/paged-preview.js +10 -5
  21. package/dist/content/paged-preview.js.map +1 -1
  22. package/dist/content/views.d.ts +3 -0
  23. package/dist/content/views.d.ts.map +1 -1
  24. package/dist/content/views.js +110 -41
  25. package/dist/content/views.js.map +1 -1
  26. package/dist/content/welcome.d.ts.map +1 -1
  27. package/dist/content/welcome.js +19 -7
  28. package/dist/content/welcome.js.map +1 -1
  29. package/dist/dom.js +1 -1
  30. package/dist/dom.js.map +1 -1
  31. package/dist/files/panels.d.ts +8 -1
  32. package/dist/files/panels.d.ts.map +1 -1
  33. package/dist/files/panels.js +235 -120
  34. package/dist/files/panels.js.map +1 -1
  35. package/dist/files/systems.d.ts.map +1 -1
  36. package/dist/files/systems.js +81 -91
  37. package/dist/files/systems.js.map +1 -1
  38. package/dist/forms/actions.d.ts +28 -7
  39. package/dist/forms/actions.d.ts.map +1 -1
  40. package/dist/forms/actions.js +59 -11
  41. package/dist/forms/actions.js.map +1 -1
  42. package/dist/forms/custom-connection.d.ts +2 -1
  43. package/dist/forms/custom-connection.d.ts.map +1 -1
  44. package/dist/forms/custom-connection.js +36 -28
  45. package/dist/forms/custom-connection.js.map +1 -1
  46. package/dist/forms/dialog-frame.d.ts +2 -0
  47. package/dist/forms/dialog-frame.d.ts.map +1 -1
  48. package/dist/forms/dialog-frame.js +46 -26
  49. package/dist/forms/dialog-frame.js.map +1 -1
  50. package/dist/forms/history.d.ts +1 -1
  51. package/dist/forms/history.d.ts.map +1 -1
  52. package/dist/forms/history.js +78 -15
  53. package/dist/forms/history.js.map +1 -1
  54. package/dist/forms/identity.d.ts +12 -0
  55. package/dist/forms/identity.d.ts.map +1 -1
  56. package/dist/forms/identity.js +16 -0
  57. package/dist/forms/identity.js.map +1 -1
  58. package/dist/forms/model-editor.d.ts +8 -3
  59. package/dist/forms/model-editor.d.ts.map +1 -1
  60. package/dist/forms/model-editor.js +73 -62
  61. package/dist/forms/model-editor.js.map +1 -1
  62. package/dist/forms/panels.d.ts +103 -7
  63. package/dist/forms/panels.d.ts.map +1 -1
  64. package/dist/forms/panels.js +183 -77
  65. package/dist/forms/panels.js.map +1 -1
  66. package/dist/forms/provider-login.d.ts.map +1 -1
  67. package/dist/forms/provider-login.js +25 -39
  68. package/dist/forms/provider-login.js.map +1 -1
  69. package/dist/forms/resource-editor.d.ts +9 -5
  70. package/dist/forms/resource-editor.d.ts.map +1 -1
  71. package/dist/forms/resource-editor.js +20 -9
  72. package/dist/forms/resource-editor.js.map +1 -1
  73. package/dist/foundations.d.ts +95 -0
  74. package/dist/foundations.d.ts.map +1 -0
  75. package/dist/foundations.js +299 -0
  76. package/dist/foundations.js.map +1 -0
  77. package/dist/navigation/context-menu.d.ts +8 -1
  78. package/dist/navigation/context-menu.d.ts.map +1 -1
  79. package/dist/navigation/context-menu.js +67 -50
  80. package/dist/navigation/context-menu.js.map +1 -1
  81. package/dist/navigation/navigation.d.ts +55 -7
  82. package/dist/navigation/navigation.d.ts.map +1 -1
  83. package/dist/navigation/navigation.js +167 -18
  84. package/dist/navigation/navigation.js.map +1 -1
  85. package/dist/operation.d.ts +12 -0
  86. package/dist/operation.d.ts.map +1 -0
  87. package/dist/operation.js +49 -0
  88. package/dist/operation.js.map +1 -0
  89. package/dist/primitives.d.ts +11 -1
  90. package/dist/primitives.d.ts.map +1 -1
  91. package/dist/primitives.js +164 -301
  92. package/dist/primitives.js.map +1 -1
  93. package/dist/reconcile.d.ts +11 -0
  94. package/dist/reconcile.d.ts.map +1 -0
  95. package/dist/reconcile.js +36 -0
  96. package/dist/reconcile.js.map +1 -0
  97. package/dist/select.d.ts +14 -0
  98. package/dist/select.d.ts.map +1 -0
  99. package/dist/select.js +304 -0
  100. package/dist/select.js.map +1 -0
  101. package/dist/styles.css +452 -382
  102. package/dist/surface.d.ts +60 -0
  103. package/dist/surface.d.ts.map +1 -0
  104. package/dist/surface.js +344 -0
  105. package/dist/surface.js.map +1 -0
  106. package/dist/tasks/approval.d.ts.map +1 -1
  107. package/dist/tasks/approval.js +86 -45
  108. package/dist/tasks/approval.js.map +1 -1
  109. package/dist/tasks/permission-element.d.ts +3 -0
  110. package/dist/tasks/permission-element.d.ts.map +1 -0
  111. package/dist/tasks/permission-element.js +10 -0
  112. package/dist/tasks/permission-element.js.map +1 -0
  113. package/dist/tasks/permission.d.ts +5 -3
  114. package/dist/tasks/permission.d.ts.map +1 -1
  115. package/dist/tasks/permission.js +47 -22
  116. package/dist/tasks/permission.js.map +1 -1
  117. package/dist/tasks/runtime.d.ts.map +1 -1
  118. package/dist/tasks/runtime.js +30 -13
  119. package/dist/tasks/runtime.js.map +1 -1
  120. package/dist/workspace.d.ts +58 -4
  121. package/dist/workspace.d.ts.map +1 -1
  122. package/dist/workspace.js +202 -44
  123. package/dist/workspace.js.map +1 -1
  124. package/package.json +1 -1
@@ -1,16 +1,33 @@
1
- import { type UIBlock, type ActionResult } from './core.js';
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): UIBlock<WorkspaceShellState> & {
35
- composer: ReturnType<typeof createComposerView>;
36
- part<T extends HTMLElement = HTMLElement>(name: string): T;
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
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAGxE,MAAM,WAAW,iBAAiB;IAAG,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CAAE;AAClK,MAAM,WAAW,mBAAmB;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAAE;AAS/O,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB;;;oBAqB3C,iBAAiB;;iBAyBzB,MAAM;;;;EAGtB;AAED,MAAM,WAAW,qBAAqB;IAAG,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAAE;AACxE,MAAM,WAAW,mBAAmB;IAAG,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CAAE;AAC3G,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG;IAAE,QAAQ,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IAAC,IAAI,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAwEnN"}
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 { Generation } from './core.js';
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
- <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>
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 generation = new Generation();
34
- let pending = false, last = {}, lastAction = 'send';
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
- if (state.placeholder !== undefined)
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
- action.disabled = !!(state.actionDisabled || state.disabled || pending);
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 = async (callback) => {
58
- if (!callback || pending || action.disabled || input.disabled || input.readOnly)
89
+ const run = (callback, textSubmission = true) => {
90
+ if (!callback || (textSubmission && (input.disabled || input.readOnly)))
59
91
  return;
60
- const seq = generation.next();
61
- pending = true;
62
- error.hidden = true;
63
- error.textContent = '';
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 && action.type === 'submit') {
105
+ if (options.onSubmit && event.key === 'Enter' && !event.shiftKey && !event.isComposing) {
94
106
  event.preventDefault();
95
- element.requestSubmit();
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) { generation.invalidate(); pending = false; error.hidden = true; error.textContent = ''; input.value = value; update(last); resize(); }, focus: () => input.focus(), resize,
104
- destroy() { generation.destroy(); input.removeEventListener('input', onInput); input.removeEventListener('keydown', keydown); element.removeEventListener('submit', submit); action.removeEventListener('click', stop); element.remove(); } };
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
- }, destroy() { composer.destroy(); element.remove(); } };
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
@@ -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":"AAAA,OAAO,EAAmC,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAkBjD,IAAI,QAAQ,GAAG,CAAC,CAAC;AACjB,SAAS,QAAQ,CAAC,IAAiB,EAAE,MAAc;IACjD,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC;IACvG,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAc,GAAG,CAAC,CAAC;QAAE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YAC1G,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAAC,IAAI,KAAK;gBAAE,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7I,CAAC;AACH,CAAC;AACD,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,MAAM,CAAC,SAAS,GAAG;;;;;;6KAM0G,IAAI,CAAC,OAAO,CAAC;;;mdAGyR,IAAI,CAAC,OAAO,CAAC;;cAEld,CAAC;IACb,MAAM,OAAO,GAAG,MAAM,CAAC,iBAAoC,CAAC;IAC5D,MAAM,UAAU,GAAG,wBAAwB,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,oBAAoB,CAAC;IACpF,MAAM,cAAc,GAAG,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAE,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,iBAAiB,CAAC;IAAC,cAAc,CAAC,YAAY,CAAC,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;IAC7K,OAAO,CAAC,aAAa,CAAC,wBAAwB,CAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAsB,UAAU,CAAE,CAAC;IACtE,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAoB,iBAAiB,CAAE,CAAC;IAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAoB,uBAAuB,CAAE,CAAC;IACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAoB,gCAAgC,CAAE,CAAC;IAC7F,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAmB,OAAO,CAAE,CAAC;IACnE,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAmB,eAAe,CAAE,CAAC;IAC9E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,IAAI,eAAe,GAAG,EAAE,QAAQ,GAAG,GAAG,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAoB,yBAAyB,CAAE,CAAC,CAAC;IACpF,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,IAAI,GAAsB,EAAE,EAAE,UAAU,GAAG,MAAM,CAAC;IACtD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,KAAK,CAAC,SAAS,GAAG,gBAAgB,CAAC;IAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAC,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1L,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,CAAC,OAAc,EAAE,EAAE,GAAE,QAAQ,CAAC,MAAM,CAAC,EAAC,OAAO,EAAC,IAAI,EAAC,OAAO,EAAC,CAAC,CAAC,CAAA,KAAK,CAAC,MAAM,GAAC,CAAC,OAAO,CAAC,CAAA,CAAC,CAAC;IACtG,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrH,MAAM,MAAM,GAAG,CAAC,KAAwB,EAAE,EAAE;QAC1C,IAAI,SAAS;YAAE,OAAO;QACtB,IAAI,GAAG,KAAK,CAAC;QACb,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACxK,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAAC,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;YAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAAC,CAAC;QAClR,MAAM,WAAW,GAAG,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;QACrH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;QAC3E,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;QAClH,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7H,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC7D,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YACjD,aAAa,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtG,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,CAAC;IACjB,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,eAAe,CAAC,EAAC,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAC,CAAC,CAAC;IACvI,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,CAAC,QAAgF,EAAE,cAAc,GAAG,IAAI,EAAE,EAAE;QACtH,IAAI,CAAC,QAAQ,IAAI,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO;QAChF,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA,OAAO,QAAQ,EAAE,CAAC,CAAA,CAAC,EAAE,MAAM,CAAC,EAAE;YAC9D,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;gBAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,KAAkB,EAAE,EAAE,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAAC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;QAAC,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC;IAChK,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;QAAE,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,CAAC,KAAoB,EAAE,EAAE;QACvC,IAAI,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACvF,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,CAAC,aAAa,EAAE,CAAC;QACxD,CAAC;IACH,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,KAAiB,EAAE,EAAE;QAClC,MAAM,MAAM,GAAI,KAAK,CAAC,MAAkB,CAAC,OAAO,CAAoB,QAAQ,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ;YAAE,OAAO;QACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QACrK,IAAI,QAAQ,EAAE,CAAC;YAAC,KAAK,CAAC,eAAe,EAAE,CAAC;YAAC,QAAQ,EAAE,CAAC;QAAC,CAAC;IACxD,CAAC,CAAC;IACF,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/H,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAAC,WAAW,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9I,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzK,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK;QAC1D,KAAK,CAAC,KAAa,IAAI,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM;QAC3L,UAAU,KAAK,IAAI,CAAC,SAAS;YAAE,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACrD,OAAO,KAAK,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAEnc,CAAC;AAMD,MAAM,UAAU,oBAAoB,CAAC,OAA8B;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7E,OAAO,CAAC,SAAS,GAAG;;;8IAGwH,IAAI,CAAC,MAAM,CAAC;wCAClH,IAAI,CAAC,QAAQ,CAAC;;;oEAGc,IAAI,CAAC,MAAM,CAAC;sEACV,IAAI,CAAC,MAAM,CAAC;mEACf,IAAI,CAAC,UAAU,CAAC;;;;;;;;oGAQiB,IAAI,CAAC,MAAM,CAAC;oCAC5E,IAAI,CAAC,QAAQ,CAAC,iDAAiD,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC;sNAC0E,IAAI,CAAC,UAAU,CAAC,oSAAoS,IAAI,CAAC,MAAM,CAAC;;;;;2JAK3X,IAAI,CAAC,MAAM,CAAC;uHAChD,IAAI,CAAC,MAAM,CAAC;mHAChB,IAAI,CAAC,OAAO,CAAC;;;;;iHAKf,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B5H,CAAC;IACA,OAAO,CAAC,aAAa,CAAC,mBAAmB,CAAE,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,gBAAgB,GAAG,EAAE,QAAQ,GAAG,GAAG,CAAC;IACrE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,aAAa,CAAC,sBAAsB,CAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvJ,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,CAAsC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,CAAI,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAE,CAAC;IAC9H,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAoB,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE;QACjG,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAwB,CAAC;QAC3F,OAAO,CAAC,IAAI,EAAE,sBAAsB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAU,CAAC;IAC3G,CAAC,CAAC,CAAC,CAAC;IACJ,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAc,WAAW,CAAE,CAAC;IAC9D,MAAM,cAAc,GAAG,OAAO,CAAC,aAAa,CAAoB,kBAAkB,CAAE,CAAC;IACrF,MAAM,MAAM,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IAChD,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,cAAc,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACzD,KAAK,CAAC,YAAY,CAAC,aAAa,EAAC,MAAM,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,SAAS;YAAE,OAAO;QACtB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,IAAI,WAAW,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC;QACxC,cAAc,CAAC,YAAY,CAAC,eAAe,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACxG,CAAC,CAAC;IACF,MAAM,cAAc,GAAG,CAAC,IAAa,EAAE,EAAE;QACvC,IAAI,SAAS;YAAE,OAAO;QACtB,MAAM,OAAO,GAAG,WAAW,CAAC;QAAC,WAAW,GAAG,IAAI,CAAC;QAChD,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAAA,IAAI,CAAC,KAAK,GAAC,KAAK,CAAC;YAAA,cAAc,CAAC,KAAK,CAAC,EAAC,aAAa,EAAC,IAAI,EAAC,CAAC,CAAC;QAAA,CAAC;QACvI,WAAW,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,OAAO,IAAI,IAAI,IAAI,CAAC,OAAO;YAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAC,aAAa,EAAC,IAAI,EAAC,CAAC,CAAC;IAC5F,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAAA,IAAI,CAAC,KAAK,GAAC,KAAK,CAAC;YAAA,cAAc,CAAC,KAAK,CAAC,EAAC,aAAa,EAAC,IAAI,EAAC,CAAC,CAAC;QAAA,CAAC;QAC9I,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC;IACF,MAAM,cAAc,GAAG,CAAC,KAAoB,EAAE,EAAE;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC;YAAE,OAAO;QAC/G,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAAA,KAAK,CAAC,cAAc,EAAE,CAAC;YAAA,KAAK,CAAC,eAAe,EAAE,CAAC;YAAA,cAAc,CAAC,KAAK,CAAC,CAAC;YAAA,OAAO;QAAA,CAAC;QAC1G,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;YAAE,OAAO;QAChC,MAAM,QAAQ,GAAC,eAAe,EAAE,EAAE,KAAK,GAAC,QAAQ,CAAC,CAAC,CAAC,EAAC,IAAI,GAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,IAAI,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,aAAa,KAAG,KAAK,EAAE,CAAC;YAAA,KAAK,CAAC,cAAc,EAAE,CAAC;YAAA,IAAI,EAAE,KAAK,EAAE,CAAC;QAAA,CAAC;aACxF,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,aAAa,KAAG,IAAI,EAAE,CAAC;YAAA,KAAK,CAAC,cAAc,EAAE,CAAC;YAAA,KAAK,EAAE,KAAK,EAAE,CAAC;QAAA,CAAC;IACrG,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,CAAC,KAAiB,EAAE,EAAE,GAAG,MAAM,MAAM,GAAG,KAAK,CAAC,MAAiB,CAAC,CAAC,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAAC,cAAc,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC;QAAC,KAAK,CAAC,eAAe,EAAE,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC;IACvO,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAC,YAAY,CAAC,CAAC;IAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAC,cAAc,CAAC,CAAC;IAAC,WAAW,EAAE,CAAC;IAClH,MAAM,MAAM,GAAG,IAAI,CAAmB,gBAAgB,CAAC,CAAC;IAAC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,CAAC,KAAiB,EAAE,EAAE,GAAG,IAAK,KAAK,CAAC,MAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QAAC,KAAK,CAAC,eAAe,EAAE,CAAC;QAAC,OAAO,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC;IACtL,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,KAAoC;YAC3E,IAAI,SAAS;gBAAE,OAAO;YACtB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC;YACzF,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;gBAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC;YAClG,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC;YACvD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAAC,IAAI,CAAC,cAAc,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;gBAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;YAAC,CAAC;YACxJ,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC1B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;oBACf,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;wBAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;wBAAC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAqC,CAAC;wBAAC,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;wBAAC,MAAM,CAAC,SAAS,GAAG,iBAAiB,CAAC;oBAAC,CAAC;oBACjO,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;oBAClC,IAAI,IAAI,CAAC,iBAAkB,CAAC,WAAW,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO;wBAAE,IAAI,CAAC,iBAAkB,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;oBACzH,IAAI,IAAI,CAAC,gBAAiB,CAAC,WAAW,KAAK,KAAK,CAAC,IAAI,CAAC,WAAW;wBAAE,IAAI,CAAC,gBAAiB,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;gBACjI,CAAC;YACH,CAAC;YACD,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,CAAC,EAAE,cAAc;QACjB,UAAU,CAAC,IAAyB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;QAAC,CAAC,CAAC,CAAC;QAC/G,WAAW,CAAC,IAAyB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACtF,YAAY,CAAC,IAAyB,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/F,wBAAwB,CAAC,WAA4C,EAAE,OAAmB,OAAO;YAC/F,IAAI,SAAS;gBAAE,OAAO;YACtB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAoB,kFAAkF,CAAC,EAAE,CAAC;gBAClJ,MAAM,KAAK,GAAgB,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;gBACvX,MAAM,CAAC,QAAQ,GAAG,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;YAChE,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,gBAAgB,CAAoB,+BAA+B,CAAC;gBAAE,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC;QACzN,CAAC;QACD,OAAO,KAAK,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAC,YAAY,CAAC,CAAC,CAAA,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAC,cAAc,CAAC,CAAC,CAAA,OAAO,CAAC,KAAK,GAAC,KAAK,CAAC,CAAA,IAAI,CAAC,KAAK,GAAC,KAAK,CAAC,CAAA,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE;YAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACtc,CAAC","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pith-ui",
3
- "version": "0.1.0",
3
+ "version": "0.1.4",
4
4
  "description": "Native TypeScript building blocks with explicit behavior and a human-verifiable component showroom.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",