arcane-os 0.37.0 → 0.38.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.38.0
4
+
5
+ - Add `User.AI_name` as an application-owned complete string with an empty-string
6
+ default, ordinary getter/setter, profile loading and `updateExplicit` support.
7
+ Preserve older saved profiles and restore the hydrated baseline after a failed
8
+ save; no existing history or provider/model selection is rewritten.
9
+ - Distinguish saved conversation speakers in file previews using the shared
10
+ action/action-text colors for user cards and surface/text colors for assistant
11
+ cards. Assistant headings use the complete saved nonblank string name or `AI`,
12
+ without a role suffix. Preserve other role labels, timestamps, status, complete
13
+ content and persistence. Capturing names on new Chat turns is separate work.
14
+
3
15
  ## 0.37.0
4
16
 
5
17
  - Add opt-in `markdown-editor` fit layout and preview following through
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 share the theme, packaging, event, cancellation,
20
20
  and browser run contracts while retaining their selected application layout.
21
21
 
22
- This checkout defines the `0.37.0` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.38.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
 
@@ -421,7 +421,7 @@
421
421
  ],
422
422
  "availability": "Browser and supported native WebViews",
423
423
  "transport": "HTMLImport + DOM; injected Arcane/provider modules where listed",
424
- "normalization": "Selection/filter state and neutral previews normalized; storage/provider behavior mixed. Initial directoryFilter and setDirectoryFilter(fn|null) use false-only exclusion before built-in DBOPFS key/metadata reads; data-hidden-prefixes also applies to directories unless data-show-hidden is present. Existing file predicates preserve their first argument and receive optional directory/fileName/path/layout context. previewDescriptor(original File,{directory,fileName,extension,path,mimeType,signal}) may asynchronously return text/markdown/html/json content, conversation messages with role/content/real timestamp and optional name/status, collection items, or image/audio/pdf/download content as Blob/File or a lazy ({signal}) loader. Downloads require fileName; descriptors accept title and images accept alt. Lazy items load only on explicit request and retain item-local retry. Close, replacement, and destroy abort the preview signal, suppress late output, remove iframe srcdoc, stop audio, and revoke all owned object URLs. HTML preserves the exact string in iframe srcdoc; HTML/Markdown MIME fallback supports extensionless files. Nullish descriptors preserve previewTransform for JSON-family files and native previews; untransformed JSONL/NDJSON retains complete raw text, and other binary files download the original File."
424
+ "normalization": "Selection/filter state and neutral previews normalized; storage/provider behavior mixed. Initial directoryFilter and setDirectoryFilter(fn|null) use false-only exclusion before built-in DBOPFS key/metadata reads; data-hidden-prefixes also applies to directories unless data-show-hidden is present. Existing file predicates preserve their first argument and receive optional directory/fileName/path/layout context. previewDescriptor(original File,{directory,fileName,extension,path,mimeType,signal}) may asynchronously return text/markdown/html/json content, conversation messages with role/content/real timestamp and optional name/status, collection items, or image/audio/pdf/download content as Blob/File or a lazy ({signal}) loader. Assistant conversation labels use the exact nonblank string name or AI without a role suffix; other role labels retain existing name/role presentation. User and assistant cards have distinct theme backgrounds and preserve data-role. Downloads require fileName; descriptors accept title and images accept alt. Lazy items load only on explicit request and retain item-local retry. Close, replacement, and destroy abort the preview signal, suppress late output, remove iframe srcdoc, stop audio, and revoke all owned object URLs. HTML preserves the exact string in iframe srcdoc; HTML/Markdown MIME fallback supports extensionless files. Nullish descriptors preserve previewTransform for JSON-family files and native previews; untransformed JSONL/NDJSON retains complete raw text, and other binary files download the original File."
425
425
  },
