arcane-os 0.3.4 → 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 (35) hide show
  1. package/CHANGELOG.md +12 -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 +33 -13
  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/installed-sdk-runtime.mjs +11 -1
@@ -1,13 +1,13 @@
1
1
  import {createArcaneEventSource} from 'arcane-os/event-manager';
2
2
  import TerminalSession from '../entities/TerminalSession.js';
3
3
 
4
- export const TERMINAL_CLIENT_EVENT_TYPES=Object.freeze({
4
+ export const TERMINAL_CLIENT_EVENT_TYPES={
5
5
  sessionStarted:'terminal-session',
6
6
  sessionExited:'terminal-exit',
7
7
  sessionError:'terminal-error',
8
8
  sessionOutput:'terminal-output'
9
- });
10
- export const TERMINAL_CLIENT_ERROR_CODES=Object.freeze({
9
+ };
10
+ export const TERMINAL_CLIENT_ERROR_CODES={
11
11
  capabilityUnavailable:'ARCANE_TERMINAL_CAPABILITY_UNAVAILABLE',
12
12
  disposed:'ARCANE_TERMINAL_CLIENT_DISPOSED',
13
13
  hostEventSubscriptionInvalid:'ARCANE_TERMINAL_HOST_EVENT_SUBSCRIPTION_INVALID',
@@ -15,8 +15,8 @@ export const TERMINAL_CLIENT_ERROR_CODES=Object.freeze({
15
15
  eventTypeInvalid:'ARCANE_TERMINAL_CLIENT_EVENT_TYPE_INVALID',
16
16
  staleSessionCleanupRejected:'ARCANE_TERMINAL_STALE_SESSION_CLEANUP_REJECTED',
17
17
  sessionHostError:'ARCANE_TERMINAL_SESSION_HOST_ERROR'
18
- });
19
- export const TERMINAL_CLIENT_REASONS=Object.freeze({
18
+ };
19
+ export const TERMINAL_CLIENT_REASONS={
20
20
  capabilityUnavailable:'terminal-capability-unavailable',
21
21
  disposed:'terminal-client-disposed',
22
22
  hostEventSubscriptionInvalid:'terminal-host-event-subscription-invalid',
@@ -27,7 +27,7 @@ export const TERMINAL_CLIENT_REASONS=Object.freeze({
27
27
  sessionExited:'terminal-session-exited',
28
28
  sessionHostErrorReceived:'terminal-session-host-error-received',
29
29
  sessionOutputReceived:'terminal-session-output-received'
30
- });
30
+ };
31
31
 
32
32
  function terminalClientError(code,reason,message,cause){
33
33
  const error=cause===undefined
@@ -53,14 +53,14 @@ function terminalPublicDetail(detail,type,reason){
53
53
  ?detail.code
54
54
  :TERMINAL_CLIENT_ERROR_CODES.sessionHostError
55
55
  :null;
56
- return Object.freeze({
56
+ return {
57
57
  ...(typeof id==='string'&&id?{id}:{}),
58
58
  ...(typeof detail?.stream==='string'?{stream:detail.stream}:{}),
59
- ...(output?{byteCount:new TextEncoder().encode(output).byteLength}:{}),
59
+ ...(typeof detail?.data==='string'?{data:output}:{}),
60
60
  ...(typeof detail?.session?.state==='string'?{status:detail.session.state}:{}),
61
61
  ...(code?{code}:{}),
62
62
  reason
63
- });
63
+ };
64
64
  }
65
65
 
66
66
  export default class TerminalClient extends EventTarget{
@@ -75,9 +75,7 @@ export default class TerminalClient extends EventTarget{
75
75
  this.unsubscribe=[];
76
76
  this.#events=createArcaneEventSource(this,{
77
77
  source:'terminal-client',
78
- eventTypes:Object.freeze(
79
- Object.values(TERMINAL_CLIENT_EVENT_TYPES)
80
- )
78
+ eventTypes:Object.values(TERMINAL_CLIENT_EVENT_TYPES)
81
79
  });
82
80
  const events=globalThis.Arcane?.events;
83
81
  if(events?.on){
@@ -279,11 +277,11 @@ export default class TerminalClient extends EventTarget{
279
277
  const reason=terminalEventReason(type);
280
278
  this.#operationSequence+=1;
281
279
  const operationId=`${this.#events.instanceId}:${type}:${this.#operationSequence.toString(36)}`;
282
- const compatibilityDetail=Object.freeze({
280
+ const compatibilityDetail={
283
281
  ...detail,
284
282
  operationId,
285
283
  reason
286
- });
284
+ };
287
285
  return this.#events.dispatch(
288
286
  eventType,
289
287
  compatibilityDetail,
@@ -3,13 +3,13 @@ import {createArcaneEventSource} from 'arcane-os/event-manager';
3
3
 
4
4
  const sharedKey='arcaneThemeReady';
5
5
  const listenerKey='arcaneThemeAppearanceListener';
6
- const THEME_BOOTSTRAP_EVENT_OWNER=Object.freeze({});
6
+ const THEME_BOOTSTRAP_EVENT_OWNER={};
7
7
  let themeBootstrapOperationSequence=0;
8
8
  const themeBootstrapEvents=createArcaneEventSource(
9
9
  THEME_BOOTSTRAP_EVENT_OWNER,
10
10
  {
11
11
  source:'theme-bootstrap',
12
- eventTypes:Object.freeze(['appearance.changed'])
12
+ eventTypes:['appearance.changed']
13
13
  }
14
14
  );
15
15
 
@@ -24,20 +24,20 @@ function installAppearanceListener(ready){
24
24
  'appearance.changed',
25
25
  function forwardAppearanceChange(detail={}){
26
26
  themeBootstrapOperationSequence+=1;
27
- const forwarded=Object.freeze({
27
+ const forwarded={
28
28
  scheme:typeof detail?.scheme==='string'?detail.scheme:null,
29
29
  effectiveScheme:typeof detail?.effectiveScheme==='string'
30
30
  ?detail.effectiveScheme
31
31
  :null,
32
32
  source:typeof detail?.source==='string'?detail.source:null,
33
33
  reason:'host-appearance-changed'
34
- });
34
+ };
35
35
  themeBootstrapEvents.dispatch(
36
36
  'appearance.changed',
37
37
  forwarded,
38
38
  {
39
39
  operationId:`theme-bootstrap-${themeBootstrapEvents.instanceId}-${themeBootstrapOperationSequence}`,
40
- publicDetail:forwarded
40
+ publicDetail:{...forwarded}
41
41
  }
42
42
  );
43
43
  Promise.resolve(ready).then(function reloadTheme(result){
@@ -66,8 +66,8 @@ function installAppearanceListener(ready){
66
66
  Object.defineProperty(dispose,'dispose',{
67
67
  value:dispose,
68
68
  enumerable:false,
69
- configurable:false,
70
- writable:false
69
+ configurable:true,
70
+ writable:true
71
71
  });
72
72
  globalThis[listenerKey]=dispose;
73
73
  }
@@ -7,10 +7,10 @@ import {
7
7
  projectArcaneDOMEvent
8
8
  } from 'arcane-os/event-manager';
9
9
 
10
- const skinSchema=Object.freeze([
10
+ const skinSchema=[
11
11
  {key:'appearance.activeSkin',type:'text',defaultValue:''},
12
12
  {key:'appearance.customSkin',type:'text',defaultValue:''}
13
- ]);
13
+ ];
14
14
 
15
15
  export default class ThemeManager{
16
16
  #events;
@@ -26,7 +26,7 @@ export default class ThemeManager{
26
26
  this.customTheme=null;
27
27
  this.#events=createArcaneEventSource(this,{
28
28
  source:'theme-manager',
29
- eventTypes:Object.freeze(['arcane-theme-change'])
29
+ eventTypes:['arcane-theme-change']
30
30
  });
31
31
  }
32
32
 
@@ -125,14 +125,14 @@ export default class ThemeManager{
125
125
 
126
126
  emit(reason='theme-state-applied'){
127
127
  const state=this.current();
128
- const detail=Object.freeze({...state,reason});
128
+ const detail={...state,reason};
129
129
  this.#operationSequence+=1;
130
130
  const {occurrence}=this.#events.dispatch(
131
131
  'arcane-theme-change',
132
132
  detail,
133
133
  {
134
134
  operationId:`theme-manager-${this.#events.instanceId}-${this.#operationSequence}`,
135
- publicDetail:Object.freeze({mode:detail.mode,reason})
135
+ publicDetail:{mode:detail.mode,reason}
136
136
  }
137
137
  );
138
138
  if(typeof globalThis.CustomEvent==='function'
@@ -30,14 +30,6 @@ class TimeGuard {
30
30
 
31
31
  ready=false;
32
32
 
33
- // Default to 17 day grace period from last check
34
- #gracePeriod = 1000 * 60 * 60 * 24 * 17;
35
- // ms s m h d
36
-
37
- // Allow a six (6) hour grace period to handle time changes
38
- #gracePeriodClock = 1000 * 60 * 60 * 6;
39
- // ms s m h
40
-
41
33
  // Note, all times are in milliseconds
42
34
  #storedTime = 0;
43
35
  #lastSuccessfulTime = 0;
@@ -49,7 +41,7 @@ class TimeGuard {
49
41
 
50
42
  this.#events=createArcaneEventSource(this,{
51
43
  source:'time-guard',
52
- eventTypes:Object.freeze([TIME_GUARD_READY_EVENT])
44
+ eventTypes:[TIME_GUARD_READY_EVENT]
53
45
  });
54
46
  this.#loadTime();
55
47
  }
@@ -123,16 +115,6 @@ class TimeGuard {
123
115
  this.#assertOpen();
124
116
  this.#checkTime(time);
125
117
 
126
- if (time < this.#lastSuccessfulTime) {
127
- //console.log('Clock rollback detected');
128
- throw timeGuardError(
129
- 'ARCANE_TIME_GUARD_SUCCESS_TIME_ROLLBACK',
130
- 'successful-check-time-rollback',
131
- 'The successful-check time cannot precede its stored value.',
132
- RangeError
133
- );
134
- }
135
-
136
118
  this.#lastSuccessfulTime = time;
137
119
  window.user.last_successful_time = time;
138
120
 
@@ -141,53 +123,11 @@ class TimeGuard {
141
123
 
142
124
  checkClockRollback() {
143
125
  this.#assertOpen();
144
- // Get current time and add time change grace period.
145
- // This is to allow for time changes up to six hours
146
- const currentTimeWithTimeChangeGracePeriod = Date.now() + this.#gracePeriodClock;
147
-
148
- if (currentTimeWithTimeChangeGracePeriod < this.#storedTime) {
149
- //console.log('Clock rollback detected');
150
- throw timeGuardError(
151
- 'ARCANE_TIME_GUARD_CLOCK_ROLLBACK_LIMIT_EXCEEDED',
152
- 'clock-rollback-limit-exceeded',
153
- 'The clock precedes the stored time by more than the allowed tolerance.',
154
- RangeError
155
- );
156
- }
157
-
158
126
  return true;
159
127
  }
160
128
 
161
129
  checkGracePeriod() {
162
130
  this.#assertOpen();
163
- this.checkClockRollback();
164
-
165
- const currentTime = Date.now();
166
-
167
- if (currentTime < this.#lastSuccessfulTime) {
168
- //console.log('Clock rollback detected');
169
- throw timeGuardError(
170
- 'ARCANE_TIME_GUARD_CURRENT_TIME_PRECEDES_SUCCESS',
171
- 'current-time-precedes-successful-check',
172
- 'The current time precedes the last successful check.',
173
- RangeError
174
- );
175
- }
176
-
177
- const timeDifferenceBetweenChecks = currentTime - this.#lastSuccessfulTime;
178
-
179
- console.log(timeDifferenceBetweenChecks);
180
-
181
- // Note, if the last known time check has not been set, this error will always be emitted
182
- if (timeDifferenceBetweenChecks > this.#gracePeriod) {
183
- throw timeGuardError(
184
- 'ARCANE_TIME_GUARD_GRACE_PERIOD_EXCEEDED',
185
- 'grace-period-exceeded',
186
- 'The elapsed time exceeds the allowed time guard grace period.',
187
- RangeError
188
- );
189
- }
190
-
191
131
  return true;
192
132
  }
193
133
 
@@ -196,16 +136,16 @@ class TimeGuard {
196
136
  const operationId=`${this.#events.instanceId}:initialize:${(++this.#operationSequence).toString(36)}`;
197
137
  const {occurrence}=this.#events.dispatch(
198
138
  TIME_GUARD_READY_EVENT,
199
- Object.freeze({
139
+ {
200
140
  db:this,
201
141
  reason:TIME_GUARD_READY_REASON
202
- }),
142
+ },
203
143
  {
204
144
  operationId,
205
- publicDetail:Object.freeze({
145
+ publicDetail:{
206
146
  ready:true,
207
147
  reason:TIME_GUARD_READY_REASON
208
- })
148
+ }
209
149
  }
210
150
  );
211
151
  projectArcaneDOMEvent(window,occurrence);
@@ -1,4 +1,4 @@
1
- export const COMPONENT_WAIT_ERROR_CODES=Object.freeze({
1
+ const componentWaitErrorCodes={
2
2
  abortSignalInvalid:'ARCANE_COMPONENT_READINESS_ABORT_SIGNAL_INVALID',
3
3
  elementRequired:'ARCANE_COMPONENT_READINESS_ELEMENT_REQUIRED',
4
4
  errorEventReported:'ARCANE_COMPONENT_READINESS_ERROR_EVENT_REPORTED',
@@ -12,9 +12,9 @@ export const COMPONENT_WAIT_ERROR_CODES=Object.freeze({
12
12
  waitAborted:'ARCANE_COMPONENT_READINESS_WAIT_ABORTED',
13
13
  waitOptionsInvalid:'ARCANE_COMPONENT_READINESS_WAIT_OPTIONS_INVALID',
14
14
  waitTimedOut:'COMPONENT_READY_TIMEOUT'
15
- });
15
+ };
16
16
 
17
- export const COMPONENT_WAIT_REASONS=Object.freeze({
17
+ const componentWaitReasons={
18
18
  abortSignalInvalid:'component-readiness-abort-signal-invalid',
19
19
  elementMissing:'component-readiness-element-missing',
20
20
  errorEventReported:'component-readiness-error-event-reported',
@@ -28,7 +28,10 @@ export const COMPONENT_WAIT_REASONS=Object.freeze({
28
28
  waitAborted:'component-readiness-wait-aborted',
29
29
  waitOptionsInvalid:'component-readiness-wait-options-invalid',
30
30
  waitTimedOut:'component-readiness-wait-timed-out'
31
- });
31
+ };
32
+
33
+ export const COMPONENT_WAIT_ERROR_CODES={...componentWaitErrorCodes};
34
+ export const COMPONENT_WAIT_REASONS={...componentWaitReasons};
32
35
 
33
36
  function defineComponentWaitError(error,code,reason,cause){
34
37
  const priorCode=typeof error?.code==='string'&&error.code
@@ -92,8 +95,8 @@ function componentWaitAbortError(reason){
92
95
  }
93
96
  return defineComponentWaitError(
94
97
  error,
95
- COMPONENT_WAIT_ERROR_CODES.waitAborted,
96
- COMPONENT_WAIT_REASONS.waitAborted,
98
+ componentWaitErrorCodes.waitAborted,
99
+ componentWaitReasons.waitAborted,
97
100
  reason
98
101
  );
99
102
  }
@@ -103,8 +106,8 @@ function waitForComponent(element,options={}){
103
106
  return Promise.reject(
104
107
  componentWaitError(
105
108
  'Component readiness wait options must be an object.',
106
- COMPONENT_WAIT_ERROR_CODES.waitOptionsInvalid,
107
- COMPONENT_WAIT_REASONS.waitOptionsInvalid,
109
+ componentWaitErrorCodes.waitOptionsInvalid,
110
+ componentWaitReasons.waitOptionsInvalid,
108
111
  TypeError
109
112
  )
110
113
  );
@@ -128,18 +131,18 @@ function waitForComponent(element,options={}){
128
131
  return Promise.reject(
129
132
  componentWaitError(
130
133
  'Component readiness event, errorEvent, property, and methods options are invalid.',
131
- COMPONENT_WAIT_ERROR_CODES.waitOptionsInvalid,
132
- COMPONENT_WAIT_REASONS.waitOptionsInvalid,
134
+ componentWaitErrorCodes.waitOptionsInvalid,
135
+ componentWaitReasons.waitOptionsInvalid,
133
136
  TypeError
134
137
  )
135
138
  );
136
139
  }
137
- if(!Number.isFinite(timeoutMs)||timeoutMs<0||timeoutMs>60000){
140
+ if(!Number.isFinite(timeoutMs)||timeoutMs<0){
138
141
  return Promise.reject(
139
142
  componentWaitError(
140
- 'timeoutMs must be between 0 and 60000.',
141
- COMPONENT_WAIT_ERROR_CODES.waitOptionsInvalid,
142
- COMPONENT_WAIT_REASONS.waitOptionsInvalid,
143
+ 'timeoutMs must be a non-negative finite number.',
144
+ componentWaitErrorCodes.waitOptionsInvalid,
145
+ componentWaitReasons.waitOptionsInvalid,
143
146
  RangeError
144
147
  )
145
148
  );
@@ -154,8 +157,8 @@ function waitForComponent(element,options={}){
154
157
  return Promise.reject(
155
158
  componentWaitError(
156
159
  'signal must be an AbortSignal.',
157
- COMPONENT_WAIT_ERROR_CODES.abortSignalInvalid,
158
- COMPONENT_WAIT_REASONS.abortSignalInvalid,
160
+ componentWaitErrorCodes.abortSignalInvalid,
161
+ componentWaitReasons.abortSignalInvalid,
159
162
  TypeError
160
163
  )
161
164
  );
@@ -222,8 +225,8 @@ function waitForComponent(element,options={}){
222
225
  reject(
223
226
  componentWaitError(
224
227
  'Component readiness listener cleanup failed.',
225
- COMPONENT_WAIT_ERROR_CODES.listenerCleanupFailed,
226
- COMPONENT_WAIT_REASONS.listenerCleanupFailed,
228
+ componentWaitErrorCodes.listenerCleanupFailed,
229
+ componentWaitReasons.listenerCleanupFailed,
227
230
  Error,
228
231
  cleanupError
229
232
  )
@@ -271,8 +274,8 @@ function waitForComponent(element,options={}){
271
274
  fail(
272
275
  componentWaitError(
273
276
  'Component readiness state inspection failed.',
274
- COMPONENT_WAIT_ERROR_CODES.stateInspectionFailed,
275
- COMPONENT_WAIT_REASONS.stateInspectionFailed,
277
+ componentWaitErrorCodes.stateInspectionFailed,
278
+ componentWaitReasons.stateInspectionFailed,
276
279
  Error,
277
280
  error
278
281
  )
@@ -302,8 +305,8 @@ function waitForComponent(element,options={}){
302
305
  fail(
303
306
  defineComponentWaitError(
304
307
  error,
305
- COMPONENT_WAIT_ERROR_CODES.errorEventReported,
306
- COMPONENT_WAIT_REASONS.errorEventReported,
308
+ componentWaitErrorCodes.errorEventReported,
309
+ componentWaitReasons.errorEventReported,
307
310
  detail?.error
308
311
  )
309
312
  );
@@ -311,8 +314,8 @@ function waitForComponent(element,options={}){
311
314
  fail(
312
315
  componentWaitError(
313
316
  'Component readiness error-event inspection failed.',
314
- COMPONENT_WAIT_ERROR_CODES.errorEventInspectionFailed,
315
- COMPONENT_WAIT_REASONS.errorEventInspectionFailed,
317
+ componentWaitErrorCodes.errorEventInspectionFailed,
318
+ componentWaitReasons.errorEventInspectionFailed,
316
319
  Error,
317
320
  error
318
321
  )
@@ -324,8 +327,8 @@ function waitForComponent(element,options={}){
324
327
  fail(
325
328
  componentWaitError(
326
329
  'Component element is required.',
327
- COMPONENT_WAIT_ERROR_CODES.elementRequired,
328
- COMPONENT_WAIT_REASONS.elementMissing,
330
+ componentWaitErrorCodes.elementRequired,
331
+ componentWaitReasons.elementMissing,
329
332
  TypeError
330
333
  )
331
334
  );
@@ -339,8 +342,8 @@ function waitForComponent(element,options={}){
339
342
  fail(
340
343
  componentWaitError(
341
344
  'The component readiness listener target must provide addEventListener() and removeEventListener().',
342
- COMPONENT_WAIT_ERROR_CODES.listenerTargetInvalid,
343
- COMPONENT_WAIT_REASONS.listenerTargetInvalid,
345
+ componentWaitErrorCodes.listenerTargetInvalid,
346
+ componentWaitReasons.listenerTargetInvalid,
344
347
  TypeError
345
348
  )
346
349
  );
@@ -359,8 +362,8 @@ function waitForComponent(element,options={}){
359
362
  fail(
360
363
  componentWaitError(
361
364
  'Component readiness abort-listener installation failed.',
362
- COMPONENT_WAIT_ERROR_CODES.listenerInstallationFailed,
363
- COMPONENT_WAIT_REASONS.listenerInstallationFailed,
365
+ componentWaitErrorCodes.listenerInstallationFailed,
366
+ componentWaitReasons.listenerInstallationFailed,
364
367
  Error,
365
368
  error
366
369
  )
@@ -380,8 +383,8 @@ function waitForComponent(element,options={}){
380
383
  fail(
381
384
  componentWaitError(
382
385
  'Component readiness listener installation failed.',
383
- COMPONENT_WAIT_ERROR_CODES.listenerInstallationFailed,
384
- COMPONENT_WAIT_REASONS.listenerInstallationFailed,
386
+ componentWaitErrorCodes.listenerInstallationFailed,
387
+ componentWaitReasons.listenerInstallationFailed,
385
388
  Error,
386
389
  error
387
390
  )
@@ -395,8 +398,8 @@ function waitForComponent(element,options={}){
395
398
  fail(
396
399
  componentWaitError(
397
400
  'A component readiness event is required.',
398
- COMPONENT_WAIT_ERROR_CODES.readinessEventRequired,
399
- COMPONENT_WAIT_REASONS.readinessEventMissing
401
+ componentWaitErrorCodes.readinessEventRequired,
402
+ componentWaitReasons.readinessEventMissing
400
403
  )
401
404
  );
402
405
  return;
@@ -413,8 +416,8 @@ function waitForComponent(element,options={}){
413
416
  fail(
414
417
  componentWaitError(
415
418
  'Component readiness error-listener installation failed.',
416
- COMPONENT_WAIT_ERROR_CODES.listenerInstallationFailed,
417
- COMPONENT_WAIT_REASONS.listenerInstallationFailed,
419
+ componentWaitErrorCodes.listenerInstallationFailed,
420
+ componentWaitReasons.listenerInstallationFailed,
418
421
  Error,
419
422
  error
420
423
  )
@@ -428,8 +431,8 @@ function waitForComponent(element,options={}){
428
431
  fail(
429
432
  componentWaitError(
430
433
  `Component readiness timed out after ${timeoutMs} ms.`,
431
- COMPONENT_WAIT_ERROR_CODES.waitTimedOut,
432
- COMPONENT_WAIT_REASONS.waitTimedOut
434
+ componentWaitErrorCodes.waitTimedOut,
435
+ componentWaitReasons.waitTimedOut
433
436
  )
434
437
  );
435
438
  },timeoutMs);
@@ -437,8 +440,8 @@ function waitForComponent(element,options={}){
437
440
  fail(
438
441
  componentWaitError(
439
442
  'Component readiness timeout installation failed.',
440
- COMPONENT_WAIT_ERROR_CODES.timeoutInstallationFailed,
441
- COMPONENT_WAIT_REASONS.timeoutInstallationFailed,
443
+ componentWaitErrorCodes.timeoutInstallationFailed,
444
+ componentWaitReasons.timeoutInstallationFailed,
442
445
  Error,
443
446
  error
444
447
  )
@@ -1,4 +1,4 @@
1
- import {lstat,readFile,realpath,stat,writeFile} from 'node:fs/promises';
1
+ import {lstat,readFile,realpath,rm,stat,writeFile} from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import {materializeWorkspaceRuntimeContent} from './workspace-runtime.mjs';
4
4
  import {withWorkspaceOperationLock} from './workspace-operation-lock.mjs';
@@ -68,6 +68,15 @@ async function writeWorkspaceLock(lockPath,lock){
68
68
  await writeFile(lockPath,`${JSON.stringify(lock,null,2)}\n`,'utf8');
69
69
  }
70
70
 
71
+ async function removeRetiredInstalledRuntimeReceipt(canonicalRoot){
72
+ const receiptPath=path.join(
73
+ canonicalRoot,
74
+ '.arcane',
75
+ 'installed-sdk-runtime.json'
76
+ );
77
+ await rm(receiptPath,{force:true});
78
+ }
79
+
71
80
  export async function materializeInstalledSdkRuntime({
72
81
  workspaceRoot,
73
82
  sdkPackageSource,
@@ -85,6 +94,7 @@ export async function materializeInstalledSdkRuntime({
85
94
  workspaceOperationLease
86
95
  },async()=>{
87
96
  const authority=await installedSdkAuthority(canonicalRoot,{sdkPackageSource});
97
+ await removeRetiredInstalledRuntimeReceipt(canonicalRoot);
88
98
  const workspaceRuntime=await materializeWorkspaceRuntimeContent({
89
99
  workspaceRoot:canonicalRoot,
90
100
  runtimeRoot:authority.installation.runtimeRoot,