arcane-os 0.1.0-dev.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 (248) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/COMMERCIAL-LICENSE.md +13 -0
  3. package/LICENSE +661 -0
  4. package/NOTICE +70 -0
  5. package/README.md +448 -0
  6. package/bin/arcane-test.mjs +741 -0
  7. package/bin/arcane.mjs +5 -0
  8. package/docs/architecture.md +234 -0
  9. package/docs/compatibility.md +36 -0
  10. package/docs/event-manager.md +166 -0
  11. package/docs/platform-targets.md +108 -0
  12. package/docs/publishing.md +203 -0
  13. package/docs/reference/README.md +117 -0
  14. package/docs/reference/arcane-ollama.md +288 -0
  15. package/docs/reference/availability-and-normalization.md +123 -0
  16. package/docs/reference/behavioral-testing.md +86 -0
  17. package/docs/reference/cli.md +569 -0
  18. package/docs/reference/core/README.md +62 -0
  19. package/docs/reference/core/arcane-ai-contracts.md +873 -0
  20. package/docs/reference/core/arcane-api.md +601 -0
  21. package/docs/reference/core/arcane-entities.md +65 -0
  22. package/docs/reference/core/arcane-events.md +134 -0
  23. package/docs/reference/core/ollama-module.md +181 -0
  24. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  25. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  26. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  27. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  28. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  29. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  30. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  31. package/docs/reference/event-manager.md +957 -0
  32. package/docs/reference/inventory/package-api.json +2632 -0
  33. package/docs/reference/inventory/runtime-components.json +934 -0
  34. package/docs/reference/inventory/runtime-entities.json +26 -0
  35. package/docs/reference/inventory/runtime-modules.json +1249 -0
  36. package/docs/reference/protocols.md +242 -0
  37. package/docs/reference/runtime-components.md +1098 -0
  38. package/docs/reference/runtime-entities.md +303 -0
  39. package/docs/reference/runtime-modules.md +2010 -0
  40. package/docs/reference/sdk-api.md +4901 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +124 -0
  43. package/node_modules/event-pubsub/CHANGELOG.md +55 -0
  44. package/node_modules/event-pubsub/MIGRATION.md +70 -0
  45. package/node_modules/event-pubsub/README.md +363 -0
  46. package/node_modules/event-pubsub/SECURITY.md +37 -0
  47. package/node_modules/event-pubsub/index.js +141 -0
  48. package/node_modules/event-pubsub/licence +21 -0
  49. package/node_modules/event-pubsub/package.json +59 -0
  50. package/node_modules/strong-type/README.md +408 -0
  51. package/node_modules/strong-type/assets/strong-type-header.png +0 -0
  52. package/node_modules/strong-type/index.js +1151 -0
  53. package/node_modules/strong-type/licence +21 -0
  54. package/node_modules/strong-type/node.js +125 -0
  55. package/node_modules/strong-type/package.json +61 -0
  56. package/package.json +95 -0
  57. package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
  58. package/runtime/arcane/components/app-bar.html +468 -0
  59. package/runtime/arcane/components/assistant-panel.html +715 -0
  60. package/runtime/arcane/components/calculator.html +8 -0
  61. package/runtime/arcane/components/chart.html +655 -0
  62. package/runtime/arcane/components/chat.html +1225 -0
  63. package/runtime/arcane/components/conversation-view.html +13 -0
  64. package/runtime/arcane/components/dashboard-config.html +341 -0
  65. package/runtime/arcane/components/data-maintenance.html +112 -0
  66. package/runtime/arcane/components/data-view.html +92 -0
  67. package/runtime/arcane/components/directory-picker.html +197 -0
  68. package/runtime/arcane/components/document-inspector.html +252 -0
  69. package/runtime/arcane/components/file-drop.html +264 -0
  70. package/runtime/arcane/components/file-inspector.html +293 -0
  71. package/runtime/arcane/components/file-manager.html +1715 -0
  72. package/runtime/arcane/components/header.html +142 -0
  73. package/runtime/arcane/components/integration-settings.html +14 -0
  74. package/runtime/arcane/components/local-ai-status.html +360 -0
  75. package/runtime/arcane/components/markdown-document.html +1048 -0
  76. package/runtime/arcane/components/markdown-editor.html +360 -0
  77. package/runtime/arcane/components/media-embed.html +8 -0
  78. package/runtime/arcane/components/modal.html +402 -0
  79. package/runtime/arcane/components/output-panel.html +259 -0
  80. package/runtime/arcane/components/preferences-form.html +135 -0
  81. package/runtime/arcane/components/record-timeline.html +105 -0
  82. package/runtime/arcane/components/relationship-board.html +116 -0
  83. package/runtime/arcane/components/screen-capture.html +8 -0
  84. package/runtime/arcane/components/source-code-viewer.html +441 -0
  85. package/runtime/arcane/components/source-explanation.html +124 -0
  86. package/runtime/arcane/components/speech.html +365 -0
  87. package/runtime/arcane/components/summary-strip.html +177 -0
  88. package/runtime/arcane/components/table.html +77 -0
  89. package/runtime/arcane/components/task-progress.html +282 -0
  90. package/runtime/arcane/components/terminal-workspace.html +65 -0
  91. package/runtime/arcane/components/theme-editor.html +41 -0
  92. package/runtime/arcane/components/theme-switcher.html +46 -0
  93. package/runtime/arcane/components/unified-inbox.html +20 -0
  94. package/runtime/arcane/components/voice-transcription.html +476 -0
  95. package/runtime/arcane/components/weather-widget.html +8 -0
  96. package/runtime/arcane/components/web-navigator.html +239 -0
  97. package/runtime/arcane/css/communications.css +1 -0
  98. package/runtime/arcane/css/dashboard-config.css +45 -0
  99. package/runtime/arcane/css/document-site.css +981 -0
  100. package/runtime/arcane/css/layout.css +438 -0
  101. package/runtime/arcane/css/primitives.css +321 -0
  102. package/runtime/arcane/css/theme.css +112 -0
  103. package/runtime/arcane/css/utility-workspace.css +1 -0
  104. package/runtime/arcane/entities/ApiModelRecord.js +20 -0
  105. package/runtime/arcane/entities/Calculation.js +13 -0
  106. package/runtime/arcane/entities/Chat.js +581 -0
  107. package/runtime/arcane/entities/CommunicationMessage.js +29 -0
  108. package/runtime/arcane/entities/CommunicationThread.js +21 -0
  109. package/runtime/arcane/entities/Document.js +10 -0
  110. package/runtime/arcane/entities/File.js +143 -0
  111. package/runtime/arcane/entities/Image.js +135 -0
  112. package/runtime/arcane/entities/IntentEnvelope.js +834 -0
  113. package/runtime/arcane/entities/Preference.js +83 -0
  114. package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
  115. package/runtime/arcane/entities/TerminalSession.js +46 -0
  116. package/runtime/arcane/entities/Theme.js +107 -0
  117. package/runtime/arcane/entities/User.js +1046 -0
  118. package/runtime/arcane/entities/Weather.js +23 -0
  119. package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
  120. package/runtime/arcane/img/arrow-left.png +0 -0
  121. package/runtime/arcane/img/arrow-right.png +0 -0
  122. package/runtime/arcane/img/doc.svg +5 -0
  123. package/runtime/arcane/img/folder.svg +4 -0
  124. package/runtime/arcane/img/image.svg +5 -0
  125. package/runtime/arcane/img/refresh.png +0 -0
  126. package/runtime/arcane/img/send.svg +9 -0
  127. package/runtime/arcane/img/trash.svg +5 -0
  128. package/runtime/arcane/img/upload.svg +5 -0
  129. package/runtime/arcane/modules/AI.js +2048 -0
  130. package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
  131. package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
  132. package/runtime/arcane/modules/AIResponseLength.js +42 -0
  133. package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
  134. package/runtime/arcane/modules/AnsiText.js +53 -0
  135. package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
  136. package/runtime/arcane/modules/AppDataScope.js +245 -0
  137. package/runtime/arcane/modules/AppearancePreferences.js +28 -0
  138. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
  139. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
  140. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
  141. package/runtime/arcane/modules/AsyncBoundary.js +161 -0
  142. package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
  143. package/runtime/arcane/modules/CalculatorEngine.js +20 -0
  144. package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
  145. package/runtime/arcane/modules/ChartLibrary.js +35 -0
  146. package/runtime/arcane/modules/ChatRecords.js +13 -0
  147. package/runtime/arcane/modules/CommunicationAppController.js +43 -0
  148. package/runtime/arcane/modules/CommunicationHub.js +16 -0
  149. package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
  150. package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
  151. package/runtime/arcane/modules/ComponentContracts.js +586 -0
  152. package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
  153. package/runtime/arcane/modules/ConversationActionItems.js +488 -0
  154. package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
  155. package/runtime/arcane/modules/ConversationTimebox.js +527 -0
  156. package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
  157. package/runtime/arcane/modules/DBLS.js +171 -0
  158. package/runtime/arcane/modules/DBOPFS.js +1154 -0
  159. package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
  160. package/runtime/arcane/modules/DataMaintenance.js +91 -0
  161. package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
  162. package/runtime/arcane/modules/DirectoryPicker.js +109 -0
  163. package/runtime/arcane/modules/DocumentNavigation.js +223 -0
  164. package/runtime/arcane/modules/Errors.js +1025 -0
  165. package/runtime/arcane/modules/GifEncoder.js +29 -0
  166. package/runtime/arcane/modules/HTMLImport.js +114 -0
  167. package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
  168. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
  169. package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
  170. package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
  171. package/runtime/arcane/modules/MD.js +111 -0
  172. package/runtime/arcane/modules/Mail.js +352 -0
  173. package/runtime/arcane/modules/MailTransport.mjs +180 -0
  174. package/runtime/arcane/modules/Marked.min.js +71 -0
  175. package/runtime/arcane/modules/MemoryRecords.js +44 -0
  176. package/runtime/arcane/modules/MessageAdvisory.js +38 -0
  177. package/runtime/arcane/modules/ModelDefinition.js +189 -0
  178. package/runtime/arcane/modules/Ollama.js +74 -0
  179. package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
  180. package/runtime/arcane/modules/OllamaSettings.js +24 -0
  181. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
  182. package/runtime/arcane/modules/PreferenceStore.js +109 -0
  183. package/runtime/arcane/modules/QRCode.min.js +1 -0
  184. package/runtime/arcane/modules/Questionnaire.js +61 -0
  185. package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
  186. package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
  187. package/runtime/arcane/modules/RecordReviewStore.js +94 -0
  188. package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
  189. package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
  190. package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
  191. package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
  192. package/runtime/arcane/modules/ScreenCapture.js +20 -0
  193. package/runtime/arcane/modules/SpeechPlayback.js +581 -0
  194. package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
  195. package/runtime/arcane/modules/SystemAppearance.js +20 -0
  196. package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
  197. package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
  198. package/runtime/arcane/modules/TerminalClient.js +52 -0
  199. package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
  200. package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
  201. package/runtime/arcane/modules/ThemeManager.js +131 -0
  202. package/runtime/arcane/modules/TimeGuard.js +149 -0
  203. package/runtime/arcane/modules/ToolCallRouter.js +83 -0
  204. package/runtime/arcane/modules/WaitForComponent.js +102 -0
  205. package/runtime/arcane/modules/YouTubeMedia.js +16 -0
  206. package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
  207. package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
  208. package/runtime/arcane/modules/uPlot.min.css +1 -0
  209. package/runtime/arcane/security/arcane-network-policy.json +6 -0
  210. package/runtime/strong-type/index.js +352 -0
  211. package/runtime/strong-type/licence +21 -0
  212. package/runtime/strong-type/package.json +45 -0
  213. package/schemas/arcane-app-bundle.schema.json +125 -0
  214. package/schemas/arcane-app.schema.json +329 -0
  215. package/schemas/arcane-lock.schema.json +86 -0
  216. package/schemas/arcane-package.schema.json +224 -0
  217. package/schemas/cli-event.schema.json +122 -0
  218. package/schemas/event-stack.schema.json +152 -0
  219. package/schemas/native-build-plan.schema.json +176 -0
  220. package/schemas/target-adapter.schema.json +117 -0
  221. package/src/app-descriptor.mjs +500 -0
  222. package/src/cli/main.mjs +561 -0
  223. package/src/constants.mjs +31 -0
  224. package/src/dev-server.mjs +718 -0
  225. package/src/doctor.mjs +315 -0
  226. package/src/dom-event-instrumentation.mjs +594 -0
  227. package/src/errors.mjs +75 -0
  228. package/src/event-manager.mjs +1342 -0
  229. package/src/event-queue.mjs +138 -0
  230. package/src/events.mjs +219 -0
  231. package/src/index.mjs +177 -0
  232. package/src/integrated-provider-loader.mjs +432 -0
  233. package/src/native-plan.mjs +698 -0
  234. package/src/native-provider-loader.mjs +1126 -0
  235. package/src/packager/core.mjs +2691 -0
  236. package/src/process.mjs +353 -0
  237. package/src/release-bundle.mjs +2523 -0
  238. package/src/repository.mjs +90 -0
  239. package/src/runtime.mjs +452 -0
  240. package/src/scaffold.mjs +380 -0
  241. package/src/targets/index.mjs +436 -0
  242. package/src/templates/assets/app-icon.png +0 -0
  243. package/src/templates/workspace-template.mjs +388 -0
  244. package/src/testing-loader.mjs +9 -0
  245. package/src/testing.mjs +427 -0
  246. package/src/toolchain.mjs +1335 -0
  247. package/src/update-check.mjs +307 -0
  248. package/src/workspace.mjs +449 -0
