arcane-os 0.3.5 → 0.4.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 +33 -0
- package/README.md +7 -7
- package/package.json +1 -1
- package/runtime/arcane/components/chat.html +16 -19
- package/runtime/arcane/components/directory-picker.html +2 -2
- package/runtime/arcane/components/file-drop.html +1 -12
- package/runtime/arcane/components/record-timeline.html +13 -11
- package/runtime/arcane/components/relationship-board.html +6 -6
- package/runtime/arcane/components/source-code-viewer.html +23 -27
- package/runtime/arcane/modules/AIProviderRuntime.js +11 -16
- package/runtime/arcane/modules/ComponentContracts.js +3 -16
- package/runtime/arcane/modules/DevelopmentWorkspace.js +6 -10
- package/runtime/arcane/modules/MessageAdvisory.js +16 -14
- package/runtime/arcane/modules/RecordPassageIndex.js +12 -26
- package/runtime/arcane/modules/RecordReviewStore.js +16 -3
- package/runtime/arcane/modules/ScamRiskPolicy.js +8 -7
- package/src/import-map.mjs +1 -7
- package/runtime/arcane/entities/TWiNPolicyDecision.js +0 -995
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +0 -130
- package/runtime/arcane/modules/RevocableProjectionLedger.js +0 -1623
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
- Preserved complete finite provider progress values and units as
|
|
6
|
+
informational state, including fractional and out-of-range observations,
|
|
7
|
+
while keeping the visual percentage bounded and exposing ARIA range values
|
|
8
|
+
only when the reported range is valid.
|
|
9
|
+
- Preserved complete file selections, timelines, relationship graphs, source
|
|
10
|
+
content, message advisories, record passages, and date findings without
|
|
11
|
+
arbitrary count or character clipping, and surfaced malformed stored-review
|
|
12
|
+
data instead of silently replacing it.
|
|
13
|
+
- Made workspace and scam-policy hardening explicitly opt in, with ordinary
|
|
14
|
+
complete workspace inputs and `secure:false` scam analysis remaining fully
|
|
15
|
+
functional without restrictive policy admission or frozen results.
|
|
16
|
+
- Removed the product-owned `CaseEvidenceIndexer.js` module and
|
|
17
|
+
`TWiNPolicyDecision.js` entity from the shared runtime payload and generated
|
|
18
|
+
browser import map so application policy remains owned by each consumer.
|
|
19
|
+
|
|
20
|
+
- Removed the unused `RevocableProjectionLedger.js` runtime artifact and its
|
|
21
|
+
public contract. No authored SDK or Arcane OS application source consumes it,
|
|
22
|
+
and its mandatory capacity, character, UTF-8 byte, and node budgets,
|
|
23
|
+
fingerprinting, freezing, and pristine-descriptor admission conflict with the
|
|
24
|
+
ordinary functional baseline.
|
|
25
|
+
|
|
26
|
+
## 0.3.6
|
|
27
|
+
|
|
28
|
+
- Replaced coherent selected-but-unregistered STT and TTS placeholders during
|
|
29
|
+
initial explicit browser-speech configuration while preserving rejection of
|
|
30
|
+
registered, busy, local-only, or internally divergent selections and keeping
|
|
31
|
+
the new providers unloaded until the application activates them.
|
|
32
|
+
- Preserved complete finite provider progress values and units as
|
|
33
|
+
informational, non-gating state in the reusable formatter and shared Chat
|
|
34
|
+
activation interface.
|
|
35
|
+
|
|
3
36
|
## 0.3.5
|
|
4
37
|
|
|
5
38
|
- Preserved complete AI and chat runtime content across multi-choice streaming,
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
|
|
|
19
19
|
`arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
|
|
20
20
|
event, cancellation, and browser run contracts.
|
|
21
21
|
|
|
22
|
-
This checkout defines the `0.
|
|
22
|
+
This checkout defines the `0.4.0` SDK contract. Applications pin one exact npm
|
|
23
23
|
version and lockfile; registry state is deliberately not baked into application
|
|
24
24
|
artifacts.
|
|
25
25
|
|
|
@@ -126,7 +126,7 @@ uses the same controller for automatic memory extraction.
|
|
|
126
126
|
Create a new repository-shaped Arcane application with the exact stable SDK:
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
|
-
npx arcane-os@0.
|
|
129
|
+
npx arcane-os@0.4.0 new my-app --path ./my-app --target portable --git
|
|
130
130
|
cd my-app
|
|
131
131
|
npm install
|
|
132
132
|
npm run check
|
|
@@ -137,7 +137,7 @@ To enroll an existing repository, install the exact SDK and initialize only
|
|
|
137
137
|
missing Arcane files:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
npm install --save-dev --save-exact arcane-os@0.
|
|
140
|
+
npm install --save-dev --save-exact arcane-os@0.4.0
|
|
141
141
|
npm exec -- arcane init my-app --target portable
|
|
142
142
|
```
|
|
143
143
|
|
|
@@ -153,7 +153,7 @@ npm exec -- arcane-os targets
|
|
|
153
153
|
No global SDK install or standalone Arcane CLI is required. The application
|
|
154
154
|
repository's exact npm dependency and lockfile own the CLI and toolchain version.
|
|
155
155
|
|
|
156
|
-
Use `npx arcane-os@0.
|
|
156
|
+
Use `npx arcane-os@0.4.0` for the initial bootstrap because it names this npm
|
|
157
157
|
package explicitly; bare `npx arcane` outside an installed project could resolve
|
|
158
158
|
a different package. Both installed commands invoke the same headless toolchain.
|
|
159
159
|
Project-local npm scripts use the SDK pinned by that app's `package-lock.json`,
|
|
@@ -174,7 +174,7 @@ node ./bin/arcane.mjs new local-app --path ../local-app --target portable --git
|
|
|
174
174
|
|
|
175
175
|
# From the generated app repository
|
|
176
176
|
cd ../local-app
|
|
177
|
-
npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.
|
|
177
|
+
npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.4.0.tgz
|
|
178
178
|
npm run check
|
|
179
179
|
npm ci
|
|
180
180
|
```
|
|
@@ -184,7 +184,7 @@ same location. The lockfile retains the selected package dependency while
|
|
|
184
184
|
Arcane uses the installed package name and version. Local directory `file:` dependencies are not
|
|
185
185
|
accepted because npm may install them as links; use a packed `.tgz`. A GitHub
|
|
186
186
|
runner also needs that tarball at the locked path. After publication, replace
|
|
187
|
-
the local declaration with the exact `arcane-os@0.
|
|
187
|
+
the local declaration with the exact `arcane-os@0.4.0` registry package and
|
|
188
188
|
commit the regenerated lock.
|
|
189
189
|
|
|
190
190
|
Generated repositories use `npm ci --ignore-scripts` in CI. Run dependency
|
|
@@ -322,7 +322,7 @@ package installation, or assertions.
|
|
|
322
322
|
|
|
323
323
|
## Current target support
|
|
324
324
|
|
|
325
|
-
Version `0.
|
|
325
|
+
Version `0.4.0` exposes one browser target and five explicitly paired
|
|
326
326
|
native development targets: a non-runnable portable directory, a
|
|
327
327
|
Windows x64 unsigned-local-test EXE bundle, Linux x64 and Linux ARM64
|
|
328
328
|
unsigned-local-test DEBs, and an Android development-signed APK. The
|
package/package.json
CHANGED
|
@@ -1877,13 +1877,13 @@
|
|
|
1877
1877
|
){
|
|
1878
1878
|
const messageId=String(id);
|
|
1879
1879
|
const normalizedTotal=Number.isFinite(Number(total))
|
|
1880
|
-
?
|
|
1880
|
+
?Number(total)
|
|
1881
1881
|
:0;
|
|
1882
1882
|
const normalizedCurrent=Number.isFinite(Number(current))
|
|
1883
|
-
?
|
|
1883
|
+
?Number(current)
|
|
1884
1884
|
:0;
|
|
1885
1885
|
const normalizedFailed=Number.isFinite(Number(failed))
|
|
1886
|
-
?
|
|
1886
|
+
?Number(failed)
|
|
1887
1887
|
:0;
|
|
1888
1888
|
const message=messageId
|
|
1889
1889
|
?[...chatOutput.children].find(
|
|
@@ -1936,7 +1936,7 @@
|
|
|
1936
1936
|
?`${visibleStatus}${warningLabel}`
|
|
1937
1937
|
:`${normalizedCurrent} of ${normalizedTotal}${warningLabel}`;
|
|
1938
1938
|
const percent=normalizedTotal>0
|
|
1939
|
-
?normalizedCurrent/normalizedTotal*100
|
|
1939
|
+
?Math.min(100,Math.max(0,normalizedCurrent/normalizedTotal*100))
|
|
1940
1940
|
:0;
|
|
1941
1941
|
|
|
1942
1942
|
labelElement.textContent=visibleLabel;
|
|
@@ -1949,10 +1949,18 @@
|
|
|
1949
1949
|
progress.removeAttribute('aria-valuemin');
|
|
1950
1950
|
progress.removeAttribute('aria-valuemax');
|
|
1951
1951
|
progress.removeAttribute('aria-valuenow');
|
|
1952
|
-
}else
|
|
1952
|
+
}else if(
|
|
1953
|
+
normalizedTotal>0
|
|
1954
|
+
&&normalizedCurrent>=0
|
|
1955
|
+
&&normalizedCurrent<=normalizedTotal
|
|
1956
|
+
){
|
|
1953
1957
|
progress.setAttribute('aria-valuemin','0');
|
|
1954
1958
|
progress.setAttribute('aria-valuemax',String(normalizedTotal));
|
|
1955
1959
|
progress.setAttribute('aria-valuenow',String(normalizedCurrent));
|
|
1960
|
+
}else{
|
|
1961
|
+
progress.removeAttribute('aria-valuemin');
|
|
1962
|
+
progress.removeAttribute('aria-valuemax');
|
|
1963
|
+
progress.removeAttribute('aria-valuenow');
|
|
1956
1964
|
}
|
|
1957
1965
|
progress.setAttribute(
|
|
1958
1966
|
'aria-valuetext',
|
|
@@ -2044,16 +2052,6 @@
|
|
|
2044
2052
|
return configured||role?.modelId||'the selected language model';
|
|
2045
2053
|
}
|
|
2046
2054
|
|
|
2047
|
-
function byteProgressUnit(value){
|
|
2048
|
-
const unit=String(value??'')
|
|
2049
|
-
.trim()
|
|
2050
|
-
.toLowerCase()
|
|
2051
|
-
.replace(/[\s_-]+/g,'');
|
|
2052
|
-
return unit.includes('byte')
|
|
2053
|
-
||unit.includes('octet')
|
|
2054
|
-
||/^(?:[kmgtpe]?i?b)(?:(?:\/|per)?(?:s|sec|second))?$/u.test(unit);
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
2055
|
function determinateProgress(){
|
|
2058
2056
|
const total=Number(role?.progress?.total);
|
|
2059
2057
|
const completed=Number(role?.progress?.completed);
|
|
@@ -2061,15 +2059,14 @@
|
|
|
2061
2059
|
?role.progress.unit
|
|
2062
2060
|
:'items';
|
|
2063
2061
|
if(
|
|
2064
|
-
|
|
2065
|
-
||!Number.isFinite(total)
|
|
2062
|
+
!Number.isFinite(total)
|
|
2066
2063
|
||total<=0
|
|
2067
2064
|
||!Number.isFinite(completed)
|
|
2068
2065
|
){
|
|
2069
2066
|
return null;
|
|
2070
2067
|
}
|
|
2071
2068
|
return {
|
|
2072
|
-
completed
|
|
2069
|
+
completed,
|
|
2073
2070
|
total,
|
|
2074
2071
|
unit
|
|
2075
2072
|
};
|
|
@@ -2106,7 +2103,7 @@
|
|
|
2106
2103
|
return;
|
|
2107
2104
|
}
|
|
2108
2105
|
progress.max=measured.total;
|
|
2109
|
-
progress.value=
|
|
2106
|
+
progress.value=measured.completed;
|
|
2110
2107
|
}
|
|
2111
2108
|
|
|
2112
2109
|
function render(){
|
|
@@ -166,8 +166,8 @@
|
|
|
166
166
|
|
|
167
167
|
function normalizeValue(value=''){
|
|
168
168
|
const next=`${value??''}`.trim();
|
|
169
|
-
if(
|
|
170
|
-
throw new TypeError('The directory path must be
|
|
169
|
+
if(/[\u0000-\u001f\u007f]/.test(next)){
|
|
170
|
+
throw new TypeError('The directory path must be plain text.');
|
|
171
171
|
}
|
|
172
172
|
return next;
|
|
173
173
|
}
|
|
@@ -188,18 +188,7 @@
|
|
|
188
188
|
if(!files.length){
|
|
189
189
|
return false;
|
|
190
190
|
}
|
|
191
|
-
|
|
192
|
-
setError(
|
|
193
|
-
`Select no more than ${options.maxFiles} file${options.maxFiles===1?'':'s'}.`,
|
|
194
|
-
{
|
|
195
|
-
code:'ARCANE_FILE_DROP_FILE_COUNT_LIMIT_EXCEEDED',
|
|
196
|
-
reason:'file-count-limit-exceeded'
|
|
197
|
-
},
|
|
198
|
-
operationId
|
|
199
|
-
);
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
currentFiles=options.multiple?files:files.slice(0,1);
|
|
191
|
+
currentFiles=files;
|
|
203
192
|
setError('');
|
|
204
193
|
feedback.hidden=false;
|
|
205
194
|
statusElement.className='status';
|
|
@@ -50,27 +50,29 @@
|
|
|
50
50
|
|
|
51
51
|
function normalizeItem(item,index){
|
|
52
52
|
const source=item&&typeof item==='object'?item:{};
|
|
53
|
-
const date=String(source.date||source.isoDate||'')
|
|
53
|
+
const date=String(source.date||source.isoDate||'');
|
|
54
54
|
if(!source.id||!date) return null;
|
|
55
55
|
return {
|
|
56
56
|
...source,
|
|
57
|
-
id:String(source.id)
|
|
57
|
+
id:String(source.id),
|
|
58
58
|
date,
|
|
59
|
-
title:String(source.title||'Dated event')
|
|
60
|
-
summary:String(source.summary||'')
|
|
61
|
-
category:String(source.category||source.kind||'Event')
|
|
62
|
-
actor:String(source.actor||'Actor not assigned')
|
|
63
|
-
sourceLabel:String(source.sourceLabel||'')
|
|
64
|
-
status:String(source.status||'')
|
|
65
|
-
factualPosture:String(source.factualPosture||'')
|
|
66
|
-
sourceCount:
|
|
59
|
+
title:String(source.title||'Dated event'),
|
|
60
|
+
summary:String(source.summary||''),
|
|
61
|
+
category:String(source.category||source.kind||'Event'),
|
|
62
|
+
actor:String(source.actor||'Actor not assigned'),
|
|
63
|
+
sourceLabel:String(source.sourceLabel||''),
|
|
64
|
+
status:String(source.status||''),
|
|
65
|
+
factualPosture:String(source.factualPosture||''),
|
|
66
|
+
sourceCount:Number.isFinite(Number(source.sourceCount))&&Number(source.sourceCount)>=0
|
|
67
|
+
?Number(source.sourceCount)
|
|
68
|
+
:0,
|
|
67
69
|
order:index
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
function setItems(value=[],input={}){
|
|
72
74
|
options={...options,...(input&&typeof input==='object'?input:{})};
|
|
73
|
-
items=(Array.isArray(value)?value:[]).
|
|
75
|
+
items=(Array.isArray(value)?value:[]).map(normalizeItem).filter(Boolean)
|
|
74
76
|
.sort((left,right)=>left.date.localeCompare(right.date)||left.order-right.order);
|
|
75
77
|
render();
|
|
76
78
|
return items.map(item=>({...item}));
|
|
@@ -66,21 +66,21 @@
|
|
|
66
66
|
function normalizeNode(value,index){
|
|
67
67
|
const item=value&&typeof value==='object'?value:{};
|
|
68
68
|
if(!item.id) return null;
|
|
69
|
-
return {...item,id:String(item.id)
|
|
69
|
+
return {...item,id:String(item.id),label:String(item.label||item.title||item.id),summary:String(item.summary||''),lane:String(item.lane||item.kind||'Other'),order:Number.isFinite(Number(item.order))?Number(item.order):index};
|
|
70
70
|
}
|
|
71
71
|
function normalizeEdge(value,index,known){
|
|
72
72
|
const item=value&&typeof value==='object'?value:{};
|
|
73
|
-
const from=String(item.from||'')
|
|
73
|
+
const from=String(item.from||''); const to=String(item.to||'');
|
|
74
74
|
if(!from||!to||!known.has(from)||!known.has(to)) return null;
|
|
75
|
-
return {...item,id:String(item.id||`edge-${index+1}`)
|
|
75
|
+
return {...item,id:String(item.id||`edge-${index+1}`),from,to,label:String(item.label||'related to'),summary:String(item.summary||'')};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function setGraph(graph={},options={}){
|
|
79
|
-
nodes=(Array.isArray(graph.nodes)?graph.nodes:[]).
|
|
79
|
+
nodes=(Array.isArray(graph.nodes)?graph.nodes:[]).map(normalizeNode).filter(Boolean);
|
|
80
80
|
const known=new Set(nodes.map(item=>item.id));
|
|
81
|
-
edges=(Array.isArray(graph.edges)?graph.edges:[]).
|
|
81
|
+
edges=(Array.isArray(graph.edges)?graph.edges:[]).map((item,index)=>normalizeEdge(item,index,known)).filter(Boolean);
|
|
82
82
|
const supplied=Array.isArray(options.lanes)?options.lanes:Array.isArray(graph.lanes)?graph.lanes:[];
|
|
83
|
-
lanes=[...new Set([...supplied.map(String),...nodes.map(item=>item.lane)])]
|
|
83
|
+
lanes=[...new Set([...supplied.map(String),...nodes.map(item=>item.lane)])];
|
|
84
84
|
board.style.setProperty('--lane-count',String(Math.max(1,Math.min(6,lanes.length))));
|
|
85
85
|
if(selectedId&&!known.has(selectedId)) selectedId='';
|
|
86
86
|
render();
|
|
@@ -202,26 +202,24 @@
|
|
|
202
202
|
const sourceScroll=host.shadowRoot.querySelector('#sourceScroll');
|
|
203
203
|
const sourceLines=host.shadowRoot.querySelector('#sourceLines');
|
|
204
204
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
const defaultOptions=Object.freeze({
|
|
208
|
-
labels:Object.freeze({
|
|
205
|
+
const defaultOptions={
|
|
206
|
+
labels:{
|
|
209
207
|
content:'Source code',
|
|
210
208
|
empty:'Choose a source file from the catalog.',
|
|
211
209
|
error:'This source file could not be displayed.',
|
|
212
|
-
loading:'Loading
|
|
210
|
+
loading:'Loading source code…',
|
|
213
211
|
repository:'View repository source'
|
|
214
|
-
}
|
|
215
|
-
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
216
214
|
|
|
217
|
-
let current=
|
|
215
|
+
let current={
|
|
218
216
|
language:'text',
|
|
219
217
|
lineCount:0,
|
|
220
218
|
repositoryURL:'',
|
|
221
219
|
sourcePath:'',
|
|
222
220
|
text:'',
|
|
223
221
|
title:''
|
|
224
|
-
}
|
|
222
|
+
};
|
|
225
223
|
let destroyed=false;
|
|
226
224
|
let eventOperationSequence=0;
|
|
227
225
|
let loadSequence=0;
|
|
@@ -244,17 +242,17 @@
|
|
|
244
242
|
value:{get:()=>current.text,set:value=>render(value)}
|
|
245
243
|
});
|
|
246
244
|
|
|
247
|
-
function
|
|
245
|
+
function normalizedText(value,label,{optional=false}={}){
|
|
248
246
|
if(optional&&(value===undefined||value===null||value===''))return '';
|
|
249
|
-
if(typeof value!=='string'||!value.trim()
|
|
250
|
-
throw new TypeError(`${label} must be
|
|
247
|
+
if(typeof value!=='string'||!value.trim()||/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/.test(value)){
|
|
248
|
+
throw new TypeError(`${label} must be text.`);
|
|
251
249
|
}
|
|
252
250
|
return value.trim();
|
|
253
251
|
}
|
|
254
252
|
|
|
255
253
|
function safeRepositoryURL(value=''){
|
|
256
254
|
if(value===undefined||value===null||value==='')return '';
|
|
257
|
-
const input=
|
|
255
|
+
const input=normalizedText(value,'Source repositoryURL');
|
|
258
256
|
try{
|
|
259
257
|
const url=new URL(input,document.baseURI);
|
|
260
258
|
if(!['http:','https:'].includes(url.protocol)||url.username||url.password){
|
|
@@ -278,22 +276,22 @@
|
|
|
278
276
|
const labels={...previous.labels};
|
|
279
277
|
for(const name of ['content','empty','error','loading','repository']){
|
|
280
278
|
if(labelInput[name]!==undefined){
|
|
281
|
-
labels[name]=
|
|
279
|
+
labels[name]=normalizedText(labelInput[name],`Source viewer labels.${name}`);
|
|
282
280
|
}
|
|
283
281
|
}
|
|
284
|
-
return
|
|
282
|
+
return {labels};
|
|
285
283
|
}
|
|
286
284
|
|
|
287
285
|
function normalizeRenderOptions(input={}){
|
|
288
286
|
if(!input||typeof input!=='object'||Array.isArray(input)){
|
|
289
287
|
throw new TypeError('Source render options must be an object.');
|
|
290
288
|
}
|
|
291
|
-
return
|
|
292
|
-
language:
|
|
289
|
+
return {
|
|
290
|
+
language:normalizedText(input.language||'text','Source language').toLowerCase(),
|
|
293
291
|
repositoryURL:safeRepositoryURL(input.repositoryURL),
|
|
294
|
-
sourcePath:
|
|
295
|
-
title:
|
|
296
|
-
}
|
|
292
|
+
sourcePath:normalizedText(input.sourcePath||'Source file','Source path'),
|
|
293
|
+
title:normalizedText(input.title||input.sourcePath||'Source file','Source title')
|
|
294
|
+
};
|
|
297
295
|
}
|
|
298
296
|
|
|
299
297
|
function configure(input={}){
|
|
@@ -337,14 +335,12 @@
|
|
|
337
335
|
|
|
338
336
|
function renderSource(text='',renderOptions={}){
|
|
339
337
|
if(typeof text!=='string')throw new TypeError('Source content must be a string.');
|
|
340
|
-
if(text.length>MAXIMUM_CHARACTERS)throw new RangeError('Source content exceeds the viewer character limit.');
|
|
341
338
|
const metadata=normalizeRenderOptions(renderOptions);
|
|
342
339
|
const lines=text.replace(/\r\n?/g,'\n').split('\n');
|
|
343
|
-
if(lines.length>MAXIMUM_LINES)throw new RangeError('Source content exceeds the viewer line limit.');
|
|
344
340
|
|
|
345
341
|
sourceLines.replaceChildren();
|
|
346
342
|
if(!text){
|
|
347
|
-
current=
|
|
343
|
+
current={...metadata,lineCount:0,text:''};
|
|
348
344
|
transition('empty');
|
|
349
345
|
return true;
|
|
350
346
|
}
|
|
@@ -363,7 +359,7 @@
|
|
|
363
359
|
fragment.append(item);
|
|
364
360
|
});
|
|
365
361
|
sourceLines.replaceChildren(fragment);
|
|
366
|
-
current=
|
|
362
|
+
current={...metadata,lineCount:lines.length,text};
|
|
367
363
|
transition('ready');
|
|
368
364
|
return true;
|
|
369
365
|
}
|
|
@@ -371,14 +367,14 @@
|
|
|
371
367
|
function clear(){
|
|
372
368
|
++loadSequence;
|
|
373
369
|
sourceLines.replaceChildren();
|
|
374
|
-
current=
|
|
370
|
+
current={
|
|
375
371
|
language:'text',
|
|
376
372
|
lineCount:0,
|
|
377
373
|
repositoryURL:'',
|
|
378
374
|
sourcePath:'',
|
|
379
375
|
text:'',
|
|
380
376
|
title:''
|
|
381
|
-
}
|
|
377
|
+
};
|
|
382
378
|
transition('empty');
|
|
383
379
|
return true;
|
|
384
380
|
}
|
|
@@ -423,7 +419,7 @@
|
|
|
423
419
|
sourcePath:current.sourcePath,
|
|
424
420
|
state
|
|
425
421
|
};
|
|
426
|
-
if(error)detail.message=String(error?.message||'Source rendering failed.')
|
|
422
|
+
if(error)detail.message=String(error?.message||'Source rendering failed.');
|
|
427
423
|
const reason={
|
|
428
424
|
empty:'source-code-viewer-cleared',
|
|
429
425
|
error:'source-code-viewer-render-rejected',
|
|
@@ -2031,15 +2031,12 @@ export class AIProviderRuntime {
|
|
|
2031
2031
|
}
|
|
2032
2032
|
}
|
|
2033
2033
|
|
|
2034
|
-
#pendingSpeechProviderHydrationMatches(role, slot
|
|
2035
|
-
if (!
|
|
2034
|
+
#pendingSpeechProviderHydrationMatches(role, slot) {
|
|
2035
|
+
if (!slot.selection) {
|
|
2036
2036
|
return false;
|
|
2037
2037
|
}
|
|
2038
2038
|
const pending = slot.selection;
|
|
2039
|
-
if (this.#providers.has(providerKey(role, pending.providerId))
|
|
2040
|
-
|| provider.id !== pending.providerId
|
|
2041
|
-
|| routes.default.providerId !== pending.providerId
|
|
2042
|
-
|| routes.default.modelId !== pending.modelId) {
|
|
2039
|
+
if (this.#providers.has(providerKey(role, pending.providerId))) {
|
|
2043
2040
|
return false;
|
|
2044
2041
|
}
|
|
2045
2042
|
const currentSelections = [
|
|
@@ -2048,10 +2045,12 @@ export class AIProviderRuntime {
|
|
|
2048
2045
|
slot.routes.localOnly
|
|
2049
2046
|
].filter(Boolean);
|
|
2050
2047
|
return currentSelections.length > 0
|
|
2051
|
-
&& currentSelections.every(
|
|
2052
|
-
selection
|
|
2053
|
-
|
|
2054
|
-
|
|
2048
|
+
&& currentSelections.every(
|
|
2049
|
+
function isSamePendingSpeechSelection(selection) {
|
|
2050
|
+
return selection.providerId === pending.providerId
|
|
2051
|
+
&& selection.modelId === pending.modelId
|
|
2052
|
+
&& selection.localOnly === null;
|
|
2053
|
+
}
|
|
2055
2054
|
);
|
|
2056
2055
|
}
|
|
2057
2056
|
|
|
@@ -2104,9 +2103,7 @@ export class AIProviderRuntime {
|
|
|
2104
2103
|
|| slot.selection)
|
|
2105
2104
|
&& !this.#pendingSpeechProviderHydrationMatches(
|
|
2106
2105
|
role,
|
|
2107
|
-
slot
|
|
2108
|
-
replacement.provider,
|
|
2109
|
-
replacement.routes
|
|
2106
|
+
slot
|
|
2110
2107
|
)) {
|
|
2111
2108
|
throw speechProviderReplacementError(
|
|
2112
2109
|
'ARCANE_AI_SPEECH_PROVIDER_REPLACEMENT_EXPECTED_PROVIDER_REQUIRED',
|
|
@@ -2249,9 +2246,7 @@ export class AIProviderRuntime {
|
|
|
2249
2246
|
|| slot.selection)
|
|
2250
2247
|
&& !this.#pendingSpeechProviderHydrationMatches(
|
|
2251
2248
|
role,
|
|
2252
|
-
slot
|
|
2253
|
-
replacement.providers[role],
|
|
2254
|
-
replacement.routes[role]
|
|
2249
|
+
slot
|
|
2255
2250
|
)) {
|
|
2256
2251
|
throw speechProviderReplacementError(
|
|
2257
2252
|
'ARCANE_AI_SPEECH_PROVIDER_REPLACEMENT_EXPECTED_PROVIDER_REQUIRED',
|
|
@@ -403,16 +403,6 @@ function effectiveDashboardVisibility(definitions=[],visibility={}){
|
|
|
403
403
|
);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
function byteProgressUnit(value){
|
|
407
|
-
const unit=String(value??'')
|
|
408
|
-
.trim()
|
|
409
|
-
.toLowerCase()
|
|
410
|
-
.replace(/[\s_-]+/g,'');
|
|
411
|
-
return unit.includes('byte')
|
|
412
|
-
||unit.includes('octet')
|
|
413
|
-
||/^(?:[kmgtpe]?i?b)(?:(?:\/|per)?(?:s|sec|second))?$/u.test(unit);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
406
|
function formatAIRuntimeProgress(progress,fallback){
|
|
417
407
|
const phase=typeof progress?.phase==='string'&&progress.phase
|
|
418
408
|
?progress.phase
|
|
@@ -422,13 +412,10 @@ function formatAIRuntimeProgress(progress,fallback){
|
|
|
422
412
|
const unit=typeof progress?.unit==='string'
|
|
423
413
|
?progress.unit
|
|
424
414
|
:'';
|
|
425
|
-
if(!Number.
|
|
426
|
-
|
|
427
|
-
||!Number.isSafeInteger(total)
|
|
415
|
+
if(!Number.isFinite(completed)
|
|
416
|
+
||!Number.isFinite(total)
|
|
428
417
|
||total<=0
|
|
429
|
-
|
|
430
|
-
||!unit
|
|
431
|
-
||byteProgressUnit(unit)){
|
|
418
|
+
||!unit){
|
|
432
419
|
return phase;
|
|
433
420
|
}
|
|
434
421
|
return `${phase} · ${completed} of ${total} ${unit}`;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
const ROOT_MAX_LENGTH=4096;
|
|
2
|
-
const QUERY_MAX_LENGTH=4096;
|
|
3
|
-
const TASK_ID_PATTERN=/^[a-z][a-z0-9-]{0,63}$/;
|
|
4
|
-
|
|
5
1
|
function workspaceRoot(value){
|
|
6
2
|
const root=String(value??'').trim();
|
|
7
|
-
if(!root
|
|
3
|
+
if(!root||/[\u0000-\u001f]/.test(root)){
|
|
8
4
|
throw new TypeError('Choose one existing development workspace directory.');
|
|
9
5
|
}
|
|
10
6
|
return root;
|
|
@@ -12,16 +8,16 @@ function workspaceRoot(value){
|
|
|
12
8
|
|
|
13
9
|
function contextQuery(value){
|
|
14
10
|
const query=String(value??'').trim();
|
|
15
|
-
if(
|
|
16
|
-
throw new TypeError('Development context queries must be
|
|
11
|
+
if(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/.test(query)){
|
|
12
|
+
throw new TypeError('Development context queries must be plain text.');
|
|
17
13
|
}
|
|
18
14
|
return query;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
function setupTaskId(value){
|
|
22
|
-
const taskId=String(value??'').trim()
|
|
23
|
-
if(!
|
|
24
|
-
throw new TypeError('Choose a
|
|
18
|
+
const taskId=String(value??'').trim();
|
|
19
|
+
if(!taskId||/[\u0000-\u001f]/.test(taskId)){
|
|
20
|
+
throw new TypeError('Choose a development setup task.');
|
|
25
21
|
}
|
|
26
22
|
return taskId;
|
|
27
23
|
}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
function
|
|
1
|
+
function completeText(value){return String(value??'');}
|
|
2
2
|
|
|
3
3
|
export function normalizeContentAdvisory(value){
|
|
4
4
|
if(!value||typeof value!=='object')return null;
|
|
5
|
-
return
|
|
5
|
+
return {
|
|
6
6
|
level:['critical','high','caution','low','unavailable'].includes(value.level)?value.level:'caution',
|
|
7
|
-
title:
|
|
8
|
-
summary:
|
|
9
|
-
signals:
|
|
10
|
-
actionLabel:
|
|
11
|
-
}
|
|
7
|
+
title:completeText(value.title??'Content advisory'),
|
|
8
|
+
summary:completeText(value.summary??'Review this message carefully.'),
|
|
9
|
+
signals:Array.from(value.signals||[],completeText),
|
|
10
|
+
actionLabel:completeText(value.actionLabel),
|
|
11
|
+
};
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
function unavailableAdvisory(){
|
|
15
|
+
return normalizeContentAdvisory({
|
|
16
|
+
level:'unavailable',
|
|
17
|
+
title:'Safety check unavailable',
|
|
18
|
+
summary:'No safety conclusion was made for this message. Pause and review it manually before replying.',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
19
21
|
|
|
20
22
|
export function unavailableMessageInspection(messages){
|
|
21
23
|
const advisories=new Map();
|
|
22
|
-
for(const message of Array.from(messages||[]))advisories.set(message,unavailableAdvisory);
|
|
24
|
+
for(const message of Array.from(messages||[]))advisories.set(message,unavailableAdvisory());
|
|
23
25
|
return {advisories,failures:advisories.size};
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -32,7 +34,7 @@ export async function inspectMessageRecords(messages,inspector,{prepare}={}){
|
|
|
32
34
|
catch{return unavailableMessageInspection(records);}
|
|
33
35
|
for(const message of records){
|
|
34
36
|
try{const advisory=normalizeContentAdvisory(await inspector(message,context));if(advisory){if(advisory.level==='unavailable')failures+=1;advisories.set(message,advisory);}}
|
|
35
|
-
catch{failures+=1;advisories.set(message,unavailableAdvisory);}
|
|
37
|
+
catch{failures+=1;advisories.set(message,unavailableAdvisory());}
|
|
36
38
|
}
|
|
37
39
|
return {advisories,failures};
|
|
38
40
|
}
|