arcane-os 0.3.3 → 0.3.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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +7 -7
  3. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +315 -119
  4. package/browser-runtime/ai/model-controller.mjs +439 -95
  5. package/package.json +1 -1
  6. package/runtime/arcane/components/assistant-panel.html +2 -1
  7. package/runtime/arcane/components/chat.html +466 -206
  8. package/runtime/arcane/components/speech.html +107 -30
  9. package/runtime/arcane/components/voice-transcription.html +27 -3
  10. package/runtime/arcane/entities/Chat.js +165 -97
  11. package/runtime/arcane/entities/IntentEnvelope.js +52 -118
  12. package/runtime/arcane/entities/TWiNPolicyDecision.js +33 -130
  13. package/runtime/arcane/entities/User.js +38 -44
  14. package/runtime/arcane/modules/AI.js +569 -302
  15. package/runtime/arcane/modules/AIProviderRuntime.js +765 -135
  16. package/runtime/arcane/modules/AIRuntimeState.js +22 -24
  17. package/runtime/arcane/modules/ApiModelDatabase.js +54 -48
  18. package/runtime/arcane/modules/CaseEvidenceIndexer.js +6 -10
  19. package/runtime/arcane/modules/CommunicationHub.js +90 -94
  20. package/runtime/arcane/modules/ComponentContracts.js +34 -9
  21. package/runtime/arcane/modules/ConfiguredAIChatSession.js +77 -77
  22. package/runtime/arcane/modules/ConversationTimebox.js +76 -104
  23. package/runtime/arcane/modules/DBLS.js +14 -12
  24. package/runtime/arcane/modules/DBOPFS.js +20 -15
  25. package/runtime/arcane/modules/Errors.js +196 -436
  26. package/runtime/arcane/modules/HTMLImport.js +49 -32
  27. package/runtime/arcane/modules/Ollama.js +16 -14
  28. package/runtime/arcane/modules/PersistentAIChatSession.js +174 -93
  29. package/runtime/arcane/modules/RecordReviewStore.js +40 -35
  30. package/runtime/arcane/modules/TerminalClient.js +12 -14
  31. package/runtime/arcane/modules/ThemeBootstrap.js +7 -7
  32. package/runtime/arcane/modules/ThemeManager.js +5 -5
  33. package/runtime/arcane/modules/TimeGuard.js +5 -65
  34. package/runtime/arcane/modules/WaitForComponent.js +43 -40
  35. package/src/cli/main.mjs +12 -11
  36. package/src/installed-sdk-runtime.mjs +11 -1
  37. package/src/mail-server.mjs +12 -5
  38. package/src/mail.mjs +25 -19
  39. package/src/workspace.mjs +32 -9
package/src/mail.mjs CHANGED
@@ -40,13 +40,16 @@ function dependency(options,name,fallback){
40
40
  }
41
41
 
