arcane-os 0.1.0-dev.5

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 (248) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/COMMERCIAL-LICENSE.md +13 -0
  3. package/LICENSE +661 -0
  4. package/NOTICE +70 -0
  5. package/README.md +448 -0
  6. package/bin/arcane-test.mjs +741 -0
  7. package/bin/arcane.mjs +5 -0
  8. package/docs/architecture.md +234 -0
  9. package/docs/compatibility.md +36 -0
  10. package/docs/event-manager.md +166 -0
  11. package/docs/platform-targets.md +108 -0
  12. package/docs/publishing.md +203 -0
  13. package/docs/reference/README.md +117 -0
  14. package/docs/reference/arcane-ollama.md +288 -0
  15. package/docs/reference/availability-and-normalization.md +123 -0
  16. package/docs/reference/behavioral-testing.md +86 -0
  17. package/docs/reference/cli.md +569 -0
  18. package/docs/reference/core/README.md +62 -0
  19. package/docs/reference/core/arcane-ai-contracts.md +873 -0
  20. package/docs/reference/core/arcane-api.md +601 -0
  21. package/docs/reference/core/arcane-entities.md +65 -0
  22. package/docs/reference/core/arcane-events.md +134 -0
  23. package/docs/reference/core/ollama-module.md +181 -0
  24. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  25. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  26. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  27. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  28. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  29. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  30. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  31. package/docs/reference/event-manager.md +957 -0
  32. package/docs/reference/inventory/package-api.json +2632 -0
  33. package/docs/reference/inventory/runtime-components.json +934 -0
  34. package/docs/reference/inventory/runtime-entities.json +26 -0
  35. package/docs/reference/inventory/runtime-modules.json +1249 -0
  36. package/docs/reference/protocols.md +242 -0
  37. package/docs/reference/runtime-components.md +1098 -0
  38. package/docs/reference/runtime-entities.md +303 -0
  39. package/docs/reference/runtime-modules.md +2010 -0
  40. package/docs/reference/sdk-api.md +4901 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +124 -0
  43. package/node_modules/event-pubsub/CHANGELOG.md +55 -0
  44. package/node_modules/event-pubsub/MIGRATION.md +70 -0
  45. package/node_modules/event-pubsub/README.md +363 -0
  46. package/node_modules/event-pubsub/SECURITY.md +37 -0
  47. package/node_modules/event-pubsub/index.js +141 -0
  48. package/node_modules/event-pubsub/licence +21 -0
  49. package/node_modules/event-pubsub/package.json +59 -0
  50. package/node_modules/strong-type/README.md +408 -0
  51. package/node_modules/strong-type/assets/strong-type-header.png +0 -0
  52. package/node_modules/strong-type/index.js +1151 -0
  53. package/node_modules/strong-type/licence +21 -0
  54. package/node_modules/strong-type/node.js +125 -0
  55. package/node_modules/strong-type/package.json +61 -0
  56. package/package.json +95 -0
  57. package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
  58. package/runtime/arcane/components/app-bar.html +468 -0
  59. package/runtime/arcane/components/assistant-panel.html +715 -0
  60. package/runtime/arcane/components/calculator.html +8 -0
  61. package/runtime/arcane/components/chart.html +655 -0
  62. package/runtime/arcane/components/chat.html +1225 -0
  63. package/runtime/arcane/components/conversation-view.html +13 -0
  64. package/runtime/arcane/components/dashboard-config.html +341 -0
  65. package/runtime/arcane/components/data-maintenance.html +112 -0
  66. package/runtime/arcane/components/data-view.html +92 -0
  67. package/runtime/arcane/components/directory-picker.html +197 -0
  68. package/runtime/arcane/components/document-inspector.html +252 -0
  69. package/runtime/arcane/components/file-drop.html +264 -0
  70. package/runtime/arcane/components/file-inspector.html +293 -0
  71. package/runtime/arcane/components/file-manager.html +1715 -0
  72. package/runtime/arcane/components/header.html +142 -0
  73. package/runtime/arcane/components/integration-settings.html +14 -0
  74. package/runtime/arcane/components/local-ai-status.html +360 -0
  75. package/runtime/arcane/components/markdown-document.html +1048 -0
  76. package/runtime/arcane/components/markdown-editor.html +360 -0
  77. package/runtime/arcane/components/media-embed.html +8 -0
  78. package/runtime/arcane/components/modal.html +402 -0
  79. package/runtime/arcane/components/output-panel.html +259 -0
  80. package/runtime/arcane/components/preferences-form.html +135 -0
  81. package/runtime/arcane/components/record-timeline.html +105 -0
  82. package/runtime/arcane/components/relationship-board.html +116 -0
  83. package/runtime/arcane/components/screen-capture.html +8 -0
  84. package/runtime/arcane/components/source-code-viewer.html +441 -0
  85. package/runtime/arcane/components/source-explanation.html +124 -0
  86. package/runtime/arcane/components/speech.html +365 -0
  87. package/runtime/arcane/components/summary-strip.html +177 -0
  88. package/runtime/arcane/components/table.html +77 -0
  89. package/runtime/arcane/components/task-progress.html +282 -0
  90. package/runtime/arcane/components/terminal-workspace.html +65 -0
  91. package/runtime/arcane/components/theme-editor.html +41 -0
  92. package/runtime/arcane/components/theme-switcher.html +46 -0
  93. package/runtime/arcane/components/unified-inbox.html +20 -0
  94. package/runtime/arcane/components/voice-transcription.html +476 -0
  95. package/runtime/arcane/components/weather-widget.html +8 -0
  96. package/runtime/arcane/components/web-navigator.html +239 -0
  97. package/runtime/arcane/css/communications.css +1 -0
  98. package/runtime/arcane/css/dashboard-config.css +45 -0
  99. package/runtime/arcane/css/document-site.css +981 -0
  100. package/runtime/arcane/css/layout.css +438 -0
  101. package/runtime/arcane/css/primitives.css +321 -0
  102. package/runtime/arcane/css/theme.css +112 -0
  103. package/runtime/arcane/css/utility-workspace.css +1 -0
  104. package/runtime/arcane/entities/ApiModelRecord.js +20 -0
  105. package/runtime/arcane/entities/Calculation.js +13 -0
  106. package/runtime/arcane/entities/Chat.js +581 -0
  107. package/runtime/arcane/entities/CommunicationMessage.js +29 -0
  108. package/runtime/arcane/entities/CommunicationThread.js +21 -0
  109. package/runtime/arcane/entities/Document.js +10 -0
  110. package/runtime/arcane/entities/File.js +143 -0
  111. package/runtime/arcane/entities/Image.js +135 -0
  112. package/runtime/arcane/entities/IntentEnvelope.js +834 -0
  113. package/runtime/arcane/entities/Preference.js +83 -0
  114. package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
  115. package/runtime/arcane/entities/TerminalSession.js +46 -0
  116. package/runtime/arcane/entities/Theme.js +107 -0
  117. package/runtime/arcane/entities/User.js +1046 -0
  118. package/runtime/arcane/entities/Weather.js +23 -0
  119. package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
  120. package/runtime/arcane/img/arrow-left.png +0 -0
  121. package/runtime/arcane/img/arrow-right.png +0 -0
  122. package/runtime/arcane/img/doc.svg +5 -0
  123. package/runtime/arcane/img/folder.svg +4 -0
  124. package/runtime/arcane/img/image.svg +5 -0
  125. package/runtime/arcane/img/refresh.png +0 -0
  126. package/runtime/arcane/img/send.svg +9 -0
  127. package/runtime/arcane/img/trash.svg +5 -0
  128. package/runtime/arcane/img/upload.svg +5 -0
  129. package/runtime/arcane/modules/AI.js +2048 -0
  130. package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
  131. package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
  132. package/runtime/arcane/modules/AIResponseLength.js +42 -0
  133. package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
  134. package/runtime/arcane/modules/AnsiText.js +53 -0
  135. package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
  136. package/runtime/arcane/modules/AppDataScope.js +245 -0
  137. package/runtime/arcane/modules/AppearancePreferences.js +28 -0
  138. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
  139. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
  140. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
  141. package/runtime/arcane/modules/AsyncBoundary.js +161 -0
  142. package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
  143. package/runtime/arcane/modules/CalculatorEngine.js +20 -0
  144. package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
  145. package/runtime/arcane/modules/ChartLibrary.js +35 -0
  146. package/runtime/arcane/modules/ChatRecords.js +13 -0
  147. package/runtime/arcane/modules/CommunicationAppController.js +43 -0
  148. package/runtime/arcane/modules/CommunicationHub.js +16 -0
  149. package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
  150. package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
  151. package/runtime/arcane/modules/ComponentContracts.js +586 -0
  152. package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
  153. package/runtime/arcane/modules/ConversationActionItems.js +488 -0
  154. package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
  155. package/runtime/arcane/modules/ConversationTimebox.js +527 -0
  156. package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
  157. package/runtime/arcane/modules/DBLS.js +171 -0
  158. package/runtime/arcane/modules/DBOPFS.js +1154 -0
  159. package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
  160. package/runtime/arcane/modules/DataMaintenance.js +91 -0
  161. package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
  162. package/runtime/arcane/modules/DirectoryPicker.js +109 -0
  163. package/runtime/arcane/modules/DocumentNavigation.js +223 -0
  164. package/runtime/arcane/modules/Errors.js +1025 -0
  165. package/runtime/arcane/modules/GifEncoder.js +29 -0
  166. package/runtime/arcane/modules/HTMLImport.js +114 -0
  167. package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
  168. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
  169. package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
  170. package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
  171. package/runtime/arcane/modules/MD.js +111 -0
  172. package/runtime/arcane/modules/Mail.js +352 -0
  173. package/runtime/arcane/modules/MailTransport.mjs +180 -0
  174. package/runtime/arcane/modules/Marked.min.js +71 -0
  175. package/runtime/arcane/modules/MemoryRecords.js +44 -0
  176. package/runtime/arcane/modules/MessageAdvisory.js +38 -0
  177. package/runtime/arcane/modules/ModelDefinition.js +189 -0
  178. package/runtime/arcane/modules/Ollama.js +74 -0
  179. package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
  180. package/runtime/arcane/modules/OllamaSettings.js +24 -0
  181. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
  182. package/runtime/arcane/modules/PreferenceStore.js +109 -0
  183. package/runtime/arcane/modules/QRCode.min.js +1 -0
  184. package/runtime/arcane/modules/Questionnaire.js +61 -0
  185. package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
  186. package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
  187. package/runtime/arcane/modules/RecordReviewStore.js +94 -0
  188. package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
  189. package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
  190. package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
  191. package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
  192. package/runtime/arcane/modules/ScreenCapture.js +20 -0
  193. package/runtime/arcane/modules/SpeechPlayback.js +581 -0
  194. package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
  195. package/runtime/arcane/modules/SystemAppearance.js +20 -0
  196. package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
  197. package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
  198. package/runtime/arcane/modules/TerminalClient.js +52 -0
  199. package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
  200. package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
  201. package/runtime/arcane/modules/ThemeManager.js +131 -0
  202. package/runtime/arcane/modules/TimeGuard.js +149 -0
  203. package/runtime/arcane/modules/ToolCallRouter.js +83 -0
  204. package/runtime/arcane/modules/WaitForComponent.js +102 -0
  205. package/runtime/arcane/modules/YouTubeMedia.js +16 -0
  206. package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
  207. package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
  208. package/runtime/arcane/modules/uPlot.min.css +1 -0
  209. package/runtime/arcane/security/arcane-network-policy.json +6 -0
  210. package/runtime/strong-type/index.js +352 -0
  211. package/runtime/strong-type/licence +21 -0
  212. package/runtime/strong-type/package.json +45 -0
  213. package/schemas/arcane-app-bundle.schema.json +125 -0
  214. package/schemas/arcane-app.schema.json +329 -0
  215. package/schemas/arcane-lock.schema.json +86 -0
  216. package/schemas/arcane-package.schema.json +224 -0
  217. package/schemas/cli-event.schema.json +122 -0
  218. package/schemas/event-stack.schema.json +152 -0
  219. package/schemas/native-build-plan.schema.json +176 -0
  220. package/schemas/target-adapter.schema.json +117 -0
  221. package/src/app-descriptor.mjs +500 -0
  222. package/src/cli/main.mjs +561 -0
  223. package/src/constants.mjs +31 -0
  224. package/src/dev-server.mjs +718 -0
  225. package/src/doctor.mjs +315 -0
  226. package/src/dom-event-instrumentation.mjs +594 -0
  227. package/src/errors.mjs +75 -0
  228. package/src/event-manager.mjs +1342 -0
  229. package/src/event-queue.mjs +138 -0
  230. package/src/events.mjs +219 -0
  231. package/src/index.mjs +177 -0
  232. package/src/integrated-provider-loader.mjs +432 -0
  233. package/src/native-plan.mjs +698 -0
  234. package/src/native-provider-loader.mjs +1126 -0
  235. package/src/packager/core.mjs +2691 -0
  236. package/src/process.mjs +353 -0
  237. package/src/release-bundle.mjs +2523 -0
  238. package/src/repository.mjs +90 -0
  239. package/src/runtime.mjs +452 -0
  240. package/src/scaffold.mjs +380 -0
  241. package/src/targets/index.mjs +436 -0
  242. package/src/templates/assets/app-icon.png +0 -0
  243. package/src/templates/workspace-template.mjs +388 -0
  244. package/src/testing-loader.mjs +9 -0
  245. package/src/testing.mjs +427 -0
  246. package/src/toolchain.mjs +1335 -0
  247. package/src/update-check.mjs +307 -0
  248. package/src/workspace.mjs +449 -0