426
426
  {
427
427
  "file": "runtime/arcane/components/header.html",
@@ -19,7 +19,7 @@
19
19
  {"file":"runtime/arcane/entities/Preference.js","exports":["default","preferenceSchema"],"availability":"cross-host","normalization":"normalized"},
20
20
  {"file":"runtime/arcane/entities/TerminalSession.js","exports":["default","terminalShells"],"availability":"cross-host","normalization":"normalized"},
21
21
  {"file":"runtime/arcane/entities/Theme.js","exports":["arcaneDarkThemeTokens","arcaneLightThemeTokens","default","themeColorToHex","themeTokens"],"availability":"cross-host/dom-when-applied","normalization":"normalized/mixed"},
22
- {"file":"runtime/arcane/entities/User.js","exports":["default","profileUpdateFromSearchParams"],"availability":"browser/native-webview","normalization":"updateExplicit accepts existing partial/JSON updates or an awaited fresh-profile callback under the existing serialized write owner; callback null skips saving and returns the fresh profile, while failed writes restore the fresh baseline. Timestamp setters persist partial fields through that owner. profileUpdateFromSearchParams purely maps nonempty supplied URLSearchParams values without further decoding, trimming, or persistence."},
22
+ {"file":"runtime/arcane/entities/User.js","exports":["default","profileUpdateFromSearchParams"],"availability":"browser/native-webview","normalization":"AI_name is a persisted string preference with an empty-string default that preserves complete supplied text alongside AI_personality; loading older records does not rewrite them. updateExplicit accepts existing partial/JSON updates or an awaited fresh-profile callback under the existing serialized write owner; callback null skips saving and returns the fresh profile, while failed writes restore the fresh baseline. Timestamp setters persist partial fields through that owner. profileUpdateFromSearchParams purely maps nonempty supplied URLSearchParams values without further decoding, trimming, or persistence."},
23
23
  {"file":"runtime/arcane/entities/Weather.js","exports":["WeatherDay","WeatherLocation","WeatherObservation","WeatherSnapshot"],"availability":"cross-host","normalization":"normalized"}
24
24
  ]
25
25
  }
@@ -844,7 +844,11 @@ Each descriptor accepts an optional `title`. Supported shapes are:
844
844
  | `image`, `audio`, `pdf`, `download` | `content`: a `Blob` or `File`, or a function receiving `{signal}` and resolving to one |
845
845
 
846
846
  Conversation `role` and complete Markdown `content` are strings. Optional
847
- `name` and `status` are displayed alongside the role and time. Valid supplied
847
+ assistant `name` is displayed exactly when it is a nonblank string; otherwise
848
+ the assistant label is `AI`, without a role suffix. User and other role labels
849
+ retain their supplied name alongside the role. User and assistant cards use
850
+ distinct shared-theme backgrounds, and each card retains its original
851
+ `data-role`. Optional `status` is displayed beside the time. Valid supplied
848
852
  timestamps are displayed in local time with their real ISO datetime; absent
849
853
  timestamps display `Time unavailable`, and an unrecognized supplied timestamp
850
854
  is displayed as supplied. No timestamp is invented.
@@ -274,6 +274,29 @@ Owns persisted user preference/profile fields, explicit-preference updates,
274
274
  fresh reads, saves, and JSON projection. It installs `window.user` after its
275
275
  DBLS/DBOPFS lifecycle and emits `user-entity-loaded`.
276
276
 
277
+ ### AI_name
278
+
279
+ Saved AI-name preference alongside `AI_personality`. It is a string with an
280
+ empty-string default and preserves the complete supplied text, including
281
+ Unicode, whitespace, and an explicitly empty value. The property setter follows
282
+ the same persistence setting as `AI_personality`; non-string assignments throw
283
+ `Error('AI_name must be string')`.
284
+
285
+ `explicit`, `toJSON()`, `load()`, `refresh()`, and `updateExplicit()` include
286
+ this field through the existing profile schema. Loading an older record that
287
+ omits it leaves a new entity's empty default in memory and does not rewrite the
288
+ stored record. Partial updates that omit it retain the current value.
289
+
290
+ ```javascript
291
+ await user.updateExplicit(
292
+ {AI_name: 'Captain Moonboots'}
293
+ );
294
+ ```
295
+
296
+ The application owns naming choices and any mapping to its AI display name;
297
+ this preference changes neither the human `username` nor chat history. No
298
+ automatic migration or naming policy runs when it is loaded or saved.
299
+
277
300
  ### updateExplicit(update)