@@ -0,0 +1,626 @@
1
+ import {marked} from './Marked.min.js';
2
+
3
+ const BARE_HTTP_URL_PATTERN=/\bhttps?:\/\/[^\s<>\[\]"'`]+/giu;
4
+ const BARE_WWW_URL_PATTERN=/\bwww\.[^\s<>\[\]"'`]+/giu;
5
+ const BARE_EMAIL_PATTERN=/\b[A-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?(?:\.[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?)+\b/giu;
6
+ const HTML_LINK_ATTRIBUTE_PATTERN=/\b(?:href|src|action|formaction|poster|data)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/giu;
7
+ const HTML_SRCSET_ATTRIBUTE_PATTERN=/\bsrcset\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/giu;
8
+ const CSS_URL_PATTERN=/\burl\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\s*\)/giu;
9
+ const MARKDOWN_AUTOLINK_PATTERN=/<((?:[a-z][a-z0-9+.-]{1,31}):[^<>\s]+|[^<>\s@]+@[^<>\s@]+\.[^<>\s@]+)>/giu;
10
+ const MARKDOWN_ESCAPED_PUNCTUATION_PATTERN=
11
+ /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/gu;
12
+ const RENDERED_BLOCK_BOUNDARY_PATTERN=
13
+ /<\/?(?:address|article|aside|blockquote|br|caption|dd|details|dialog|div|dl|dt|fieldset|figcaption|figure|footer|form|h[1-6]|header|hr|li|main|nav|ol|p|pre|section|summary|table|tbody|td|tfoot|th|thead|tr|ul)\b[^>]*>/giu;
14
+ const RENDERED_TAG_PATTERN=/<[^>]*>/gu;
15
+ const INVISIBLE_FORMATTING_PATTERN=/\p{Default_Ignorable_Code_Point}+/gu;
16
+ const INVISIBLE_TEXT_CONTROL_PATTERN=
17
+ /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]+/gu;
18
+
19
+ function decodeNamedCharacterReference(match,name){
20
+ const normalized=String(name).toLowerCase();
21
+ const values={
22
+ af:'\u2061',
23
+ amp:'&',
24
+ applyfunction:'\u2061',
25
+ apos:"'",
26
+ ast:'*',
27
+ bsol:'\\',
28
+ colon:':',
29
+ comma:',',
30
+ commat:'@',
31
+ dollar:'$',
32
+ equals:'=',
33
+ excl:'!',
34
+ gt:'>',
35
+ ic:'\u2063',
36
+ invisiblecomma:'\u2063',
37
+ invisibletimes:'\u2062',
38
+ it:'\u2062',
39
+ lpar:'(',
40
+ lrm:'\u200e',
41
+ lt:'<',
42
+ lowbar:'_',
43
+ negativemediumspace:'\u200b',
44
+ negativethickspace:'\u200b',
45
+ negativethinspace:'\u200b',
46
+ negativeverythinspace:'\u200b',
47
+ nobreak:'\u2060',
48
+ num:'#',
49
+ percnt:'%',
50
+ period:'.',
51
+ plus:'+',
52
+ quest:'?',
53
+ quot:'"',
54
+ rlm:'\u200f',
55
+ rpar:')',
56
+ semi:';',
57
+ shy:'\u00ad',
58
+ sol:'/',
59
+ vert:'|',
60
+ zerowidthspace:'\u200b',
61
+ zwj:'\u200d',
62
+ zwnj:'\u200c'
63
+ };
64
+
65
+ return Object.hasOwn(values,normalized)?values[normalized]:match;
66
+ }
67
+
68
+ function decodeNumericCharacterReference(match,hexadecimal,decimal){
69
+ const raw=hexadecimal||decimal;
70
+ const radix=hexadecimal?16:10;
71
+ const codePoint=Number.parseInt(raw,radix);
72
+
73
+ if(
74
+ !Number.isInteger(codePoint)
75
+ ||codePoint<1
76
+ ||codePoint>0x10FFFF
77
+ ||(codePoint>=0xD800&&codePoint<=0xDFFF)
78
+ ){
79
+ return match;
80
+ }
81
+
82
+ return String.fromCodePoint(codePoint);
83
+ }
84
+
85
+ function decodeHTMLCharacterReferences(value=''){
86
+ return String(value).replace(
87
+ /&(?:(af|amp|applyfunction|apos|ast|bsol|colon|comma|commat|dollar|equals|excl|gt|ic|invisiblecomma|invisibletimes|it|lpar|lrm|lt|lowbar|negativemediumspace|negativethickspace|negativethinspace|negativeverythinspace|nobreak|num|percnt|period|plus|quest|quot|rlm|rpar|semi|shy|sol|vert|zerowidthspace|zwj|zwnj);|#x([0-9a-f]+);?|#([0-9]+);?)/gi,
88
+ function decodeOneCharacterReference(match,name,hexadecimal,decimal){
89
+ return name
90
+ ?decodeNamedCharacterReference(match,name)
91
+ :decodeNumericCharacterReference(
92
+ match,
93
+ hexadecimal,
94
+ decimal
95
+ );
96
+ }
97
+ );
98
+ }
99
+
100
+ function countCharacter(value,character){
101
+ let count=0;
102
+
103
+ for(const candidate of value){
104
+ if(candidate===character){
105
+ count++;
106
+ }
107
+ }
108
+
109
+ return count;
110
+ }
111
+
112
+ function trimUnbalancedClosingCharacters(value=''){
113
+ let result=String(value);
114
+ const pairs=[
115
+ ['(',')'],
116
+ ['[',']'],
117
+ ['{','}']
118
+ ];
119
+
120
+ for(const [opening,closing] of pairs){
121
+ while(
122
+ result.endsWith(closing)
123
+ &&countCharacter(result,closing)>countCharacter(result,opening)
124
+ ){
125
+ result=result.slice(0,-1);
126
+ }
127
+ }
128
+
129
+ return result;
130
+ }
131
+
132
+ function trimBareLinkCandidate(value=''){
133
+ let result=decodeHTMLCharacterReferences(value).trim();
134
+
135
+ result=trimUnbalancedClosingCharacters(result);
136
+ while(/[.,;:!?]$/u.test(result)){
137
+ result=result.slice(0,-1);
138
+ result=trimUnbalancedClosingCharacters(result);
139
+ }
140
+
141
+ return result;
142
+ }
143
+
144
+ function normalizeAIResponseLink(value='',{bare=false}={}){
145
+ let result=bare
146
+ ?trimBareLinkCandidate(value)
147
+ :decodeHTMLCharacterReferences(value).trim();
148
+
149
+ if(result.startsWith('<')&&result.endsWith('>')){
150
+ result=result.slice(1,-1).trim();
151
+ }
152
+
153
+ if(/^mailto:/iu.test(result)){
154
+ return `mailto:${result.slice(7)}`;
155
+ }
156
+ if(/^tel:/iu.test(result)){
157
+ return `tel:${result.slice(4)}`;
158
+ }
159
+
160
+ return result;
161
+ }
162
+
163
+ function normalizeMarkdownDestination(value=''){
164
+ return String(value).replace(
165
+ MARKDOWN_ESCAPED_PUNCTUATION_PATTERN,
166
+ '$1'
167
+ );
168
+ }
169
+
170
+ function extractMarkdownInlineDestination(text='',openingIndex=0){
171
+ let index=openingIndex+2;
172
+
173
+ while(index<text.length&&/\s/u.test(text[index])){
174
+ index++;
175
+ }
176
+
177
+ if(index>=text.length){
178
+ return null;
179
+ }
180
+
181
+ if(text[index]==='<'){
182
+ const end=text.indexOf('>',index+1);
183
+
184
+ if(end<0){
185
+ return null;
186
+ }
187
+
188
+ return {
189
+ value:text.slice(index+1,end),
190
+ start:index+1,
191
+ end
192
+ };
193
+ }
194
+
195
+ const start=index;
196
+ let nestedParentheses=0;
197
+
198
+ while(index<text.length){
199
+ const character=text[index];
200
+
201
+ if(character==='\\'&&index+1<text.length){
202
+ index+=2;
203
+ continue;
204
+ }
205
+ if(/\s/u.test(character)&&nestedParentheses===0){
206
+ break;
207
+ }
208
+ if(character==='('){
209
+ nestedParentheses++;
210
+ }else if(character===')'){
211
+ if(nestedParentheses===0){
212
+ break;
213
+ }
214
+ nestedParentheses--;
215
+ }
216
+ index++;
217
+ }
218
+
219
+ if(index===start){
220
+ return null;
221
+ }
222
+
223
+ return {
224
+ value:text.slice(start,index),
225
+ start,
226
+ end:index
227
+ };
228
+ }
229
+
230
+ function extractSrcsetCandidates(value=''){
231
+ const candidates=[];
232
+
233
+ for(const entry of String(value).split(',')){
234
+ const candidate=entry.trim().split(/\s+/u)[0];
235
+
236
+ if(candidate){
237
+ candidates.push(candidate);
238
+ }
239
+ }
240
+
241
+ return candidates;
242
+ }
243
+
244
+ function extractMarkdownReferenceDestinations(text=''){
245
+ const source=String(text);
246
+ const destinations=[];
247
+ let lineStart=0;
248
+
249
+ while(lineStart<source.length){
250
+ let lineEnd=source.indexOf('\n',lineStart);
251
+
252
+ if(lineEnd<0){
253
+ lineEnd=source.length;
254
+ }
255
+
256
+ let index=lineStart;
257
+ let indentation=0;
258
+ while(index<lineEnd&&source[index]===' '&&indentation<4){
259
+ index++;
260
+ indentation++;
261
+ }
262
+
263
+ if(indentation<=3&&source[index]==='['){
264
+ index++;
265
+
266
+ while(index<lineEnd){
267
+ if(source[index]==='\\'&&index+1<lineEnd){
268
+ index+=2;
269
+ continue;
270
+ }
271
+ if(source[index]===']'){
272
+ break;
273
+ }
274
+ index++;
275
+ }
276
+
277
+ if(source[index]===']'&&source[index+1]===':'){
278
+ index+=2;
279
+ while(index<lineEnd&&/[ \t]/u.test(source[index])){
280
+ index++;
281
+ }
282
+
283
+ if(index>=lineEnd||source[index]==='\r'){
284
+ const continuationStart=lineEnd+1;
285
+ let continuationIndex=continuationStart;
286
+
287
+ while(
288
+ continuationIndex<source.length
289
+ &&/[ \t]/u.test(source[continuationIndex])
290
+ ){
291
+ continuationIndex++;
292
+ }
293
+
294
+ if(continuationIndex>continuationStart){
295
+ index=continuationIndex;
296
+ lineEnd=source.indexOf('\n',index);
297
+ if(lineEnd<0){
298
+ lineEnd=source.length;
299
+ }
300
+ }
301
+ }
302
+
303
+ if(index<lineEnd&&source[index]!=='\r'){
304
+ const start=source[index]==='<'?index+1:index;
305
+ let end=start;
306
+
307
+ if(source[index]==='<'){
308
+ end=source.indexOf('>',start);
309
+ if(end<0||end>lineEnd){
310
+ end=start;
311
+ }
312
+ }else{
313
+ while(end<lineEnd&&!/\s/u.test(source[end])){
314
+ end++;
315
+ }
316
+ }
317
+
318
+ if(end>start){
319
+ destinations.push({
320
+ value:source.slice(start,end),
321
+ start,
322
+ end
323
+ });
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ lineStart=lineEnd+1;
330
+ }
331
+
332
+ return destinations;
333
+ }
334
+
335
+ function extractRenderedMarkdownLinks(text=''){
336
+ const rendered=marked.parse(String(text),{
337
+ async:false,
338
+ gfm:true,
339
+ pedantic:false
340
+ });
341
+ const links=[];
342
+
343
+ for(const match of rendered.matchAll(HTML_LINK_ATTRIBUTE_PATTERN)){
344
+ links.push({
345
+ value:match[1]??match[2]??match[3]??'',
346
+ start:match.index||0,
347
+ kind:'rendered-html-attribute'
348
+ });
349
+ }
350
+
351
+ for(const match of rendered.matchAll(HTML_SRCSET_ATTRIBUTE_PATTERN)){
352
+ const value=match[1]??match[2]??match[3]??'';
353
+
354
+ for(const candidate of extractSrcsetCandidates(value)){
355
+ links.push({
356
+ value:candidate,
357
+ start:match.index||0,
358
+ kind:'rendered-html-srcset'
359
+ });
360
+ }
361
+ }
362
+
363
+ const visibleText=decodeHTMLCharacterReferences(
364
+ rendered
365
+ .replace(RENDERED_BLOCK_BOUNDARY_PATTERN,' ')
366
+ .replace(RENDERED_TAG_PATTERN,'')
367
+ )
368
+ .replace(INVISIBLE_FORMATTING_PATTERN,'')
369
+ .replace(INVISIBLE_TEXT_CONTROL_PATTERN,'');
370
+ const visibleWebRanges=[];
371
+
372
+ function isInsideVisibleWebRange(index){
373
+ return visibleWebRanges.some(function containsVisibleIndex(range){
374
+ return index>=range.start&&index<range.end;
375
+ });
376
+ }
377
+
378
+ for(const match of visibleText.matchAll(BARE_HTTP_URL_PATTERN)){
379
+ const start=match.index||0;
380
+
381
+ visibleWebRanges.push({start,end:start+match[0].length});
382
+ links.push({
383
+ value:match[0],
384
+ start,
385
+ kind:'rendered-visible-http',
386
+ bare:true
387
+ });
388
+ }
389
+
390
+ for(const match of visibleText.matchAll(BARE_WWW_URL_PATTERN)){
391
+ const start=match.index||0;
392
+
393
+ if(isInsideVisibleWebRange(start)){
394
+ continue;
395
+ }
396
+ visibleWebRanges.push({start,end:start+match[0].length});
397
+ links.push({
398
+ value:`http://${match[0]}`,
399
+ start,
400
+ kind:'rendered-visible-www',
401
+ bare:true
402
+ });
403
+ }
404
+
405
+ for(const match of visibleText.matchAll(BARE_EMAIL_PATTERN)){
406
+ const start=match.index||0;
407
+
408
+ if(isInsideVisibleWebRange(start)){
409
+ continue;
410
+ }
411
+ links.push({
412
+ value:`mailto:${match[0]}`,
413
+ start,
414
+ kind:'rendered-visible-email',
415
+ bare:false
416
+ });
417
+ }
418
+
419
+ return links;
420
+ }
421
+
422
+ /**
423
+ * Returns both authored URL-like text and destinations produced by the same
424
+ * Markdown parser used by Arcane chat. Values stay exact after renderer-level
425
+ * entity and escape decoding; URL canonicalization would weaken provenance.
426
+ */
427
+ function extractAIResponseLinks(text=''){
428
+ const source=String(text);
429
+ const links=[];
430
+ const seen=new Set();
431
+ const webRanges=[];
432
+ const structuredRanges=[];
433
+
434
+ function addCandidate(
435
+ value,
436
+ start=0,
437
+ kind='unknown',
438
+ bare=false,
439
+ allowEmpty=false
440
+ ){
441
+ const normalized=normalizeAIResponseLink(value,{bare});
442
+
443
+ if((!normalized&&!allowEmpty)||seen.has(normalized)){
444
+ return false;
445
+ }
446
+
447
+ seen.add(normalized);
448
+ links.push(Object.freeze({value:normalized,start,kind}));
449
+ return true;
450
+ }
451
+
452
+ function isInsideWebRange(index){
453
+ return webRanges.some(function containsIndex(range){
454
+ return index>=range.start&&index<range.end;
455
+ });
456
+ }
457
+
458
+ function isInsideStructuredRange(index){
459
+ return structuredRanges.some(function containsIndex(range){
460
+ return index>=range.start&&index<range.end;
461
+ });
462
+ }
463
+
464
+ function addStructuredCandidate(value,start,end,kind){
465
+ structuredRanges.push({start,end});
466
+ return addCandidate(value,start,kind,false);
467
+ }
468
+
469
+ let markdownIndex=source.indexOf('](');
470
+ while(markdownIndex>=0){
471
+ const destination=extractMarkdownInlineDestination(
472
+ source,
473
+ markdownIndex
474
+ );
475
+
476
+ if(destination){
477
+ addStructuredCandidate(
478
+ normalizeMarkdownDestination(destination.value),
479
+ destination.start,
480
+ destination.end,
481
+ 'markdown-inline',
482
+ );
483
+ }
484
+ markdownIndex=source.indexOf('](',markdownIndex+2);
485
+ }
486
+
487
+ for(const destination of extractMarkdownReferenceDestinations(source)){
488
+ addStructuredCandidate(
489
+ normalizeMarkdownDestination(destination.value),
490
+ destination.start,
491
+ destination.end,
492
+ 'markdown-reference',
493
+ );
494
+ }
495
+
496
+ for(const match of source.matchAll(MARKDOWN_AUTOLINK_PATTERN)){
497
+ const value=match[1].includes('@')&&!/^[a-z][a-z0-9+.-]*:/iu.test(match[1])
498
+ ?`mailto:${match[1]}`
499
+ :match[1];
500
+
501
+ const start=(match.index||0)+1;
502
+
503
+ addStructuredCandidate(
504
+ value,
505
+ start,
506
+ start+match[1].length,
507
+ 'markdown-autolink'
508
+ );
509
+ }
510
+
511
+ for(const match of source.matchAll(HTML_LINK_ATTRIBUTE_PATTERN)){
512
+ const value=match[1]??match[2]??match[3]??'';
513
+ const offset=match[0].indexOf(value);
514
+
515
+ const start=(match.index||0)+Math.max(0,offset);
516
+
517
+ addStructuredCandidate(
518
+ value,
519
+ start,
520
+ start+value.length,
521
+ 'html-attribute',
522
+ );
523
+ }
524
+
525
+ for(const match of source.matchAll(HTML_SRCSET_ATTRIBUTE_PATTERN)){
526
+ const value=match[1]??match[2]??match[3]??'';
527
+ const offset=(match.index||0)+Math.max(0,match[0].indexOf(value));
528
+
529
+ structuredRanges.push({start:offset,end:offset+value.length});
530
+
531
+ for(const candidate of extractSrcsetCandidates(value)){
532
+ addCandidate(candidate,offset,'html-srcset',false);
533
+ }
534
+ }
535
+
536
+ for(const match of source.matchAll(CSS_URL_PATTERN)){
537
+ const value=match[1]??match[2]??match[3]??'';
538
+ const offset=match[0].indexOf(value);
539
+ const start=(match.index||0)+Math.max(0,offset);
540
+
541
+ addStructuredCandidate(
542
+ value,
543
+ start,
544
+ start+value.length,
545
+ 'css-url'
546
+ );
547
+ }
548
+
549
+ for(const match of source.matchAll(BARE_HTTP_URL_PATTERN)){
550
+ const raw=match[0];
551
+ const start=match.index||0;
552
+
553
+ webRanges.push({start,end:start+raw.length});
554
+ if(!isInsideStructuredRange(start)){
555
+ addCandidate(raw,start,'bare-http',true);
556
+ }
557
+ }
558
+
559
+ for(const match of source.matchAll(BARE_WWW_URL_PATTERN)){
560
+ const start=match.index||0;
561
+
562
+ if(!isInsideWebRange(start)&&!isInsideStructuredRange(start)){
563
+ addCandidate(`http://${match[0]}`,start,'bare-www',true);
564
+ }
565
+ }
566
+
567
+ for(const match of source.matchAll(BARE_EMAIL_PATTERN)){
568
+ const start=match.index||0;
569
+
570
+ if(!isInsideWebRange(start)&&!isInsideStructuredRange(start)){
571
+ addCandidate(`mailto:${match[0]}`,start,'bare-email',false);
572
+ }
573
+ }
574
+
575
+ for(const renderedLink of extractRenderedMarkdownLinks(source)){
576
+ addCandidate(
577
+ renderedLink.value,
578
+ source.length+renderedLink.start,
579
+ renderedLink.kind,
580
+ renderedLink.bare===true,
581
+ true
582
+ );
583
+ }
584
+
585
+ links.sort(function sortLinksByPosition(left,right){
586
+ return left.start-right.start||left.value.localeCompare(right.value);
587
+ });
588
+
589
+ return Object.freeze(links);
590
+ }
591
+
592
+ function normalizeAllowedLinks(allowedLinks=[]){
593
+ const normalized=new Set();
594
+
595
+ for(const value of allowedLinks||[]){
596
+ const link=normalizeAIResponseLink(value);
597
+
598
+ if(link){
599
+ normalized.add(link);
600
+ }
601
+ }
602
+
603
+ return normalized;
604
+ }
605
+
606
+ function auditAIResponseLinks(text='',allowedLinks=[]){
607
+ const links=extractAIResponseLinks(text);
608
+ const allowed=normalizeAllowedLinks(allowedLinks);
609
+ const unsupportedLinks=links.filter(function isUnsupported(link){
610
+ return !allowed.has(link.value);
611
+ });
612
+
613
+ return Object.freeze({
614
+ ok:unsupportedLinks.length===0,
615
+ links,
616
+ unsupportedLinks:Object.freeze(unsupportedLinks),
617
+ allowedLinks:Object.freeze(Array.from(allowed))
618
+ });
619
+ }
620
+
621
+ export {
622
+ auditAIResponseLinks,
623
+ decodeHTMLCharacterReferences,
624
+ extractAIResponseLinks,
625
+ normalizeAIResponseLink
626
+ };
@@ -0,0 +1,53 @@
1
+ const ANSI_PATTERN=/\x1b\[([0-9;?]*)([ -\/]*)([@-~])/g;
2
+ const COLORS=['black','red','green','yellow','blue','magenta','cyan','white'];
3
+
4
+ function freshStyle(){ return {bold:false,dim:false,italic:false,underline:false,inverse:false,foreground:null,background:null}; }
5
+ function snapshot(style){ return Object.freeze({...style}); }
6
+
7
+ function applyCodes(style,raw=''){
8
+ const codes=(raw?raw.split(';'):['0']).map(value=>Number(value||0));
9
+ for(let index=0;index<codes.length;index+=1){
10
+ const code=codes[index];
11
+ if(code===0) Object.assign(style,freshStyle());
12
+ else if(code===1) style.bold=true;
13
+ else if(code===2) style.dim=true;
14
+ else if(code===3) style.italic=true;
15
+ else if(code===4) style.underline=true;
16
+ else if(code===7) style.inverse=true;
17
+ else if(code===22){style.bold=false;style.dim=false;}
18
+ else if(code===23) style.italic=false;
19
+ else if(code===24) style.underline=false;
20
+ else if(code===27) style.inverse=false;
21
+ else if(code===39) style.foreground=null;
22
+ else if(code===49) style.background=null;
23
+ else if(code>=30&&code<=37) style.foreground=COLORS[code-30];
24
+ else if(code>=40&&code<=47) style.background=COLORS[code-40];
25
+ else if(code>=90&&code<=97) style.foreground=`bright-${COLORS[code-90]}`;
26
+ else if(code>=100&&code<=107) style.background=`bright-${COLORS[code-100]}`;
27
+ else if((code===38||code===48)&&codes[index+1]===5&&Number.isInteger(codes[index+2])){
28
+ style[code===38?'foreground':'background']=`index-${Math.max(0,Math.min(255,codes[index+2]))}`;
29
+ index+=2;
30
+ }
31
+ }
32
+ }
33
+
34
+ export function parseAnsi(input=''){
35
+ const text=String(input??'');
36
+ const tokens=[];
37
+ const style=freshStyle();
38
+ let cursor=0;
39
+ let match;
40
+ ANSI_PATTERN.lastIndex=0;
41
+ while((match=ANSI_PATTERN.exec(text))){
42
+ if(match.index>cursor) tokens.push(Object.freeze({text:text.slice(cursor,match.index),style:snapshot(style)}));
43
+ if(match[3]==='m') applyCodes(style,match[1]);
44
+ cursor=ANSI_PATTERN.lastIndex;
45
+ }
46
+ if(cursor<text.length) tokens.push(Object.freeze({text:text.slice(cursor),style:snapshot(style)}));
47
+ return Object.freeze(tokens);
48
+ }
49
+
50
+ export function stripAnsi(input=''){
51
+ ANSI_PATTERN.lastIndex=0;
52
+ return String(input??'').replace(ANSI_PATTERN,'');
53
+ }
@@ -0,0 +1,25 @@
1
+ import ApiModelRecord from '../entities/ApiModelRecord.js';
2
+
3
+ function event(type,detail){return new CustomEvent(type,{detail});}
4
+ function endpoint(value){const url=new URL(String(value||''));if(!['http:','https:'].includes(url.protocol))throw new TypeError('API model endpoints must use HTTP or HTTPS.');return url.href;}
5
+ function appendParameters(url,parameters={}){for(const [key,value] of Object.entries(parameters||{})){if(value===undefined||value===null||value==='')continue;url.searchParams.set(key,Array.isArray(value)?value.join(','):String(value));}return url;}
6
+ function publicEndpoint(url){const safe=new URL(url);for(const key of [...safe.searchParams.keys()])if(/(?:auth|key|password|secret|token)/i.test(key))safe.searchParams.set(key,'[redacted]');return safe.href;}
7
+
8
+ export default class ApiModelDatabase extends EventTarget{
9
+ constructor({endpoint:source,parser=value=>value,fetchImpl=globalThis.fetch,cache=null,request={}}={}){super();this.endpoint=endpoint(source);if(typeof parser!=='function')throw new TypeError('API model parser must be a function.');if(typeof fetchImpl!=='function')throw new TypeError('API model fetch implementation must be a function.');this.parser=parser;this.fetchImpl=fetchImpl;this.cache=cache;this.request={...request};this.latest=null;}
10
+ setEndpoint(value){this.endpoint=endpoint(value);return this.endpoint;}
11
+ async fetch(parameters={},context={}){
12
+ const url=appendParameters(new URL(this.endpoint),parameters);const visibleEndpoint=publicEndpoint(url);const requestId=globalThis.crypto?.randomUUID?.()||`${Date.now()}-${Math.random().toString(16).slice(2)}`;
13
+ this.dispatchEvent(event('api-model-request',{requestId,endpoint:visibleEndpoint}));
14
+ try{
15
+ const response=await this.fetchImpl(url,{method:'GET',...this.request,headers:{Accept:'application/json',...(this.request.headers||{})}});const raw=await response.json();
16
+ if(!response.ok)throw new Error(raw?.reason||raw?.error||`API request failed (${response.status}).`);
17
+ const value=await this.parser(raw,{context,endpoint:url.href,response:{status:response.status,headers:response.headers}});const record=new ApiModelRecord({endpoint:visibleEndpoint,value,metadata:{requestId,status:response.status}});this.latest=record;
18
+ if(this.cache?.set)await this.cache.set(visibleEndpoint,record.toJSON());
19
+ this.dispatchEvent(event('api-model-success',{requestId,record}));return record;
20
+ }catch(error){this.dispatchEvent(event('api-model-error',{requestId,endpoint:visibleEndpoint,error}));throw error;}
21
+ }
22
+ async cached(parameters={}){const url=appendParameters(new URL(this.endpoint),parameters);if(!this.cache?.get)return null;const value=await this.cache.get(publicEndpoint(url));return value?new ApiModelRecord(value):null;}
23
+ }
24
+
25
+ export {appendParameters,publicEndpoint};