42
42
  function recipientList(value,label){
43
+ if(value===undefined||value===null||value===''||(Array.isArray(value)&&value.length===0)){
44
+ return [];
45
+ }
43
46
  const entries=Array.isArray(value)
44
47
  ? value
45
48
  : typeof value==='string'
46
49
  ? value.split(',')
47
50
  : null;
48
- if(!entries||entries.length===0||entries.length>50){
49
- usage(`${label} must contain one to 50 comma-separated email addresses.`);
51
+ if(!entries||entries.length===0){
52
+ usage(`${label} must contain at least one email address when supplied.`);
50
53
  }
51
54
  const result=entries.map(function normalizeMailRecipient(entry){
52
55
  if(typeof entry!=='string'||!entry.trim()){
@@ -111,21 +114,24 @@ async function deleteCredential(options){
111
114
  return remove(credentialOptions(options));
112
115
  }
113
116
 
114
- function safeSendFailure(result){
115
- return {
116
- provider:'resend',
117
- status:result.status,
118
- classification:result.classification,
119
- requestId:result.requestId,
120
- providerStatus:result.providerStatus,
121
- recipientCount:result.recipientCount,
122
- retryable:result.retryable===true,
123
- uncertain:result.uncertain===true,
124
- ...(typeof result.code==='string'?{code:result.code}:{}),
125
- ...(Number.isSafeInteger(result.retryAfterMs)&&result.retryAfterMs>0
126
- ?{retryAfterMs:result.retryAfterMs}
127
- :{})
128
- };
117
+ function withoutMailCredentials(value,seen=new WeakMap()){
118
+ if(!value||typeof value!=='object')return value;
119
+ if(seen.has(value))return seen.get(value);
120
+ const copy=Array.isArray(value)?[]:{};
121
+ seen.set(value,copy);
122
+ for(const [key,entry] of Object.entries(value)){
123
+ if(key==='apiKey'||key==='appKey')continue;
124
+ copy[key]=withoutMailCredentials(entry,seen);
125
+ }
126
+ return copy;
127
+ }
128
+
129
+ function completeSendFailure(result){
130
+ if(!result||typeof result!=='object'||Array.isArray(result)){
131
+ return {provider:'resend',result:withoutMailCredentials(result)};
132
+ }
133
+ // Complete provider detail remains visible; only credential fields are omitted.
134
+ return withoutMailCredentials(result);
129
135
  }
130
136
 
131
137
  async function sendMail(options){
@@ -164,9 +170,9 @@ async function sendMail(options){
164
170
  signal:options.signal
165
171
  });
166
172
  if(result?.classification==='accepted'&&result.status==='accepted'){
167
- return result;
173
+ return withoutMailCredentials(result);
168
174
  }
169
- const details=safeSendFailure(result||{});
175
+ const details=completeSendFailure(result);
170
176
  throw new ArcaneError(
171
177
  ERROR_CODES.operationFailed,
172
178
  `Resend did not authoritatively accept the mail request (${details.classification||'unknown'}).`,
package/src/workspace.mjs CHANGED
@@ -94,6 +94,18 @@ function dependencyNameForSdkPackageSource(source){
94
94
  }
95
95
  }
96
96
 
97
+ function routeIncludeMatches(actual,wanted,optionalSecurity){
98
+ if(!Array.isArray(actual)||!Array.isArray(wanted))return false;
99
+ if(actual.length===wanted.length
100
+ &&actual.every(function sameIncludedPath(value,index){return value===wanted[index];})){
101
+ return true;
102
+ }
103
+ return optionalSecurity
104
+ &&wanted.at(-1)==='security'
105
+ &&actual.length===wanted.length-1
106
+ &&actual.every(function sameFunctionalPath(value,index){return value===wanted[index];});
107
+ }
108
+
97
109
  export function resolveSdkPackageDeclaration(rootPackage,{
98
110
  allowMissing=false,
99
111
  packageSource
@@ -179,19 +191,30 @@ function classifyRootConfig(config){
179
191
  include:['index.js','licence','package.json']
180
192
  }
181
193
  ];
182
- const matches=expected=>routes.length===expected.length&&routes.every((route,index)=>{
183
- const wanted=expected[index];
184
- return isObject(route)&&Object.keys(route).every(key=>['source','destination','include','exclude'].includes(key))
185
- &&route.source===wanted.source&&route.destination===wanted.destination
186
- &&JSON.stringify(route.include)===JSON.stringify(wanted.include)
187
- &&Array.isArray(route.exclude)&&route.exclude.length===0;
188
- });
194
+ const matches=(expected,{optionalArcaneSecurity=false}={})=>{
195
+ if(routes.length!==expected.length)return false;
196
+ return routes.every(function routeMatches(route,index){
197
+ const wanted=expected[index];
198
+ return isObject(route)
199
+ &&Object.keys(route).every(function knownRouteKey(key){
200
+ return ['source','destination','include','exclude'].includes(key);
201
+ })
202
+ &&route.source===wanted.source&&route.destination===wanted.destination
203
+ &&routeIncludeMatches(
204
+ route.include,
205
+ wanted.include,
206
+ optionalArcaneSecurity&&index===0
207
+ &&wanted.source==='arcane'&&wanted.destination==='arcane'
208
+ )
209
+ &&Array.isArray(route.exclude)&&route.exclude.length===0;
210
+ });
211
+ };
189
212
  let workspaceMode;
190
213
  let browserRuntimeLayout;
191
- if(matches(external)){
214
+ if(matches(external,{optionalArcaneSecurity:true})){
192
215
  workspaceMode='external';
193
216
  browserRuntimeLayout='physical-v1';
194
- }else if(matches(integrated)){
217
+ }else if(matches(integrated,{optionalArcaneSecurity:true})){
195
218
  workspaceMode='integrated';
196
219
  browserRuntimeLayout='physical-v1';
197
220
  }else if(matches(integratedLegacy)){