arcane-os 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +29 -22
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +203 -0
- package/browser-runtime/ai/browser-kokoro-worker.mjs +11 -2
- package/browser-runtime/ai/browser-speech-artifacts.mjs +3230 -397
- package/browser-runtime/ai/browser-speech-providers.mjs +1141 -157
- package/browser-runtime/ai/browser-speech.mjs +2 -0
- package/browser-runtime/ai/browser-whisper-worker.mjs +11 -2
- package/browser-runtime/ai/model-controller.mjs +285 -95
- package/browser-runtime/ai/speech-worker-client.mjs +247 -32
- package/browser-runtime/ai/speech-worker-runtime.mjs +2310 -167
- package/browser-runtime/event-manager.mjs +1097 -1
- package/docs/architecture.md +2 -2
- package/docs/event-manager.md +155 -27
- package/docs/reference/README.md +27 -27
- package/docs/reference/ai/browser-speech-package-authority.json +835 -0
- package/docs/reference/ai/browser-speech.md +1162 -246
- package/docs/reference/ai/browser-wasm.md +18 -7
- package/docs/reference/availability-and-normalization.md +6 -3
- package/docs/reference/behavioral-testing.md +29 -6
- package/docs/reference/cli.md +117 -9
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/event-manager.md +577 -32
- package/docs/reference/inventory/package-api.json +478 -2
- package/docs/reference/inventory/runtime-components.json +108 -44
- package/docs/reference/inventory/runtime-modules.json +131 -53
- package/docs/reference/mail.md +316 -0
- package/docs/reference/protocols.md +157 -43
- package/docs/reference/runtime-components.md +258 -83
- package/docs/reference/runtime-modules.md +613 -77
- package/docs/reference/sdk-api.md +1014 -25
- package/package.json +5 -4
- package/runtime/ARCANE_RUNTIME_RELEASE.json +145 -140
- package/runtime/arcane/components/app-bar.html +34 -13
- package/runtime/arcane/components/assistant-panel.html +110 -57
- package/runtime/arcane/components/calculator.html +7 -4
- package/runtime/arcane/components/chart.html +58 -17
- package/runtime/arcane/components/chat.html +606 -136
- package/runtime/arcane/components/conversation-view.html +13 -6
- package/runtime/arcane/components/dashboard-config.html +96 -59
- package/runtime/arcane/components/data-maintenance.html +69 -14
- package/runtime/arcane/components/data-view.html +53 -7
- package/runtime/arcane/components/directory-picker.html +118 -32
- package/runtime/arcane/components/document-inspector.html +47 -10
- package/runtime/arcane/components/file-drop.html +81 -35
- package/runtime/arcane/components/file-inspector.html +72 -22
- package/runtime/arcane/components/file-manager.html +374 -79
- package/runtime/arcane/components/integration-settings.html +12 -5
- package/runtime/arcane/components/local-ai-status.html +48 -19
- package/runtime/arcane/components/markdown-document.html +161 -68
- package/runtime/arcane/components/markdown-editor.html +110 -33
- package/runtime/arcane/components/media-embed.html +8 -5
- package/runtime/arcane/components/modal.html +15 -5
- package/runtime/arcane/components/output-panel.html +28 -23
- package/runtime/arcane/components/preferences-form.html +22 -4
- package/runtime/arcane/components/record-timeline.html +18 -2
- package/runtime/arcane/components/relationship-board.html +23 -3
- package/runtime/arcane/components/screen-capture.html +10 -4
- package/runtime/arcane/components/source-code-viewer.html +76 -9
- package/runtime/arcane/components/source-explanation.html +23 -3
- package/runtime/arcane/components/speech.html +462 -384
- package/runtime/arcane/components/summary-strip.html +22 -11
- package/runtime/arcane/components/table.html +39 -21
- package/runtime/arcane/components/task-progress.html +79 -21
- package/runtime/arcane/components/terminal-workspace.html +7 -4
- package/runtime/arcane/components/theme-editor.html +7 -3
- package/runtime/arcane/components/unified-inbox.html +9 -4
- package/runtime/arcane/components/voice-transcription.html +639 -98
- package/runtime/arcane/components/weather-widget.html +5 -3
- package/runtime/arcane/components/web-navigator.html +48 -8
- package/runtime/arcane/entities/Chat.js +1 -1
- package/runtime/arcane/entities/User.js +110 -23
- package/runtime/arcane/modules/AI.js +2109 -130
- package/runtime/arcane/modules/AIProviderRuntime.js +720 -13
- package/runtime/arcane/modules/AIRuntimeState.js +109 -52
- package/runtime/arcane/modules/ApiModelDatabase.js +390 -17
- package/runtime/arcane/modules/BrowserTestSuite.js +205 -28
- package/runtime/arcane/modules/CalculatorEngine.js +63 -3
- package/runtime/arcane/modules/CommunicationAppController.js +588 -28
- package/runtime/arcane/modules/CommunicationHub.js +590 -10
- package/runtime/arcane/modules/ComponentContracts.js +470 -0
- package/runtime/arcane/modules/ConversationTimebox.js +152 -33
- package/runtime/arcane/modules/DBLS.js +40 -7
- package/runtime/arcane/modules/DBOPFS.js +35 -11
- package/runtime/arcane/modules/DataMaintenance.js +12 -2
- package/runtime/arcane/modules/Errors.js +65 -7
- package/runtime/arcane/modules/HTMLImport.js +198 -14
- package/runtime/arcane/modules/LocalAIReadinessController.js +208 -29
- package/runtime/arcane/modules/Mail.js +738 -115
- package/runtime/arcane/modules/MailOutbox.mjs +1395 -0
- package/runtime/arcane/modules/MailTransport.mjs +197 -39
- package/runtime/arcane/modules/Ollama.js +36 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +583 -7
- package/runtime/arcane/modules/PreferenceStore.js +367 -33
- package/runtime/arcane/modules/RecordReviewStore.js +322 -23
- package/runtime/arcane/modules/ScreenCapture.js +1397 -15
- package/runtime/arcane/modules/SpeechPlayback.js +438 -41
- package/runtime/arcane/modules/TerminalClient.js +277 -12
- package/runtime/arcane/modules/ThemeBootstrap.js +80 -6
- package/runtime/arcane/modules/ThemeManager.js +39 -7
- package/runtime/arcane/modules/TimeGuard.js +131 -20
- package/runtime/arcane/modules/WaitForComponent.js +386 -33
- package/schemas/arcane-lock.schema.json +2 -2
- package/src/cli/main.mjs +435 -9
- package/src/event-manager.mjs +1097 -1
- package/src/import-map.mjs +21 -3
- package/src/index.mjs +13 -0
- package/src/installed-sdk-runtime.mjs +112 -0
- package/src/mail-api.mjs +22 -0
- package/src/mail-credentials.mjs +667 -0
- package/src/mail-server.mjs +1769 -0
- package/src/mail.mjs +261 -0
- package/src/sdk-browser-runtime.mjs +85 -41
- package/src/testing-loader.mjs +7 -0
- package/src/toolchain.mjs +3 -0
- package/src/workspace.mjs +1 -1
|
@@ -40,13 +40,17 @@
|
|
|
40
40
|
<script type="module">
|
|
41
41
|
const host=this;
|
|
42
42
|
const root=host.shadowRoot;
|
|
43
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
44
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.summary-strip',eventTypes:['summary-strip-change','summary-strip-select','summary-strip-ready']});
|
|
43
45
|
const region=root.querySelector('#region');
|
|
44
46
|
const list=root.querySelector('#items');
|
|
47
|
+
let destroyed=false;
|
|
45
48
|
let items=[];
|
|
46
49
|
let options={};
|
|
47
50
|
|
|
48
51
|
host.clear=clear;
|
|
49
52
|
host.configure=configure;
|
|
53
|
+
host.destroy=destroy;
|
|
50
54
|
host.setItems=setItems;
|
|
51
55
|
host.updateItem=updateItem;
|
|
52
56
|
|
|
@@ -57,6 +61,12 @@
|
|
|
57
61
|
|
|
58
62
|
list.addEventListener('click',selectItem);
|
|
59
63
|
|
|
64
|
+
function emit(type,detail={},publicDetail={}){
|
|
65
|
+
if(destroyed)return false;
|
|
66
|
+
const publication=events.dispatch(type,detail,{publicDetail});
|
|
67
|
+
return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
function datasetOptions(){
|
|
61
71
|
return {
|
|
62
72
|
ariaLabel:host.dataset.ariaLabel||'Summary',
|
|
@@ -74,11 +84,7 @@
|
|
|
74
84
|
function setItems(values=[]){
|
|
75
85
|
items=Array.from(values||[]).map((value,index)=>normalizeItem(value,index));
|
|
76
86
|
render();
|
|
77
|
-
|
|
78
|
-
bubbles:true,
|
|
79
|
-
composed:true,
|
|
80
|
-
detail:{items:getItems()}
|
|
81
|
-
}));
|
|
87
|
+
emit('summary-strip-change',{items:getItems()},{itemCount:items.length});
|
|
82
88
|
return getItems();
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -156,11 +162,7 @@
|
|
|
156
162
|
if(!target||!item||item.disabled){
|
|
157
163
|
return;
|
|
158
164
|
}
|
|
159
|
-
|
|
160
|
-
bubbles:true,
|
|
161
|
-
composed:true,
|
|
162
|
-
detail:{id:item.id,item:{...item}}
|
|
163
|
-
}));
|
|
165
|
+
emit('summary-strip-select',{id:item.id,item:{...item}},{id:item.id,status:item.status});
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
function getItems(){
|
|
@@ -171,7 +173,16 @@
|
|
|
171
173
|
return setItems([]);
|
|
172
174
|
}
|
|
173
175
|
|
|
176
|
+
function destroy(){
|
|
177
|
+
if(destroyed)return false;
|
|
178
|
+
destroyed=true;
|
|
179
|
+
host.ready=false;
|
|
180
|
+
list.removeEventListener('click',selectItem);
|
|
181
|
+
events.dispose();
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
|
|
174
185
|
configure(datasetOptions());
|
|
175
186
|
host.ready=true;
|
|
176
|
-
|
|
187
|
+
emit('summary-strip-ready',{}, {ready:true});
|
|
177
188
|
</script>
|
|
@@ -16,32 +16,39 @@
|
|
|
16
16
|
</tbody>
|
|
17
17
|
</table>
|
|
18
18
|
|
|
19
|
-
<script
|
|
19
|
+
<script type="module">
|
|
20
20
|
const host = this;
|
|
21
21
|
const shadowRoot=this.shadowRoot;
|
|
22
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=
|
|
23
|
+
await import('arcane-os/event-manager');
|
|
24
|
+
const events=createArcaneEventSource(host,{
|
|
25
|
+
source:'arcane.component.table',
|
|
26
|
+
eventTypes:['table-ready','header-update','body-update']
|
|
27
|
+
});
|
|
28
|
+
let destroyed=false;
|
|
29
|
+
let eventOperationSequence=0;
|
|
22
30
|
host.buildHeader=buildHeader;
|
|
23
31
|
host.buildTable=buildTable;
|
|
32
|
+
host.destroy=destroy;
|
|
24
33
|
host.ready=false;
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
detail: { }
|
|
41
|
-
}
|
|
42
|
-
);
|
|
35
|
+
function emit(type,detail={},publicDetail={}){
|
|
36
|
+
if(destroyed)return false;
|
|
37
|
+
const operationId=
|
|
38
|
+
`${events.instanceId}:${type}:${(++eventOperationSequence).toString(36)}`;
|
|
39
|
+
const publication=events.dispatch(
|
|
40
|
+
type,
|
|
41
|
+
detail,
|
|
42
|
+
{
|
|
43
|
+
operationId,
|
|
44
|
+
publicDetail:{...publicDetail,reason:type}
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
return projectArcaneDOMEvent(host,publication.occurrence);
|
|
48
|
+
}
|
|
43
49
|
|
|
44
50
|
async function buildHeader(headerArray=['','']){
|
|
51
|
+
if(destroyed)return false;
|
|
45
52
|
const tableHead = shadowRoot.querySelector('thead');
|
|
46
53
|
tableHead.innerHTML = '';
|
|
47
54
|
const th = tableHead.insertRow();
|
|
@@ -51,10 +58,12 @@
|
|
|
51
58
|
th.insertCell(-1).innerText=header;
|
|
52
59
|
}
|
|
53
60
|
);
|
|
54
|
-
|
|
61
|
+
emit('header-update',{}, {columnCount:headerArray.length});
|
|
62
|
+
return true;
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
async function buildTable(tableArray=[['', ''], ['','']]){
|
|
66
|
+
if(destroyed)return false;
|
|
58
67
|
const tableBody = shadowRoot.querySelector('tbody');
|
|
59
68
|
tableBody.innerHTML = '';
|
|
60
69
|
|
|
@@ -68,10 +77,19 @@
|
|
|
68
77
|
);
|
|
69
78
|
}
|
|
70
79
|
);
|
|
71
|
-
|
|
80
|
+
emit('body-update',{}, {rowCount:tableArray.length});
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function destroy(){
|
|
85
|
+
if(destroyed)return false;
|
|
86
|
+
destroyed=true;
|
|
87
|
+
host.ready=false;
|
|
88
|
+
events.dispose();
|
|
89
|
+
return true;
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
host.ready=true;
|
|
75
|
-
|
|
93
|
+
emit('table-ready',{}, {ready:true});
|
|
76
94
|
|
|
77
95
|
</script>
|
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
<script type="module">
|
|
48
48
|
const host=this;
|
|
49
49
|
const root=host.shadowRoot;
|
|
50
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
51
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.task-progress',eventTypes:['task-progress-started','task-progress-error','task-progress-complete','task-progress-change','task-progress-ready']});
|
|
50
52
|
const panel=root.querySelector('#panel');
|
|
51
53
|
const heading=root.querySelector('#taskProgressTitle');
|
|
52
54
|
const description=root.querySelector('#description');
|
|
@@ -58,12 +60,26 @@
|
|
|
58
60
|
|
|
59
61
|
const allowedStatuses=new Set(['pending','running','complete','failed','canceled']);
|
|
60
62
|
let activeRun=Promise.resolve([]);
|
|
63
|
+
let destroyed=false;
|
|
64
|
+
let eventOperationSequence=0;
|
|
61
65
|
let options={};
|
|
66
|
+
let runGeneration=0;
|
|
62
67
|
let running=false;
|
|
63
68
|
let tasks=[];
|
|
64
69
|
|
|
70
|
+
function emit(type,detail={},publicDetail={},operationId=null){
|
|
71
|
+
if(destroyed)return false;
|
|
72
|
+
const publication=events.dispatch(
|
|
73
|
+
type,
|
|
74
|
+
detail,
|
|
75
|
+
{publicDetail,operationId}
|
|
76
|
+
);
|
|
77
|
+
return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
host.clear=clear;
|
|
66
81
|
host.configure=configure;
|
|
82
|
+
host.destroy=destroy;
|
|
67
83
|
host.runTasks=runTasks;
|
|
68
84
|
host.setTasks=setTasks;
|
|
69
85
|
host.updateTask=updateTask;
|
|
@@ -92,6 +108,7 @@
|
|
|
92
108
|
}
|
|
93
109
|
|
|
94
110
|
function setTasks(values=[]){
|
|
111
|
+
if(destroyed)return [];
|
|
95
112
|
const ids=new Set();
|
|
96
113
|
tasks=Array.from(values||[]).map((value,index)=>{
|
|
97
114
|
const task=normalizeTask(value,index);
|
|
@@ -117,6 +134,7 @@
|
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
function updateTask(id,update={}){
|
|
137
|
+
if(destroyed)return null;
|
|
120
138
|
const index=typeof id==='number'?id:tasks.findIndex(task=>task.id===`${id}`);
|
|
121
139
|
if(index<0||index>=tasks.length){
|
|
122
140
|
return null;
|
|
@@ -181,6 +199,7 @@
|
|
|
181
199
|
}
|
|
182
200
|
|
|
183
201
|
async function runTasks(title='Progress',jobs=[]){
|
|
202
|
+
if(destroyed)return [];
|
|
184
203
|
if(running){
|
|
185
204
|
return activeRun;
|
|
186
205
|
}
|
|
@@ -197,36 +216,60 @@
|
|
|
197
216
|
status:'pending'
|
|
198
217
|
})));
|
|
199
218
|
running=true;
|
|
219
|
+
const generation=++runGeneration;
|
|
220
|
+
const operationId=
|
|
221
|
+
`${events.instanceId}:task-run:${(++eventOperationSequence).toString(36)}`;
|
|
200
222
|
syncOverall();
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
223
|
+
emit(
|
|
224
|
+
'task-progress-started',
|
|
225
|
+
getSnapshot(),
|
|
226
|
+
{
|
|
227
|
+
reason:'task-run-started',
|
|
228
|
+
taskCount:tasks.length,
|
|
229
|
+
running:true
|
|
230
|
+
},
|
|
231
|
+
operationId
|
|
232
|
+
);
|
|
206
233
|
activeRun=Promise.allSettled(runnable.map(async(job,index)=>{
|
|
207
234
|
updateTask(index,{status:'running'});
|
|
208
235
|
try{
|
|
209
236
|
const value=await job.task();
|
|
237
|
+
if(destroyed||generation!==runGeneration)return value;
|
|
210
238
|
updateTask(index,{status:'complete',message:job.completeMessage||''});
|
|
211
239
|
return value;
|
|
212
240
|
}catch(error){
|
|
241
|
+
if(destroyed||generation!==runGeneration)throw error;
|
|
213
242
|
updateTask(index,{status:'failed',message:job.errorMessage||error?.message||'Unable to complete.'});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
243
|
+
emit(
|
|
244
|
+
'task-progress-error',
|
|
245
|
+
{error,id:tasks[index]?.id,index,task:{...tasks[index]}},
|
|
246
|
+
{
|
|
247
|
+
code:typeof error?.code==='string'
|
|
248
|
+
?error.code
|
|
249
|
+
:'ARCANE_TASK_EXECUTION_REJECTED',
|
|
250
|
+
index,
|
|
251
|
+
reason:'task-execution-rejected'
|
|
252
|
+
},
|
|
253
|
+
operationId
|
|
254
|
+
);
|
|
219
255
|
throw error;
|
|
220
256
|
}
|
|
221
257
|
}));
|
|
222
258
|
const results=await activeRun;
|
|
223
259
|
running=false;
|
|
260
|
+
if(destroyed||generation!==runGeneration)return results;
|
|
224
261
|
syncOverall();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
262
|
+
emit(
|
|
263
|
+
'task-progress-complete',
|
|
264
|
+
{...getSnapshot(),results:results.slice()},
|
|
265
|
+
{
|
|
266
|
+
reason:'task-run-settled',
|
|
267
|
+
taskCount:tasks.length,
|
|
268
|
+
rejectedCount:results.filter(result=>result.status==='rejected').length,
|
|
269
|
+
running:false
|
|
270
|
+
},
|
|
271
|
+
operationId
|
|
272
|
+
);
|
|
230
273
|
return results;
|
|
231
274
|
}
|
|
232
275
|
|
|
@@ -258,14 +301,20 @@
|
|
|
258
301
|
}
|
|
259
302
|
|
|
260
303
|
function emitChange(task=null){
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
304
|
+
emit(
|
|
305
|
+
'task-progress-change',
|
|
306
|
+
{...getSnapshot(),task:task?{...task}:null},
|
|
307
|
+
{
|
|
308
|
+
taskCount:tasks.length,
|
|
309
|
+
running,
|
|
310
|
+
reason:'task-state-changed',
|
|
311
|
+
taskStatus:task?.status?`task-${task.status}`:null
|
|
312
|
+
}
|
|
313
|
+
);
|
|
266
314
|
}
|
|
267
315
|
|
|
268
316
|
function clear(){
|
|
317
|
+
if(destroyed)return false;
|
|
269
318
|
if(running){
|
|
270
319
|
return false;
|
|
271
320
|
}
|
|
@@ -275,8 +324,17 @@
|
|
|
275
324
|
return true;
|
|
276
325
|
}
|
|
277
326
|
|
|
327
|
+
function destroy(){
|
|
328
|
+
if(destroyed)return false;
|
|
329
|
+
destroyed=true;
|
|
330
|
+
runGeneration+=1;
|
|
331
|
+
host.ready=false;
|
|
332
|
+
events.dispose();
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
|
|
278
336
|
configure(datasetOptions());
|
|
279
337
|
render();
|
|
280
338
|
host.ready=true;
|
|
281
|
-
|
|
339
|
+
emit('task-progress-ready',{}, {ready:true,reason:'task-progress-ready'});
|
|
282
340
|
</script>
|
|
@@ -27,10 +27,12 @@
|
|
|
27
27
|
</section>
|
|
28
28
|
<script type="module">
|
|
29
29
|
const {parseAnsi,stripAnsi}=await import('../modules/AnsiText.js');
|
|
30
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
30
31
|
const host=this,root=host.shadowRoot;
|
|
31
32
|
const tabs=root.querySelector('#tabs'),output=root.querySelector('#output'),input=root.querySelector('#input'),prompt=root.querySelector('#prompt'),promptLabel=root.querySelector('#promptLabel'),connection=root.querySelector('#connection'),search=root.querySelector('#search');
|
|
32
|
-
const
|
|
33
|
-
|
|
33
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.terminal-workspace',eventTypes:['terminal-interrupt','terminal-settings','terminal-session-select','terminal-clear','terminal-submit','terminal-session-close','terminal-session-new','terminal-workspace-ready']});
|
|
34
|
+
const sessions=new Map();let activeId='',history=[],historyIndex=0,completions=[],destroyed=false,eventOperationSequence=0;
|
|
35
|
+
host.configure=configure;host.destroy=destroy;host.addSession=addSession;host.removeSession=removeSession;host.activateSession=activateSession;host.append=append;host.clear=clear;host.setState=setState;host.setTheme=setTheme;host.focus=()=>input.focus();host.ready=true;
|
|
34
36
|
prompt.addEventListener('submit',event=>{event.preventDefault();submit();});
|
|
35
37
|
input.addEventListener('keydown',event=>{
|
|
36
38
|
if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();submit();}
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
function renderText(row,text,term){const clean=stripAnsi(text);if(!term){for(const token of parseAnsi(text)){const span=document.createElement('span');span.textContent=token.text;const classes=[];if(token.style.bold)classes.push('ansi-bold');if(token.style.dim)classes.push('ansi-dim');if(token.style.italic)classes.push('ansi-italic');if(token.style.underline)classes.push('ansi-underline');if(token.style.foreground&&!token.style.foreground.startsWith('index-'))classes.push(`ansi-${token.style.foreground}`);span.className=classes.join(' ');row.append(span);}return;}let cursor=0,index=clean.toLowerCase().indexOf(term);while(index>=0){row.append(document.createTextNode(clean.slice(cursor,index)));const mark=document.createElement('mark');mark.textContent=clean.slice(index,index+term.length);row.append(mark);cursor=index+term.length;index=clean.toLowerCase().indexOf(term,cursor);}row.append(document.createTextNode(clean.slice(cursor)));}
|
|
61
63
|
function toggleSearch(force){search.hidden=force===undefined?!search.hidden:!force;if(!search.hidden)search.focus();else{search.value='';render();input.focus();}}
|
|
62
64
|
function resizeInput(){input.style.height='auto';input.style.height=`${Math.min(input.scrollHeight,160)}px`;}
|
|
63
|
-
function emit(type,detail={}){
|
|
64
|
-
host.
|
|
65
|
+
function emit(type,detail={}){if(destroyed)return false;const operationId=`${events.instanceId}:${type}:${(++eventOperationSequence).toString(36)}`;const publication=events.dispatch(type,detail,{operationId,publicDetail:{hasSession:Boolean(detail.sessionId),lineLength:typeof detail.line==='string'?detail.line.length:0,historyCount:Array.isArray(detail.history)?detail.history.length:0,reason:type}});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});}
|
|
66
|
+
function destroy(){if(destroyed)return false;destroyed=true;host.ready=false;for(const id of ['find','clear','interrupt','settings','copy'])root.querySelector(`#${id}`).onclick=null;events.dispose();return true;}
|
|
67
|
+
emit('terminal-workspace-ready');
|
|
65
68
|
</script>
|
|
@@ -21,8 +21,11 @@
|
|
|
21
21
|
const colors=root.querySelector('#colors');
|
|
22
22
|
const status=root.querySelector('#status');
|
|
23
23
|
const {default:Theme,themeColorToHex,themeTokens}=await import('../entities/Theme.js');
|
|
24
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
25
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.theme-editor',eventTypes:['theme-preview','theme-save','theme-reset','theme-editor-ready']});
|
|
26
|
+
let destroyed=false;
|
|
24
27
|
|
|
25
|
-
host.configure=configure;host.getTheme=getTheme;host.setTheme=setTheme;host.setBusy=setBusy;host.setStatus=setStatus;
|
|
28
|
+
host.configure=configure;host.destroy=destroy;host.getTheme=getTheme;host.setTheme=setTheme;host.setBusy=setBusy;host.setStatus=setStatus;
|
|
26
29
|
colors.replaceChildren(...themeTokens.map(token=>{
|
|
27
30
|
const field=document.createElement('div'),input=document.createElement('input'),label=document.createElement('label');
|
|
28
31
|
field.className='color-field';input.type='color';input.id=`theme-${token.key}`;input.name=token.key;input.value=themeColorToHex(token.defaultValue);label.htmlFor=input.id;label.textContent=token.label;field.append(input,label);return field;
|
|
@@ -31,11 +34,12 @@
|
|
|
31
34
|
form.addEventListener('submit',event=>{event.preventDefault();emit('theme-save',{theme:getTheme()});});
|
|
32
35
|
root.querySelector('#reset').addEventListener('click',()=>emit('theme-reset'));
|
|
33
36
|
|
|
34
|
-
function emit(name,detail={}){
|
|
37
|
+
function emit(name,detail={}){if(destroyed)return false;const theme=detail.theme;const publication=events.dispatch(name,detail,{publicDetail:theme?{scheme:String(theme.scheme||''),tokenCount:Object.keys(theme.tokens||{}).length}:{}});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});}
|
|
35
38
|
function getTheme(){return new Theme({name:form.elements.name.value,scheme:form.elements.scheme.value,tokens:Object.fromEntries(themeTokens.map(token=>[token.key,form.elements[token.key].value]))});}
|
|
36
39
|
function setTheme(input={}){const theme=Theme.fromJSON(input);form.elements.name.value=theme.name;form.elements.scheme.value=theme.scheme;for(const token of themeTokens) form.elements[token.key].value=themeColorToHex(theme.tokens[token.key]);return theme;}
|
|
37
40
|
function configure(options={}){return setTheme(options.theme||{name:'My Arcane skin'});}
|
|
38
41
|
function setBusy(value=true){for(const control of form.elements) control.disabled=Boolean(value);form.setAttribute('aria-busy',String(Boolean(value)));}
|
|
39
42
|
function setStatus(value=''){status.textContent=String(value||'');return status.textContent;}
|
|
40
|
-
|
|
43
|
+
function destroy(){if(destroyed)return false;destroyed=true;host.ready=false;events.dispose();return true;}
|
|
44
|
+
configure();host.ready=true;const readyPublication=events.dispatch('theme-editor-ready',{}, {publicDetail:{ready:true}});projectArcaneDOMEvent(host,readyPublication.occurrence,{bubbles:true,composed:true});
|
|
41
45
|
</script>
|
|
@@ -8,13 +8,18 @@
|
|
|
8
8
|
<div id="empty" class="empty"><strong>No conversations yet</strong><p>Connect a service in settings to bring conversations into this inbox.</p></div>
|
|
9
9
|
</section>
|
|
10
10
|
<script type="module">
|
|
11
|
-
const host=this,root=host.shadowRoot,list=root.querySelector('#list'),empty=root.querySelector('#empty'),search=root.querySelector('#search'),filters=root.querySelector('#filters');
|
|
11
|
+
const host=this,root=host.shadowRoot,list=root.querySelector('#list'),empty=root.querySelector('#empty'),search=root.querySelector('#search'),filters=root.querySelector('#filters');
|
|
12
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
13
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.unified-inbox',eventTypes:['inbox-refresh','thread-select','unified-inbox-ready']});
|
|
14
|
+
let threads=[],activeId='',channel='all',providers={},destroyed=false;
|
|
15
|
+
function emit(type,detail={},publicDetail={}){if(destroyed)return false;const publication=events.dispatch(type,detail,{publicDetail});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true})}
|
|
16
|
+
host.destroy=()=>{if(destroyed)return false;destroyed=true;host.ready=false;events.dispose();return true};
|
|
12
17
|
host.configure=options=>{providers=Object.fromEntries(Array.from(options?.providers||[],item=>[item.id,item]));renderFilters(options?.channels);return host.setThreads(options?.threads||[])};
|
|
13
18
|
host.setThreads=values=>{threads=Array.from(values||[]);render();return threads};host.setActive=id=>{activeId=String(id||'');render();};host.setLoading=value=>{root.querySelector('#refresh').disabled=Boolean(value)};
|
|
14
|
-
root.querySelector('#refresh').addEventListener('click',()=>
|
|
19
|
+
root.querySelector('#refresh').addEventListener('click',()=>emit('inbox-refresh'));
|
|
15
20
|
search.addEventListener('input',render);
|
|
16
21
|
function renderFilters(values){const names=['all',...new Set(values||[])];filters.replaceChildren(...names.map(name=>{const button=document.createElement('button');button.type='button';button.className='arcane-button arcane-button--tertiary';button.textContent=name==='all'?'All':name.toUpperCase();button.setAttribute('aria-pressed',String(channel===name));button.addEventListener('click',()=>{channel=name;renderFilters(values);render()});return button}))}
|
|
17
22
|
function render(){const term=search.value.trim().toLowerCase();const visible=threads.filter(item=>(channel==='all'||item.channel===channel)&&(!term||`${item.title} ${item.preview} ${(item.participants||[]).join(' ')}`.toLowerCase().includes(term)));empty.hidden=visible.length>0;list.replaceChildren(...visible.map(makeThread));}
|
|
18
|
-
function makeThread(item){const button=document.createElement('button');button.type='button';button.className='thread';button.setAttribute('aria-current',String(item.id===activeId));const top=document.createElement('span'),title=document.createElement('span'),time=document.createElement('time'),preview=document.createElement('span'),meta=document.createElement('span'),badge=document.createElement('span'),provider=document.createElement('span');top.className='line';title.className='title';title.textContent=item.title;time.dateTime=item.updatedAt;time.textContent=new Intl.DateTimeFormat(undefined,{month:'short',day:'numeric'}).format(new Date(item.updatedAt));preview.className='preview';preview.textContent=item.preview||'No preview';meta.className='meta';badge.className='badge';badge.textContent=item.channel;provider.textContent=providers[item.providerId]?.label||item.providerId;top.append(title,time);meta.append(badge,provider);if(item.unreadCount){const unread=document.createElement('span');unread.className='unread';unread.textContent=String(item.unreadCount);meta.append(unread)}button.append(top,preview,meta);button.addEventListener('click',()=>
|
|
19
|
-
host.ready=true;
|
|
23
|
+
function makeThread(item){const button=document.createElement('button');button.type='button';button.className='thread';button.setAttribute('aria-current',String(item.id===activeId));const top=document.createElement('span'),title=document.createElement('span'),time=document.createElement('time'),preview=document.createElement('span'),meta=document.createElement('span'),badge=document.createElement('span'),provider=document.createElement('span');top.className='line';title.className='title';title.textContent=item.title;time.dateTime=item.updatedAt;time.textContent=new Intl.DateTimeFormat(undefined,{month:'short',day:'numeric'}).format(new Date(item.updatedAt));preview.className='preview';preview.textContent=item.preview||'No preview';meta.className='meta';badge.className='badge';badge.textContent=item.channel;provider.textContent=providers[item.providerId]?.label||item.providerId;top.append(title,time);meta.append(badge,provider);if(item.unreadCount){const unread=document.createElement('span');unread.className='unread';unread.textContent=String(item.unreadCount);meta.append(unread)}button.append(top,preview,meta);button.addEventListener('click',()=>emit('thread-select',{thread:item},{threadId:String(item.id||''),channel:String(item.channel||'')}));return button;}
|
|
24
|
+
host.ready=true;emit('unified-inbox-ready',{}, {ready:true});
|
|
20
25
|
</script>
|