@@ -0,0 +1,715 @@
1
+ <style>
2
+ :host{
3
+ --assistant-panel-width:24rem;
4
+ --assistant-surface:var(--modal-background,#fff);
5
+ --assistant-text:var(--text-color,#172238);
6
+ --assistant-border:var(--border-color,rgba(23,34,56,.18));
7
+ --assistant-accent:var(--primary-color,#315b8a);
8
+ --assistant-muted:color-mix(in srgb,var(--assistant-text) 66%,transparent);
9
+ box-sizing:border-box;
10
+ display:block;
11
+ min-width:0;
12
+ color:var(--assistant-text);
13
+ }
14
+
15
+ :host(:not([data-open])){
16
+ display:none;
17
+ }
18
+
19
+ *,*::before,*::after{
20
+ box-sizing:border-box;
21
+ }
22
+
23
+ .assistant-shell{
24
+ display:flex;
25
+ min-width:0;
26
+ height:100%;
27
+ }
28
+
29
+ .backdrop{
30
+ display:none;
31
+ }
32
+
33
+ .panel{
34
+ display:flex;
35
+ flex:1 1 auto;
36
+ flex-direction:column;
37
+ min-width:0;
38
+ width:100%;
39
+ height:100%;
40
+ overflow:hidden;
41
+ color:var(--assistant-text);
42
+ background:var(--assistant-surface);
43
+ border-inline-start:1px solid var(--assistant-border);
44
+ box-shadow:-.4rem 0 1.4rem var(--shadow-color,rgba(0,0,0,.16));
45
+ }
46
+
47
+ .header{
48
+ display:grid;
49
+ grid-template-columns:auto minmax(0,1fr) auto;
50
+ align-items:center;
51
+ gap:.75rem;
52
+ padding:1rem;
53
+ border-bottom:1px solid var(--assistant-border);
54
+ }
55
+
56
+ .identity:empty{
57
+ display:none;
58
+ }
59
+
60
+ .heading{
61
+ min-width:0;
62
+ }
63
+
64
+ h2{
65
+ margin:0;
66
+ font:700 1rem/1.25 system-ui,sans-serif;
67
+ }
68
+
69
+ .subtitle{
70
+ margin:.18rem 0 0;
71
+ overflow:hidden;
72
+ color:var(--assistant-muted);
73
+ font:.78rem/1.35 system-ui,sans-serif;
74
+ text-overflow:ellipsis;
75
+ white-space:nowrap;
76
+ }
77
+
78
+ .subtitle:empty{
79
+ display:none;
80
+ }
81
+
82
+ button{
83
+ min-height:2.25rem;
84
+ border:1px solid var(--assistant-border);
85
+ border-radius:.48rem;
86
+ padding:.48rem .7rem;
87
+ color:inherit;
88
+ background:transparent;
89
+ cursor:pointer;
90
+ font:650 .78rem/1 system-ui,sans-serif;
91
+ }
92
+
93
+ button:hover{
94
+ background:color-mix(in srgb,var(--assistant-accent) 10%,transparent);
95
+ }
96
+
97
+ button:focus-visible,
98
+ textarea:focus-visible{
99
+ outline:.18rem solid var(--focus-color,var(--assistant-accent));
100
+ outline-offset:.14rem;
101
+ }
102
+
103
+ .close-button{
104
+ width:2.25rem;
105
+ padding:0;
106
+ font-size:1.15rem;
107
+ }
108
+
109
+ .body{
110
+ display:flex;
111
+ flex:1 1 auto;
112
+ flex-direction:column;
113
+ min-height:0;
114
+ }
115
+
116
+ .state{
117
+ margin:.85rem 1rem 0;
118
+ border:1px solid var(--assistant-border);
119
+ border-radius:.55rem;
120
+ padding:.72rem .8rem;
121
+ color:var(--assistant-muted);
122
+ background:color-mix(in srgb,var(--assistant-accent) 5%,transparent);
123
+ font:.82rem/1.4 system-ui,sans-serif;
124
+ }
125
+
126
+ .state[hidden],
127
+ .state-view{
128
+ display:none;
129
+ }
130
+
131
+ .assistant-shell[data-state="empty"] [data-state-view="empty"],
132
+ .assistant-shell[data-state="pending"] [data-state-view="pending"],
133
+ .assistant-shell[data-state="streaming"] [data-state-view="streaming"],
134
+ .assistant-shell[data-state="error"] [data-state-view="error"]{
135
+ display:block;
136
+ }
137
+
138
+ .assistant-shell[data-state="pending"] .state,
139
+ .assistant-shell[data-state="streaming"] .state{
140
+ border-color:color-mix(in srgb,var(--assistant-accent) 38%,var(--assistant-border));
141
+ }
142
+
143
+ .assistant-shell[data-state="error"] .state{
144
+ color:var(--danger-color,#a52d26);
145
+ border-color:color-mix(in srgb,var(--danger-color,#a52d26) 42%,var(--assistant-border));
146
+ background:color-mix(in srgb,var(--danger-color,#a52d26) 7%,transparent);
147
+ }
148
+
149
+ .messages{
150
+ flex:1 1 auto;
151
+ min-height:0;
152
+ overflow:auto;
153
+ padding:1rem;
154
+ }
155
+
156
+ .composer-region{
157
+ padding:.8rem 1rem;
158
+ border-top:1px solid var(--assistant-border);
159
+ }
160
+
161
+ .composer{
162
+ display:grid;
163
+ grid-template-columns:minmax(0,1fr) auto;
164
+ align-items:end;
165
+ gap:.55rem;
166
+ margin:0;
167
+ }
168
+
169
+ textarea{
170
+ width:100%;
171
+ min-height:2.7rem;
172
+ max-height:10rem;
173
+ resize:vertical;
174
+ border:1px solid var(--assistant-border);
175
+ border-radius:.55rem;
176
+ padding:.7rem .75rem;
177
+ color:inherit;
178
+ background:var(--assistant-surface);
179
+ font:inherit;
180
+ }
181
+
182
+ .send-button{
183
+ color:var(--button-text-color,#fff);
184
+ background:var(--assistant-accent);
185
+ border-color:var(--assistant-accent);
186
+ }
187
+
188
+ .actions{
189
+ display:flex;
190
+ align-items:center;
191
+ justify-content:flex-end;
192
+ gap:.5rem;
193
+ padding:0 1rem .8rem;
194
+ }
195
+
196
+ .footer{
197
+ padding:.7rem 1rem;
198
+ color:var(--assistant-muted);
199
+ border-top:1px solid var(--assistant-border);
200
+ font:.72rem/1.35 system-ui,sans-serif;
201
+ }
202
+
203
+ .footer:empty{
204
+ display:none;
205
+ }
206
+
207
+ :host([data-layout="overlay"]){
208
+ position:fixed;
209
+ inset:0;
210
+ z-index:1000;
211
+ width:auto;
212
+ height:auto;
213
+ }
214
+
215
+ :host([data-layout="overlay"]) .assistant-shell{
216
+ justify-content:flex-end;
217
+ }
218
+
219
+ :host([data-layout="overlay"]) .backdrop{
220
+ position:absolute;
221
+ inset:0;
222
+ display:block;
223
+ border:0;
224
+ border-radius:0;
225
+ padding:0;
226
+ background:rgba(0,0,0,.48);
227
+ }
228
+
229
+ :host([data-layout="overlay"]) .panel{
230
+ position:relative;
231
+ flex:0 1 var(--assistant-panel-width);
232
+ width:min(100%,var(--assistant-panel-width));
233
+ max-width:100%;
234
+ }
235
+
236
+ @media(max-width:34rem){
237
+ :host([data-layout="overlay"]) .panel{
238
+ flex-basis:100%;
239
+ }
240
+
241
+ .header,.messages,.composer-region{
242
+ padding-inline:.75rem;
243
+ }
244
+
245
+ .actions{
246
+ padding-inline:.75rem;
247
+ }
248
+ }
249
+
250
+ @media(prefers-reduced-motion:no-preference){
251
+ :host([data-layout="overlay"]) .panel{
252
+ animation:assistant-panel-enter 160ms ease-out;
253
+ }
254
+
255
+ @keyframes assistant-panel-enter{
256
+ from{transform:translateX(1rem);opacity:.7}
257
+ to{transform:none;opacity:1}
258
+ }
259
+ }
260
+ </style>
261
+
262
+ <section class="assistant-shell" data-state="empty" part="container">
263
+ <button class="backdrop" type="button" tabindex="-1" aria-label="Close assistant" part="backdrop"></button>
264
+ <aside class="panel" role="complementary" aria-labelledby="assistant-title" aria-hidden="true" tabindex="-1" part="panel">
265
+ <header class="header" part="header">
266
+ <div class="identity" part="identity"><slot name="identity"></slot></div>
267
+ <div class="heading" part="heading">
268
+ <h2 id="assistant-title" part="title"><slot name="title"><span id="defaultTitle">Assistant</span></slot></h2>
269
+ <p class="subtitle" part="subtitle"><slot name="subtitle"><span id="defaultSubtitle"></span></slot></p>
270
+ </div>
271
+ <button class="close-button" type="button" aria-label="Close assistant" title="Close assistant" part="close-button">&times;</button>
272
+ </header>
273
+
274
+ <div class="body" part="body">
275
+ <div class="state" role="status" aria-live="polite" part="state">
276
+ <div class="state-view" data-state-view="empty" part="empty-state"><slot name="empty"><span id="emptyMessage">No messages yet.</span></slot></div>
277
+ <div class="state-view" data-state-view="pending" part="pending-state"><slot name="pending"><span id="pendingMessage">Working…</span></slot></div>
278
+ <div class="state-view" data-state-view="streaming" part="streaming-state"><slot name="streaming"><span id="streamingMessage">Responding…</span></slot></div>
279
+ <div class="state-view" data-state-view="error" part="error-state"><slot name="error"><span id="errorMessage">The assistant could not complete that request.</span></slot></div>
280
+ </div>
281
+ <div class="messages" part="messages"><slot name="messages" id="messagesSlot"></slot></div>
282
+ </div>
283
+
284
+ <div class="composer-region" part="composer">
285
+ <slot name="composer" id="composerSlot">
286
+ <form class="composer" id="defaultComposer">
287
+ <textarea name="message" aria-label="Message" placeholder="Write a message…" rows="1"></textarea>
288
+ <button class="send-button" type="submit" part="send-button">Send</button>
289
+ </form>
290
+ </slot>
291
+ </div>
292
+
293
+ <div class="actions" part="actions">
294
+ <slot name="actions"><button class="clear-button" type="button" part="clear-button">Clear</button></slot>
295
+ </div>
296
+ <footer class="footer" part="footer"><slot name="footer"></slot></footer>
297
+ </aside>
298
+ </section>
299
+
300
+ <script type="module">
301
+ const host=this;
302
+ const root=host.shadowRoot;
303
+ const shell=root.querySelector('.assistant-shell');
304
+ const panel=root.querySelector('.panel');
305
+ const stateRegion=root.querySelector('.state');
306
+ const messagesSlot=root.querySelector('#messagesSlot');
307
+ const composerSlot=root.querySelector('#composerSlot');
308
+ const defaultComposer=root.querySelector('#defaultComposer');
309
+ const closeButton=root.querySelector('.close-button');
310
+ const clearButton=root.querySelector('.clear-button');
311
+ const backdrop=root.querySelector('.backdrop');
312
+ const validStates=new Set(['ready','empty','pending','streaming','error']);
313
+ const handledSubmits=new WeakSet();
314
+ const pendingDisabledState=new WeakMap();
315
+
316
+ let previousFocus=null;
317
+ let opened=host.hasAttribute('data-open');
318
+
319
+ host.open=open;
320
+ host.close=close;
321
+ host.toggle=toggle;
322
+ host.send=send;
323
+ host.clear=clear;
324
+ host.setState=setState;
325
+ host.focusComposer=focusComposer;
326
+ host.scrollToEnd=scrollToEnd;
327
+
328
+ Object.defineProperties(
329
+ host,
330
+ {
331
+ opened:{
332
+ configurable:true,
333
+ get:()=>opened,
334
+ set:value=>setOpened(Boolean(value))
335
+ },
336
+ layout:{
337
+ configurable:true,
338
+ get:()=>host.getAttribute('data-layout')||'docked',
339
+ set:value=>{
340
+ host.setAttribute('data-layout',value==='overlay'?'overlay':'docked');
341
+ syncLayout();
342
+ }
343
+ },
344
+ state:{
345
+ configurable:true,
346
+ get:()=>shell.dataset.state,
347
+ set:value=>setState(value)
348
+ }
349
+ }
350
+ );
351
+
352
+ closeButton.addEventListener('click',()=>close());
353
+ clearButton.addEventListener('click',()=>clear());
354
+ backdrop.addEventListener('click',()=>close());
355
+ root.addEventListener('submit',onComposerSubmit);
356
+ host.addEventListener('submit',onComposerSubmit);
357
+ host.addEventListener('click',onHostAction);
358
+ document.addEventListener('keydown',onDocumentKeydown);
359
+ messagesSlot.addEventListener('slotchange',syncState);
360
+ composerSlot.addEventListener('slotchange',syncComposerState);
361
+
362
+ const observer=new MutationObserver(
363
+ records=>{
364
+ const attributes=new Set(records.map(record=>record.attributeName));
365
+
366
+ if(attributes.has('data-open')){
367
+ applyOpenedAttribute();
368
+ }
369
+ if(attributes.has('data-layout')){
370
+ syncLayout();
371
+ }
372
+ if(attributes.has('data-state')||attributes.has('data-error')||attributes.has('data-state-message')){
373
+ syncState();
374
+ }
375
+ if(attributes.has('data-title')||attributes.has('data-subtitle')){
376
+ syncLabels();
377
+ }
378
+ }
379
+ );
380
+
381
+ observer.observe(
382
+ host,
383
+ {
384
+ attributes:true,
385
+ attributeFilter:['data-open','data-layout','data-state','data-error','data-state-message','data-title','data-subtitle']
386
+ }
387
+ );
388
+
389
+ function open(options={}){
390
+ return setOpened(true,options);
391
+ }
392
+
393
+ function close(options={}){
394
+ return setOpened(false,options);
395
+ }
396
+
397
+ function toggle(force,options={}){
398
+ const next=typeof force==='boolean'?force:!opened;
399
+ return setOpened(next,options);
400
+ }
401
+
402
+ function setOpened(next,options={}){
403
+ const changed=next!==opened;
404
+
405
+ if(next&&changed){
406
+ const active=document.activeElement;
407
+ previousFocus=active&&active!==document.body?active:null;
408
+ }
409
+
410
+ opened=next;
411
+ host.toggleAttribute('data-open',next);
412
+ syncOpenedState();
413
+
414
+ if(!changed){
415
+ return false;
416
+ }
417
+
418
+ host.dispatchEvent(
419
+ new CustomEvent(
420
+ next?'assistant-opened':'assistant-closed',
421
+ {
422
+ detail:{assistant:host,layout:host.layout},
423
+ bubbles:true,
424
+ composed:true
425
+ }
426
+ )
427
+ );
428
+
429
+ if(next&&options.focus!==false){
430
+ requestAnimationFrame(()=>focusComposer());
431
+ }else if(!next&&options.returnFocus!==false){
432
+ returnFocus();
433
+ }
434
+
435
+ return true;
436
+ }
437
+
438
+ function applyOpenedAttribute(){
439
+ const next=host.hasAttribute('data-open');
440
+
441
+ if(next===opened){
442
+ syncOpenedState();
443
+ return;
444
+ }
445
+
446
+ setOpened(next);
447
+ }
448
+
449
+ function syncOpenedState(){
450
+ panel.setAttribute('aria-hidden',String(!opened));
451
+ host.setAttribute('aria-expanded',String(opened));
452
+ host.setAttribute('aria-hidden',String(!opened));
453
+ }
454
+
455
+ function syncLayout(){
456
+ const layout=host.getAttribute('data-layout')==='overlay'?'overlay':'docked';
457
+
458
+ if(host.getAttribute('data-layout')!==layout){
459
+ host.setAttribute('data-layout',layout);
460
+ }
461
+
462
+ panel.setAttribute('role',layout==='overlay'?'dialog':'complementary');
463
+ if(layout==='overlay'){
464
+ panel.setAttribute('aria-modal','true');
465
+ }else{
466
+ panel.removeAttribute('aria-modal');
467
+ }
468
+ }
469
+
470
+ function syncLabels(){
471
+ root.querySelector('#defaultTitle').textContent=host.dataset.title||'Assistant';
472
+ root.querySelector('#defaultSubtitle').textContent=host.dataset.subtitle||'';
473
+ }
474
+
475
+ function assignedMessageContent(){
476
+ return messagesSlot.assignedNodes({flatten:true}).some(
477
+ node=>node.nodeType===Node.ELEMENT_NODE||Boolean(node.textContent?.trim())
478
+ );
479
+ }
480
+
481
+ function syncState(){
482
+ const requested=host.getAttribute('data-state');
483
+ const next=validStates.has(requested)?requested:(assignedMessageContent()?'ready':'empty');
484
+ const message=host.dataset.stateMessage||'';
485
+
486
+ shell.dataset.state=next;
487
+ panel.setAttribute('aria-busy',String(next==='pending'||next==='streaming'));
488
+ stateRegion.hidden=next==='ready';
489
+ stateRegion.setAttribute('role',next==='error'?'alert':'status');
490
+
491
+ if(message){
492
+ const target=root.querySelector(`#${next}Message`);
493
+ if(target){
494
+ target.textContent=message;
495
+ }
496
+ }
497
+
498
+ if(next==='error'&&host.dataset.error){
499
+ root.querySelector('#errorMessage').textContent=host.dataset.error;
500
+ }
501
+
502
+ syncComposerState();
503
+ }
504
+
505
+ function setState(next='ready',message=''){
506
+ if(next==='auto'||next===null){
507
+ host.removeAttribute('data-state');
508
+ host.removeAttribute('data-state-message');
509
+ }else{
510
+ const normalized=validStates.has(next)?next:'ready';
511
+ host.setAttribute('data-state',normalized);
512
+ if(message){
513
+ host.setAttribute('data-state-message',String(message));
514
+ }else{
515
+ host.removeAttribute('data-state-message');
516
+ }
517
+ }
518
+
519
+ syncState();
520
+ return shell.dataset.state;
521
+ }
522
+
523
+ function syncComposerState(){
524
+ const disabled=shell.dataset.state==='pending';
525
+ const controls=composerControls();
526
+ controls.forEach(control=>{
527
+ if(control.matches('button,input,textarea,select')){
528
+ if(disabled&&!pendingDisabledState.has(control)){
529
+ pendingDisabledState.set(control,control.disabled);
530
+ control.disabled=true;
531
+ control.setAttribute('aria-disabled','true');
532
+ }else if(!disabled&&pendingDisabledState.has(control)){
533
+ control.disabled=pendingDisabledState.get(control);
534
+ control.toggleAttribute('aria-disabled',control.disabled);
535
+ pendingDisabledState.delete(control);
536
+ }
537
+ }
538
+ });
539
+ }
540
+
541
+ function composerControls(){
542
+ const assigned=composerSlot.assignedElements({flatten:true});
543
+ const roots=assigned.length?assigned:[defaultComposer];
544
+ const controls=[];
545
+
546
+ roots.forEach(element=>{
547
+ controls.push(element);
548
+ controls.push(...element.querySelectorAll('button,input,textarea,select,[tabindex]'));
549
+ });
550
+
551
+ return controls;
552
+ }
553
+
554
+ function focusComposer(){
555
+ const controls=composerControls();
556
+ const target=controls.find(
557
+ element=>element.matches?.('textarea,input:not([type="hidden"]),[contenteditable="true"]')&&!element.disabled
558
+ )||closeButton;
559
+
560
+ target.focus({preventScroll:true});
561
+ return target;
562
+ }
563
+
564
+ function scrollToEnd(options={}){
565
+ const messages=root.querySelector('.messages');
566
+ messages.scrollTo({
567
+ top:messages.scrollHeight,
568
+ behavior:options.behavior==='smooth'?'smooth':'auto'
569
+ });
570
+ return messages.scrollTop;
571
+ }
572
+
573
+ function returnFocus(){
574
+ if(previousFocus?.isConnected&&typeof previousFocus.focus==='function'){
575
+ previousFocus.focus({preventScroll:true});
576
+ }
577
+ previousFocus=null;
578
+ }
579
+
580
+ function onComposerSubmit(event){
581
+ if(handledSubmits.has(event)){
582
+ return;
583
+ }
584
+
585
+ handledSubmits.add(event);
586
+ event.preventDefault();
587
+ const form=event.target;
588
+ const input=form.querySelector('[data-assistant-input],[name="message"],textarea,input[type="text"]');
589
+ const message=input?.value??input?.textContent??'';
590
+ const accepted=send(message,{form:form,submitter:event.submitter||null});
591
+
592
+ if(accepted&&input&&'value' in input){
593
+ input.value='';
594
+ }
595
+ }
596
+
597
+ function send(message='',context={}){
598
+ const normalized=String(message??'').trim();
599
+
600
+ if(!normalized){
601
+ return false;
602
+ }
603
+
604
+ return host.dispatchEvent(
605
+ new CustomEvent(
606
+ 'assistant-send',
607
+ {
608
+ detail:{...context,message:normalized,assistant:host},
609
+ bubbles:true,
610
+ composed:true,
611
+ cancelable:true
612
+ }
613
+ )
614
+ );
615
+ }
616
+
617
+ function clear(detail={}){
618
+ return host.dispatchEvent(
619
+ new CustomEvent(
620
+ 'assistant-clear',
621
+ {
622
+ detail:{...detail,assistant:host},
623
+ bubbles:true,
624
+ composed:true,
625
+ cancelable:true
626
+ }
627
+ )
628
+ );
629
+ }
630
+
631
+ function onHostAction(event){
632
+ const action=event.target.closest?.('[data-assistant-toggle],[data-assistant-close],[data-assistant-clear]');
633
+
634
+ if(!action||!host.contains(action)){
635
+ return;
636
+ }
637
+
638
+ if(action.hasAttribute('data-assistant-toggle')){
639
+ toggle();
640
+ }else if(action.hasAttribute('data-assistant-close')){
641
+ close();
642
+ }else if(action.hasAttribute('data-assistant-clear')){
643
+ clear({source:action});
644
+ }
645
+ }
646
+
647
+ function focusableElements(){
648
+ const selector='a[href],button:not([disabled]),input:not([disabled]),textarea:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])';
649
+ const elements=[...root.querySelectorAll(selector),...host.querySelectorAll(selector)];
650
+ return elements.filter(element=>!element.hidden&&element.getAttribute('aria-hidden')!=='true');
651
+ }
652
+
653
+ function onDocumentKeydown(event){
654
+ if(!opened){
655
+ return;
656
+ }
657
+
658
+ if(event.key==='Escape'){
659
+ const modalOpen=Boolean(
660
+ document.querySelector('dialog[open]')
661
+ ||globalThis.modalStack?.length
662
+ );
663
+ const focusInside=document.activeElement===host
664
+ ||host.contains(document.activeElement)
665
+ ||Boolean(root.activeElement);
666
+ if(host.layout!=='overlay'||modalOpen||!focusInside){
667
+ return;
668
+ }
669
+ event.preventDefault();
670
+ close();
671
+ return;
672
+ }
673
+
674
+ if(event.key!=='Tab'||host.layout!=='overlay'){
675
+ return;
676
+ }
677
+
678
+ const focusable=focusableElements();
679
+ if(!focusable.length){
680
+ event.preventDefault();
681
+ panel.focus();
682
+ return;
683
+ }
684
+
685
+ const first=focusable[0];
686
+ const last=focusable[focusable.length-1];
687
+ const active=root.activeElement||document.activeElement;
688
+
689
+ if(event.shiftKey&&active===first){
690
+ event.preventDefault();
691
+ last.focus();
692
+ }else if(!event.shiftKey&&active===last){
693
+ event.preventDefault();
694
+ first.focus();
695
+ }
696
+ }
697
+
698
+ syncLabels();
699
+ syncLayout();
700
+ syncOpenedState();
701
+ syncState();
702
+ syncComposerState();
703
+
704
+ host.ready=true;
705
+ host.dispatchEvent(
706
+ new CustomEvent(
707
+ 'assistant-ready',
708
+ {
709
+ detail:{assistant:host},
710
+ bubbles:true,
711
+ composed:true
712
+ }
713
+ )
714
+ );
715
+ </script>