278
301
 
279
302
  Accepts an ordinary partial profile object, a JSON string, or a function
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -387,6 +387,21 @@
387
387
  background:var(--background);
388
388
  }
389
389
 
390
+ .file-preview-message[data-role="user"]{
391
+ background:var(--arcane-action,var(--primary-color));
392
+ color:var(--arcane-action-text,var(--button-text-color,var(--text-color)));
393
+ border-color:var(--arcane-action,var(--primary-color));
394
+ }
395
+
396
+ .file-preview-message[data-role="user"] a{
397
+ color:inherit;
398
+ }
399
+
400
+ .file-preview-message[data-role="assistant"]{
401
+ background:var(--arcane-surface,var(--background));
402
+ color:var(--text-color);
403
+ }
404
+
390
405
  .file-preview-message header,
391
406
  .file-preview-message footer{
392
407
  display:flex;
@@ -1740,9 +1755,15 @@
1740
1755
  const time=document.createElement('time');
1741
1756
  article.className='file-preview-message';
1742
1757
  article.dataset.role=message.role;
1743
- speaker.textContent=message.name===undefined
1744
- ?message.role
1745
- :`${message.name} · ${message.role}`;
1758
+ if(message.role==='assistant'){
1759
+ speaker.textContent=is.string(message.name)&&message.name.trim()
1760
+ ?message.name
1761
+ :'AI';
1762
+ }else{
1763
+ speaker.textContent=message.name===undefined
1764
+ ?message.role
1765
+ :`${message.name} · ${message.role}`;
1766
+ }
1746
1767
  header.append(speaker);
1747
1768
  if(message.timestamp===undefined||message.timestamp===null){
1748
1769
  time.textContent='Time unavailable';
@@ -110,6 +110,7 @@ function userEntityLifecycleError(code,reason,message){
110
110
  * @property {string|number} contact_4
111
111
  * @property {string|number} contact_5
112
112
  * @property {string|number} contact_6
113
+ * @property {string} AI_name
113
114
  * @property {string} AI_personality
114
115
  * @property {string} religion
115
116
  * @property {string} AI_voice
@@ -176,6 +177,7 @@ class UserEntity {
176
177
  'contact_5',
177
178
  'contact_6',
178
179
 
180
+ 'AI_name',
179
181
  'AI_personality',
180
182
  'religion',
181
183
  'AI_voice',
@@ -211,6 +213,7 @@ class UserEntity {
211
213
  #contact_5 = '';
212
214
  #contact_6 = '';
213
215
 
216
+ #aiName = '';
214
217
  #AI_personality = '';
215
218
  #religion = '';
216
219
  #AI_voice = '';
@@ -515,6 +518,22 @@ class UserEntity {
515
518
 
516
519
 
517
520
 
521
+ /** @returns {string} */
522
+ get AI_name() {
523
+ return this.#aiName;
524
+ }
525
+
526
+ /** @param {string} v */
527
+ set AI_name(v) {
528
+ if (!is.string(v)) {
529
+ throw new Error('AI_name must be string');
530
+ }
531
+
532
+ this.#aiName = v;
533
+
534
+ this.#persist();
535
+ }
536
+
518
537
  /** @returns {string} */
519
538
  get AI_personality(){
520
539
  return this.#AI_personality;
@@ -889,6 +908,7 @@ class UserEntity {
889
908
  this.persist=persist;
890
909
  }
891
910
 
911
+ baseline = this.explicit;
892
912
  const conditional=is.function(src);
893
913
  const update=conditional?await src(this.explicit):src;
894
914
  if(conditional&&update===null){