@openvulcan/dsh-vulcancode 0.0.0-stage → 0.4.3

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 (176) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -2
  3. package/assets/openvulcan-icon.svg +33 -0
  4. package/cordis.patch.yml +19 -0
  5. package/node_modules/@openvulcan/dsh-decision-guard/LICENSE +21 -0
  6. package/node_modules/@openvulcan/dsh-decision-guard/README.md +14 -0
  7. package/node_modules/@openvulcan/dsh-decision-guard/assets/decision-guard-icon.png +0 -0
  8. package/node_modules/@openvulcan/dsh-decision-guard/lib/calls.d.ts +40 -0
  9. package/node_modules/@openvulcan/dsh-decision-guard/lib/calls.js +150 -0
  10. package/node_modules/@openvulcan/dsh-decision-guard/lib/client.js +2250 -0
  11. package/node_modules/@openvulcan/dsh-decision-guard/lib/decide.d.ts +90 -0
  12. package/node_modules/@openvulcan/dsh-decision-guard/lib/decide.js +108 -0
  13. package/node_modules/@openvulcan/dsh-decision-guard/lib/index.d.ts +129 -0
  14. package/node_modules/@openvulcan/dsh-decision-guard/lib/index.js +572 -0
  15. package/node_modules/@openvulcan/dsh-decision-guard/lib/intent.d.ts +22 -0
  16. package/node_modules/@openvulcan/dsh-decision-guard/lib/intent.js +77 -0
  17. package/node_modules/@openvulcan/dsh-decision-guard/lib/panel.d.ts +158 -0
  18. package/node_modules/@openvulcan/dsh-decision-guard/lib/panel.js +340 -0
  19. package/node_modules/@openvulcan/dsh-decision-guard/lib/records.d.ts +133 -0
  20. package/node_modules/@openvulcan/dsh-decision-guard/lib/records.js +186 -0
  21. package/node_modules/@openvulcan/dsh-decision-guard/lib/review.d.ts +55 -0
  22. package/node_modules/@openvulcan/dsh-decision-guard/lib/review.js +202 -0
  23. package/node_modules/@openvulcan/dsh-decision-guard/lib/session-state.d.ts +62 -0
  24. package/node_modules/@openvulcan/dsh-decision-guard/lib/session-state.js +155 -0
  25. package/node_modules/@openvulcan/dsh-decision-guard/lib/version.d.ts +2 -0
  26. package/node_modules/@openvulcan/dsh-decision-guard/lib/version.js +4 -0
  27. package/node_modules/@openvulcan/dsh-decision-guard/package.json +68 -0
  28. package/node_modules/@openvulcan/dsh-vulcan-account/LICENSE +21 -0
  29. package/node_modules/@openvulcan/dsh-vulcan-account/assets/account-icon.png +0 -0
  30. package/node_modules/@openvulcan/dsh-vulcan-account/lib/client.js +573 -0
  31. package/node_modules/@openvulcan/dsh-vulcan-account/lib/index.d.ts +92 -0
  32. package/node_modules/@openvulcan/dsh-vulcan-account/lib/index.js +194 -0
  33. package/node_modules/@openvulcan/dsh-vulcan-account/package.json +57 -0
  34. package/node_modules/@openvulcan/dsh-vulcan-answers/LICENSE +21 -0
  35. package/node_modules/@openvulcan/dsh-vulcan-answers/assets/answers-icon.png +0 -0
  36. package/node_modules/@openvulcan/dsh-vulcan-answers/assets/prompts/answer-mode-interactive.md +79 -0
  37. package/node_modules/@openvulcan/dsh-vulcan-answers/assets/prompts/answer-mode-standard.md +1 -0
  38. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/answer-model.d.ts +258 -0
  39. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/answer-model.js +698 -0
  40. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/client.js +671 -0
  41. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/fences.d.ts +29 -0
  42. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/fences.js +70 -0
  43. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/index.d.ts +19 -0
  44. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/index.js +52 -0
  45. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/limits.d.ts +9 -0
  46. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/limits.js +9 -0
  47. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/prompt.d.ts +22 -0
  48. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/prompt.js +39 -0
  49. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/reply-format.d.ts +20 -0
  50. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/reply-format.js +17 -0
  51. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/session-state.d.ts +66 -0
  52. package/node_modules/@openvulcan/dsh-vulcan-answers/lib/session-state.js +118 -0
  53. package/node_modules/@openvulcan/dsh-vulcan-answers/package.json +59 -0
  54. package/node_modules/@openvulcan/dsh-vulcan-luaskills/LICENSE +21 -0
  55. package/node_modules/@openvulcan/dsh-vulcan-luaskills/assets/luaskills-icon.svg +1 -0
  56. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/client.js +949 -0
  57. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/constants.d.ts +46 -0
  58. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/constants.js +51 -0
  59. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/engine.d.ts +55 -0
  60. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/engine.js +149 -0
  61. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/hub.d.ts +49 -0
  62. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/hub.js +116 -0
  63. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/index.d.ts +26 -0
  64. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/index.js +276 -0
  65. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/protocol.d.ts +65 -0
  66. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/protocol.js +2 -0
  67. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/runtime.d.ts +111 -0
  68. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/runtime.js +281 -0
  69. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/sdk-install.d.ts +26 -0
  70. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/sdk-install.js +87 -0
  71. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/settings.d.ts +79 -0
  72. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/settings.js +165 -0
  73. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/skills.d.ts +34 -0
  74. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/skills.js +61 -0
  75. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/tools.d.ts +59 -0
  76. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/tools.js +107 -0
  77. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/worker.d.ts +10 -0
  78. package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/worker.js +140 -0
  79. package/node_modules/@openvulcan/dsh-vulcan-luaskills/package.json +57 -0
  80. package/node_modules/@openvulcan/dsh-vulcan-memory/LICENSE +21 -0
  81. package/node_modules/@openvulcan/dsh-vulcan-memory/assets/markdown-memory-guide.md +21 -0
  82. package/node_modules/@openvulcan/dsh-vulcan-memory/assets/memory-curator/SKILL.md +31 -0
  83. package/node_modules/@openvulcan/dsh-vulcan-memory/assets/memory-icon.png +0 -0
  84. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/client.js +1090 -0
  85. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/index.d.ts +30 -0
  86. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/index.js +240 -0
  87. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/inject.d.ts +30 -0
  88. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/inject.js +46 -0
  89. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/constants.d.ts +23 -0
  90. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/constants.js +25 -0
  91. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/document.d.ts +108 -0
  92. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/document.js +373 -0
  93. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/errors.d.ts +14 -0
  94. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/errors.js +31 -0
  95. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/index.d.ts +196 -0
  96. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/index.js +204 -0
  97. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/operations.d.ts +92 -0
  98. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/operations.js +472 -0
  99. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/package.d.ts +126 -0
  100. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/package.js +553 -0
  101. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/registry.d.ts +56 -0
  102. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/registry.js +182 -0
  103. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/scope.d.ts +13 -0
  104. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/scope.js +24 -0
  105. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/search.d.ts +65 -0
  106. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/search.js +227 -0
  107. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/snapshot.d.ts +34 -0
  108. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/snapshot.js +171 -0
  109. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/store.d.ts +72 -0
  110. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/store.js +250 -0
  111. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/timestamp.d.ts +6 -0
  112. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/timestamp.js +12 -0
  113. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/tokens.d.ts +8 -0
  114. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/tokens.js +38 -0
  115. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/page.d.ts +132 -0
  116. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/page.js +235 -0
  117. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/project.d.ts +14 -0
  118. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/project.js +27 -0
  119. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/settings.d.ts +29 -0
  120. package/node_modules/@openvulcan/dsh-vulcan-memory/lib/settings.js +62 -0
  121. package/node_modules/@openvulcan/dsh-vulcan-memory/package.json +63 -0
  122. package/node_modules/@openvulcan/dsh-vulcan-reasoning/LICENSE +21 -0
  123. package/node_modules/@openvulcan/dsh-vulcan-reasoning/lib/client.js +509 -0
  124. package/node_modules/@openvulcan/dsh-vulcan-reasoning/lib/index.d.ts +6 -0
  125. package/node_modules/@openvulcan/dsh-vulcan-reasoning/lib/index.js +8 -0
  126. package/node_modules/@openvulcan/dsh-vulcan-reasoning/package.json +42 -0
  127. package/node_modules/@openvulcan/dsh-vulcan-style/LICENSE +21 -0
  128. package/node_modules/@openvulcan/dsh-vulcan-style/assets/style-icon.png +0 -0
  129. package/node_modules/@openvulcan/dsh-vulcan-style/lib/client.js +1121 -0
  130. package/node_modules/@openvulcan/dsh-vulcan-style/lib/index.d.ts +34 -0
  131. package/node_modules/@openvulcan/dsh-vulcan-style/lib/index.js +42 -0
  132. package/node_modules/@openvulcan/dsh-vulcan-style/package.json +51 -0
  133. package/node_modules/@openvulcan/openvulcan-account/LICENSE +21 -0
  134. package/node_modules/@openvulcan/openvulcan-account/lib/account.d.ts +140 -0
  135. package/node_modules/@openvulcan/openvulcan-account/lib/account.js +347 -0
  136. package/node_modules/@openvulcan/openvulcan-account/lib/index.d.ts +1 -0
  137. package/node_modules/@openvulcan/openvulcan-account/lib/index.js +1 -0
  138. package/node_modules/@openvulcan/openvulcan-account/package.json +29 -0
  139. package/node_modules/@openvulcan/vulcan-decision/LICENSE +21 -0
  140. package/node_modules/@openvulcan/vulcan-decision/README.md +23 -0
  141. package/node_modules/@openvulcan/vulcan-decision/bin/vulcan-decision.js +4 -0
  142. package/node_modules/@openvulcan/vulcan-decision/lib/cli.d.ts +5 -0
  143. package/node_modules/@openvulcan/vulcan-decision/lib/cli.js +267 -0
  144. package/node_modules/@openvulcan/vulcan-decision/lib/cloud/edge.d.ts +211 -0
  145. package/node_modules/@openvulcan/vulcan-decision/lib/cloud/edge.js +594 -0
  146. package/node_modules/@openvulcan/vulcan-decision/lib/download.d.ts +36 -0
  147. package/node_modules/@openvulcan/vulcan-decision/lib/download.js +99 -0
  148. package/node_modules/@openvulcan/vulcan-decision/lib/engine.d.ts +37 -0
  149. package/node_modules/@openvulcan/vulcan-decision/lib/engine.js +39 -0
  150. package/node_modules/@openvulcan/vulcan-decision/lib/hardware.d.ts +105 -0
  151. package/node_modules/@openvulcan/vulcan-decision/lib/hardware.js +207 -0
  152. package/node_modules/@openvulcan/vulcan-decision/lib/home.d.ts +26 -0
  153. package/node_modules/@openvulcan/vulcan-decision/lib/home.js +54 -0
  154. package/node_modules/@openvulcan/vulcan-decision/lib/index.d.ts +17 -0
  155. package/node_modules/@openvulcan/vulcan-decision/lib/index.js +17 -0
  156. package/node_modules/@openvulcan/vulcan-decision/lib/local/engine.d.ts +54 -0
  157. package/node_modules/@openvulcan/vulcan-decision/lib/local/engine.js +157 -0
  158. package/node_modules/@openvulcan/vulcan-decision/lib/local/models.d.ts +126 -0
  159. package/node_modules/@openvulcan/vulcan-decision/lib/local/models.js +261 -0
  160. package/node_modules/@openvulcan/vulcan-decision/lib/local/packs.d.ts +102 -0
  161. package/node_modules/@openvulcan/vulcan-decision/lib/local/packs.js +195 -0
  162. package/node_modules/@openvulcan/vulcan-decision/lib/local/worker.d.ts +61 -0
  163. package/node_modules/@openvulcan/vulcan-decision/lib/local/worker.js +123 -0
  164. package/node_modules/@openvulcan/vulcan-decision/lib/protocol.d.ts +74 -0
  165. package/node_modules/@openvulcan/vulcan-decision/lib/protocol.js +31 -0
  166. package/node_modules/@openvulcan/vulcan-decision/lib/render.d.ts +15 -0
  167. package/node_modules/@openvulcan/vulcan-decision/lib/render.js +33 -0
  168. package/node_modules/@openvulcan/vulcan-decision/lib/version.d.ts +2 -0
  169. package/node_modules/@openvulcan/vulcan-decision/lib/version.js +4 -0
  170. package/node_modules/@openvulcan/vulcan-decision/package.json +40 -0
  171. package/node_modules/@openvulcan/vulcan-decision/python/vulcan_decision_worker.py +363 -0
  172. package/node_modules/@openvulcan/vulcan-decision/runtime-packs/onnx-cpu.json +627 -0
  173. package/node_modules/@openvulcan/vulcan-decision/runtime-packs/onnx-cuda.json +423 -0
  174. package/node_modules/@openvulcan/vulcan-decision/runtime-packs/torch-cpu.json +1047 -0
  175. package/node_modules/@openvulcan/vulcan-decision/runtime-packs/torch-cu128.json +647 -0
  176. package/package.json +55 -4
@@ -0,0 +1,949 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@openvulcan/dsh-vulcan-luaskills",
3
+ factory: (platformRequire) => {
4
+ var definitions = {
5
+ "./dsh-client": function (module, exports, require) {
6
+ "use strict";
7
+ /**
8
+ * The parts of dsh's browser runtime this client half uses.
9
+ *
10
+ * dsh serves these modules from its page module table; their packages are not published at the
11
+ * Host's version, so the shapes are restated here from dsh 0.2.1-rc.2 source and must be checked
12
+ * again when the supported dsh range moves:
13
+ * - `packages/client/ui-layout/src/client/index.ts` (the keyed `main` slot)
14
+ * - `packages/client/ui-sidebar/src/client/contract/slots.ts` (`sidebar.panellist`)
15
+ * - `packages/client/ui-settings/src/client/contract/slots.ts` (`settings.section`)
16
+ * - `packages/client/ui-settings-general/src/client/{index,shell-store}.ts` (`sidebar.settings` store)
17
+ * - `packages/client/locale/src/client/index.ts` (`bind`)
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+
21
+ },
22
+ "./i18n": function (module, exports, require) {
23
+ "use strict";
24
+ /**
25
+ * The plugin's interface text; dsh picks the dictionary that matches its interface language.
26
+ * Setting labels follow VulcanCode's `skills.luaSettings.*` catalog entries.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.en = exports.zh = exports.NAMESPACE = void 0;
30
+ exports.fill = fill;
31
+ exports.NAMESPACE = 'vulcan-luaskills';
32
+ exports.zh = {
33
+ 'nav': 'LuaSkills',
34
+ 'panel': 'LuaSkills',
35
+ /** Content language asked of the LuaSkills Hub. */
36
+ 'hubLang': 'zh-CN',
37
+ 'loading': '读取中…',
38
+ 'unavailable': '无法读取 LuaSkills 状态:dsh 没有向本页面提供插件接口。',
39
+ 'settingsPage.title': 'LuaSkills',
40
+ 'settingsPage.lead': 'LuaSkills 技能以工具形式提供给 AI。运行库按需安装,安装后自动接入,不需要重启 dsh。',
41
+ 'runtime.title': '运行库',
42
+ 'runtime.absent': '需要安装 LuaSkills 运行库',
43
+ 'runtime.absentLead': '运行库约 {size} MB,安装到 {location}。默认技能 codekit(代码导航)一并安装。',
44
+ 'runtime.install': '安装运行库',
45
+ 'runtime.cancel': '取消',
46
+ 'runtime.phase.sdk': '安装 SDK',
47
+ 'runtime.phase.core': '下载 LuaSkills 核心库',
48
+ 'runtime.phase.lua': '下载 Lua 运行包',
49
+ 'runtime.phase.engine': '启动引擎',
50
+ 'runtime.phase.skill': '安装默认技能 codekit',
51
+ 'runtime.step': '第 {index}/{count} 步',
52
+ 'runtime.bytes': '{received} / {total} MB',
53
+ 'runtime.bytesOnly': '{received} MB',
54
+ 'runtime.unpacking': '校验并解压中… {seconds} 秒',
55
+ 'runtime.ready': '运行中',
56
+ 'runtime.starting': '启动中…',
57
+ 'runtime.outdated': '已安装的运行库({installed})与本插件需要的版本({wanted})不同,需要重新安装。',
58
+ 'runtime.reinstall': '重新安装',
59
+ 'runtime.failed': '安装失败:{error}',
60
+ 'runtime.retry': '重试',
61
+ 'runtime.engineFailed': '引擎没有运行:{error}',
62
+ 'runtime.restart': '重启引擎',
63
+ 'runtime.remove': '移除运行库',
64
+ 'runtime.removeConfirm': '移除运行库会删除所有已安装的技能,设置会保留。确定移除?',
65
+ 'runtime.versions': 'SDK {sdk} · LuaSkills {luaskills} · Lua 运行包 {luaRuntime}',
66
+ 'runtime.location': '位置:{location}',
67
+ 'settings.title': 'VM 与运行设置',
68
+ 'settings.lead': '保存后引擎自动重启生效。',
69
+ 'settings.locked': '安装运行库后才能修改设置。',
70
+ 'settings.invalid': '设置文件无法读取,当前使用默认值:{error}',
71
+ 'settings.save': '保存设置',
72
+ 'settings.saving': '正在保存…',
73
+ 'settings.saved': '已保存,引擎已按新设置重启。',
74
+ 'settings.revert': '撤销修改',
75
+ 'settings.mainPool': '主 VM 池',
76
+ 'settings.runLuaPool': '隔离 runLua VM 池',
77
+ 'settings.poolHint': '最小值决定预热容量,最大值限制并发 VM 数,空闲时间控制多余 VM 的回收。',
78
+ 'settings.minSize': '最小 VM 数',
79
+ 'settings.maxSize': '最大 VM 数',
80
+ 'settings.idleTtl': '空闲回收(秒)',
81
+ 'settings.toolCache': '工具缓存',
82
+ 'settings.maxEntries': '最大条目数',
83
+ 'settings.defaultTtl': '默认 TTL(秒)',
84
+ 'settings.maxTtl': '最大 TTL(秒)',
85
+ 'settings.managedRuntime': 'Python / Node 受管运行时',
86
+ 'settings.managedRuntimeHint': '这些参数控制每个引擎的 Worker、持久会话与调用默认值。',
87
+ 'settings.managedWorkerPoolMax': '单环境最大 Worker 数',
88
+ 'settings.managedWorkerIdleTtl': 'Worker 空闲回收(秒)',
89
+ 'settings.managedSessionLimit': '单引擎持久会话上限',
90
+ 'settings.managedSessionBuffer': '单输出流默认缓冲字节数',
91
+ 'settings.managedInvokeTimeout': '默认调用超时(毫秒)',
92
+ 'settings.capabilities': '运行时能力',
93
+ 'settings.defaultEncoding': '默认文本编码',
94
+ 'settings.autoEncoding': '自动(跟随运行时)',
95
+ 'settings.skillManagementBridge': '允许 Lua 调用宿主技能管理桥接',
96
+ 'settings.managedIoCompat': '使用托管 IO 兼容层替换原生全局 IO',
97
+ 'settings.network': '网络',
98
+ 'settings.allowDownloads': '允许下载技能与依赖',
99
+ 'settings.githubBaseUrl': 'GitHub 网站基址',
100
+ 'settings.githubApiBaseUrl': 'GitHub API 基址',
101
+ 'settings.skillHubBaseUrl': 'LuaSkills Hub 基址',
102
+ 'settings.defaultPlaceholder': '默认:{url}',
103
+ 'settings.validationPositive': '容量、TTL 与空闲时间必须是大于 0 的整数。',
104
+ 'settings.validationPoolOrder': '每个 VM 池的最大 VM 数不能小于最小 VM 数。',
105
+ 'settings.validationCacheOrder': '最大缓存 TTL 不能小于默认缓存 TTL。',
106
+ 'settings.validationUrl': '地址必须是完整的 http 或 https 网址。',
107
+ 'page.lead': '技能以工具形式提供给 AI。在这里管理已安装的技能,或从 LuaSkills Hub 安装新技能。',
108
+ 'page.needRuntime': '需要先安装 LuaSkills 运行库,才能安装或管理技能。',
109
+ 'page.openSettings': '前往安装',
110
+ 'tab.installed': '已安装',
111
+ 'tab.hub': 'Hub',
112
+ 'installed.empty': '还没有安装技能。',
113
+ 'installed.refresh': '刷新',
114
+ 'installed.updateAll': '全部更新',
115
+ 'installed.layer.ROOT': '默认',
116
+ 'installed.layer.USER': '用户',
117
+ 'installed.disabled': '已停用',
118
+ 'installed.notLoaded': '未加载',
119
+ 'installed.tools': '{count} 个工具',
120
+ 'installed.enable': '启用',
121
+ 'installed.disable': '停用',
122
+ 'installed.update': '更新',
123
+ 'installed.uninstall': '卸载',
124
+ 'installed.uninstallConfirm': '卸载技能 {name}?',
125
+ 'installed.result': '{name}:{message}',
126
+ 'hub.site.global': '国际站',
127
+ 'hub.site.cn': '中国站',
128
+ 'hub.site.custom': '自定义',
129
+ 'hub.siteHint': '切换站点会保存设置并重启引擎。',
130
+ 'hub.search': '搜索技能,按回车',
131
+ 'hub.empty': '没有找到技能。',
132
+ 'hub.idle': '按回车搜索,或直接回车列出全部。',
133
+ 'hub.more': '加载更多',
134
+ 'hub.install': '安装',
135
+ 'hub.installed': '已安装',
136
+ 'hub.installing': '安装中…',
137
+ 'hub.translated': '译',
138
+ 'hub.translatedTitle': '由 Hub 翻译',
139
+ 'hub.features': '特性',
140
+ 'hub.readme': 'README',
141
+ 'hub.close': '关闭',
142
+ 'hub.version': '版本 {version}',
143
+ 'hub.repository': '仓库',
144
+ 'hub.details': '详情',
145
+ };
146
+ exports.en = {
147
+ 'nav': 'LuaSkills',
148
+ 'panel': 'LuaSkills',
149
+ 'hubLang': 'en',
150
+ 'loading': 'Loading…',
151
+ 'unavailable': 'Cannot read LuaSkills: dsh offers this page no plugin routes.',
152
+ 'settingsPage.title': 'LuaSkills',
153
+ 'settingsPage.lead': 'LuaSkills skills are tools the AI can call. The runtime is installed on demand and connects as soon as it is installed; dsh does not need a restart.',
154
+ 'runtime.title': 'Runtime',
155
+ 'runtime.absent': 'The LuaSkills runtime is not installed',
156
+ 'runtime.absentLead': 'About {size} MB, installed into {location}. The default skill codekit (code navigation) comes with it.',
157
+ 'runtime.install': 'Install runtime',
158
+ 'runtime.cancel': 'Cancel',
159
+ 'runtime.phase.sdk': 'Installing the SDK',
160
+ 'runtime.phase.core': 'Downloading the LuaSkills core',
161
+ 'runtime.phase.lua': 'Downloading the Lua runtime packages',
162
+ 'runtime.phase.engine': 'Starting the engine',
163
+ 'runtime.phase.skill': 'Installing the default skill codekit',
164
+ 'runtime.step': 'Step {index} of {count}',
165
+ 'runtime.bytes': '{received} / {total} MB',
166
+ 'runtime.bytesOnly': '{received} MB',
167
+ 'runtime.unpacking': 'Verifying and unpacking… {seconds} s',
168
+ 'runtime.ready': 'Running',
169
+ 'runtime.starting': 'Starting…',
170
+ 'runtime.outdated': 'The installed runtime ({installed}) is not the version this plugin needs ({wanted}); reinstall it.',
171
+ 'runtime.reinstall': 'Reinstall',
172
+ 'runtime.failed': 'The install failed: {error}',
173
+ 'runtime.retry': 'Retry',
174
+ 'runtime.engineFailed': 'The engine is not running: {error}',
175
+ 'runtime.restart': 'Restart engine',
176
+ 'runtime.remove': 'Remove runtime',
177
+ 'runtime.removeConfirm': 'Removing the runtime deletes every installed skill; settings are kept. Remove it?',
178
+ 'runtime.versions': 'SDK {sdk} · LuaSkills {luaskills} · Lua runtime {luaRuntime}',
179
+ 'runtime.location': 'Location: {location}',
180
+ 'settings.title': 'VM and runtime settings',
181
+ 'settings.lead': 'Saving restarts the engine with the new values.',
182
+ 'settings.locked': 'Install the runtime to change settings.',
183
+ 'settings.invalid': 'The settings file cannot be read; the defaults are in use: {error}',
184
+ 'settings.save': 'Save settings',
185
+ 'settings.saving': 'Saving…',
186
+ 'settings.saved': 'Saved; the engine restarted with the new settings.',
187
+ 'settings.revert': 'Undo changes',
188
+ 'settings.mainPool': 'Main VM Pool',
189
+ 'settings.runLuaPool': 'Isolated runLua VM Pool',
190
+ 'settings.poolHint': 'The minimum controls warm capacity, the maximum limits concurrent VMs, and idle time retires excess VMs.',
191
+ 'settings.minSize': 'Minimum VMs',
192
+ 'settings.maxSize': 'Maximum VMs',
193
+ 'settings.idleTtl': 'Idle Retirement (seconds)',
194
+ 'settings.toolCache': 'Tool Cache',
195
+ 'settings.maxEntries': 'Maximum Entries',
196
+ 'settings.defaultTtl': 'Default TTL (seconds)',
197
+ 'settings.maxTtl': 'Maximum TTL (seconds)',
198
+ 'settings.managedRuntime': 'Managed Python / Node Runtime',
199
+ 'settings.managedRuntimeHint': 'These values control per-engine workers, persistent sessions, and invoke defaults.',
200
+ 'settings.managedWorkerPoolMax': 'Maximum Workers per Environment',
201
+ 'settings.managedWorkerIdleTtl': 'Worker Idle Retirement (seconds)',
202
+ 'settings.managedSessionLimit': 'Persistent Sessions per Engine',
203
+ 'settings.managedSessionBuffer': 'Default Bytes per Output Stream',
204
+ 'settings.managedInvokeTimeout': 'Default Invoke Timeout (milliseconds)',
205
+ 'settings.capabilities': 'Runtime Capabilities',
206
+ 'settings.defaultEncoding': 'Default Text Encoding',
207
+ 'settings.autoEncoding': 'Automatic (runtime default)',
208
+ 'settings.skillManagementBridge': 'Allow Lua to call the host skill-management bridge',
209
+ 'settings.managedIoCompat': 'Replace native global IO with the managed IO compatibility layer',
210
+ 'settings.network': 'Network',
211
+ 'settings.allowDownloads': 'Allow skill and dependency downloads',
212
+ 'settings.githubBaseUrl': 'GitHub Website Base URL',
213
+ 'settings.githubApiBaseUrl': 'GitHub API Base URL',
214
+ 'settings.skillHubBaseUrl': 'LuaSkills Hub Base URL',
215
+ 'settings.defaultPlaceholder': 'Default: {url}',
216
+ 'settings.validationPositive': 'Pool sizes, TTL values, and idle time must be positive integers.',
217
+ 'settings.validationPoolOrder': 'The maximum VM count cannot be smaller than the minimum for either pool.',
218
+ 'settings.validationCacheOrder': 'The maximum cache TTL cannot be smaller than the default cache TTL.',
219
+ 'settings.validationUrl': 'Addresses must be complete http or https URLs.',
220
+ 'page.lead': 'Skills are tools the AI can call. Manage the installed ones here, or install new ones from the LuaSkills Hub.',
221
+ 'page.needRuntime': 'Install the LuaSkills runtime first to install or manage skills.',
222
+ 'page.openSettings': 'Go to install',
223
+ 'tab.installed': 'Installed',
224
+ 'tab.hub': 'Hub',
225
+ 'installed.empty': 'No skills are installed yet.',
226
+ 'installed.refresh': 'Refresh',
227
+ 'installed.updateAll': 'Update all',
228
+ 'installed.layer.ROOT': 'Default',
229
+ 'installed.layer.USER': 'User',
230
+ 'installed.disabled': 'Disabled',
231
+ 'installed.notLoaded': 'Not loaded',
232
+ 'installed.tools': '{count} tools',
233
+ 'installed.enable': 'Enable',
234
+ 'installed.disable': 'Disable',
235
+ 'installed.update': 'Update',
236
+ 'installed.uninstall': 'Uninstall',
237
+ 'installed.uninstallConfirm': 'Uninstall the skill {name}?',
238
+ 'installed.result': '{name}: {message}',
239
+ 'hub.site.global': 'Global',
240
+ 'hub.site.cn': 'China',
241
+ 'hub.site.custom': 'Custom',
242
+ 'hub.siteHint': 'Switching sites saves the settings and restarts the engine.',
243
+ 'hub.search': 'Search skills, press Enter',
244
+ 'hub.empty': 'No skills found.',
245
+ 'hub.idle': 'Press Enter to search, or Enter on its own to list everything.',
246
+ 'hub.more': 'Load more',
247
+ 'hub.install': 'Install',
248
+ 'hub.installed': 'Installed',
249
+ 'hub.installing': 'Installing…',
250
+ 'hub.translated': 'TR',
251
+ 'hub.translatedTitle': 'Translated by the Hub',
252
+ 'hub.features': 'Features',
253
+ 'hub.readme': 'README',
254
+ 'hub.close': 'Close',
255
+ 'hub.version': 'Version {version}',
256
+ 'hub.repository': 'Repository',
257
+ 'hub.details': 'Details',
258
+ };
259
+ /** Replace `{name}` placeholders. */
260
+ function fill(text, values) {
261
+ return text.replace(/\{(\w+)\}/g, (match, name) => (name in values ? String(values[name]) : match));
262
+ }
263
+
264
+ },
265
+ "./index": function (module, exports, require) {
266
+ "use strict";
267
+ Object.defineProperty(exports, "__esModule", { value: true });
268
+ exports.inject = void 0;
269
+ exports.apply = apply;
270
+ const jsx_runtime_1 = require("react/jsx-runtime");
271
+ /**
272
+ * Browser half of the LuaSkills plugin: Settings › LuaSkills (runtime and VM settings), and the
273
+ * LuaSkills page in the sidebar's panel list (installed skills and the Hub). dsh loads these files
274
+ * as one lazy factory; they may import only modules dsh serves to plugins.
275
+ */
276
+ const i18n_1 = require("./i18n");
277
+ const page_1 = require("./page");
278
+ const settings_1 = require("./settings");
279
+ const shared_1 = require("./shared");
280
+ const style_1 = require("./style");
281
+ exports.inject = ['slots', 'locale'];
282
+ function apply(ctx) {
283
+ const view = new shared_1.HostWatch(() => (0, shared_1.callHost)('GET', 'state').catch(() => null));
284
+ const openSettings = () => {
285
+ const shell = ctx.slots.entries('sidebar.settings')[0]?.store?.create();
286
+ shell?.actions.openSection(shared_1.SETTINGS_SECTION);
287
+ };
288
+ ctx.effect(() => (0, style_1.installStyle)(), 'vulcan-luaskills: stylesheet');
289
+ ctx.effect(() => ctx.locale.register(i18n_1.NAMESPACE, { zh: i18n_1.zh, en: i18n_1.en }), 'vulcan-luaskills: dictionaries');
290
+ ctx.effect(() => {
291
+ const stop = ctx.on('connection/reset', () => { view.refresh(); });
292
+ return () => {
293
+ stop();
294
+ view.close();
295
+ };
296
+ }, 'vulcan-luaskills: Host state');
297
+ // After the OpenVulcan account (24), before Market (40).
298
+ ctx.slots.inject('settings.section', () => ctx.slots.register({
299
+ name: 'settings.section',
300
+ id: shared_1.SETTINGS_SECTION,
301
+ order: 26,
302
+ label: () => ctx.locale.bind(i18n_1.NAMESPACE)('nav'),
303
+ locale: i18n_1.NAMESPACE,
304
+ inject: () => ({ view }),
305
+ }, ({ t, view: injected }) => (0, jsx_runtime_1.jsx)(settings_1.SettingsPage, { view: injected, t: t })));
306
+ // dsh 0.2.2 declares this optional slot. The injection waits on older hosts.
307
+ // dsh 0.2.2 声明了此可选插槽,旧版宿主上的注入会保持等待。
308
+ ctx.slots.inject('settings.section.icon', () => ctx.slots.register({
309
+ name: 'settings.section.icon',
310
+ id: shared_1.SETTINGS_SECTION,
311
+ }, LuaSkillsIcon));
312
+ ctx.slots.inject('main', () => ctx.slots.register({
313
+ name: 'main',
314
+ key: shared_1.PANEL_ID,
315
+ locale: i18n_1.NAMESPACE,
316
+ inject: () => ({ view, openSettings }),
317
+ }, ({ t, view: injected, openSettings: open }) => (0, jsx_runtime_1.jsx)(page_1.LuaSkillsPage, { view: injected, t: t, openSettings: open })));
318
+ // After Scheduled tasks (10).
319
+ ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({
320
+ name: 'sidebar.panellist',
321
+ id: shared_1.PANEL_ID,
322
+ order: 20,
323
+ locale: i18n_1.NAMESPACE,
324
+ label: () => ctx.locale.bind(i18n_1.NAMESPACE)('panel'),
325
+ }, LuaSkillsIcon));
326
+ }
327
+ /**
328
+ * Render the LuaSkills moon and brackets at the size requested by either navigation slot.
329
+ * 按设置或侧栏导航插槽要求的尺寸渲染 LuaSkills 的月亮与括号图标。
330
+ */
331
+ function LuaSkillsIcon({ size }) {
332
+ return ((0, jsx_runtime_1.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "8.5" }), (0, jsx_runtime_1.jsx)("circle", { cx: "16.2", cy: "7.8", r: "2.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M9.5 9.5 7 12l2.5 2.5M14.5 14.5 17 12" })] }));
333
+ }
334
+
335
+ },
336
+ "./page": function (module, exports, require) {
337
+ "use strict";
338
+ Object.defineProperty(exports, "__esModule", { value: true });
339
+ exports.LuaSkillsPage = LuaSkillsPage;
340
+ const jsx_runtime_1 = require("react/jsx-runtime");
341
+ /**
342
+ * The LuaSkills page the sidebar opens: installed skills, and the LuaSkills Hub. Without the
343
+ * runtime both tabs can be looked at, and every action points at the install in Settings.
344
+ */
345
+ const react_1 = require("react");
346
+ const i18n_1 = require("./i18n");
347
+ const runtime_1 = require("./runtime");
348
+ const shared_1 = require("./shared");
349
+ function LuaSkillsPage({ view, t, openSettings }) {
350
+ const live = (0, runtime_1.useRuntime)(view);
351
+ const [tab, setTab] = (0, react_1.useState)('installed');
352
+ const ready = live?.state.kind === 'ready';
353
+ // Installed skills, read again after every change; shared with the Hub tab's installed marks.
354
+ const [skills, setSkills] = (0, react_1.useState)(undefined);
355
+ const [skillsError, setSkillsError] = (0, react_1.useState)(undefined);
356
+ const [generation, setGeneration] = (0, react_1.useState)(0);
357
+ const reload = () => { setGeneration(value => value + 1); };
358
+ (0, react_1.useEffect)(() => {
359
+ if (live == null || !(0, shared_1.isInstalled)(live.state)) {
360
+ setSkills([]);
361
+ return undefined;
362
+ }
363
+ let current = true;
364
+ (0, shared_1.callHost)('GET', 'skills').then((rows) => {
365
+ if (!current)
366
+ return;
367
+ setSkills(rows);
368
+ setSkillsError(undefined);
369
+ }, (failure) => {
370
+ if (current)
371
+ setSkillsError((0, shared_1.messageOf)(failure));
372
+ });
373
+ return () => { current = false; };
374
+ }, [live?.state.kind, generation]);
375
+ return ((0, jsx_runtime_1.jsx)("div", { className: "vac vls-panel", children: (0, jsx_runtime_1.jsxs)("div", { className: "vac vac-page vls-panel-inner", "data-vulcan-settings-width": "full", children: [(0, jsx_runtime_1.jsxs)("header", { className: "vac-page-head", "data-vulcan-settings-header": true, children: [(0, jsx_runtime_1.jsx)("h2", { children: t('panel') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-lead", children: t('page.lead') })] }), live === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('loading') }) : null, live === null ? (0, jsx_runtime_1.jsx)("div", { className: "vac-alert bad", children: t('unavailable') }) : null, live != null && !ready ? ((0, jsx_runtime_1.jsxs)("div", { className: "vls-banner warn", children: [(0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: live.state.kind === 'installing' || live.state.kind === 'starting' ? t(`runtime.${live.state.kind === 'starting' ? 'starting' : `phase.${live.state.phase}`}`) : t('page.needRuntime') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn primary", onClick: openSettings, children: t('page.openSettings') })] })) : null, (0, jsx_runtime_1.jsx)("div", { className: "vls-tabs", role: "tablist", children: ['installed', 'hub'].map(name => ((0, jsx_runtime_1.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === name, className: tab === name ? 'vls-tab on' : 'vls-tab', onClick: () => { setTab(name); }, children: t(`tab.${name}`) }, name))) }), (0, jsx_runtime_1.jsx)("div", { hidden: tab !== 'installed', children: (0, jsx_runtime_1.jsx)(Installed, { skills: skills, error: skillsError, ready: ready, reload: reload, t: t }) }), (0, jsx_runtime_1.jsx)("div", { hidden: tab !== 'hub', children: (0, jsx_runtime_1.jsx)(Hub, { live: live ?? null, ready: ready, installed: skills ?? [], reload: reload, view: view, t: t }) })] }) }));
376
+ }
377
+ function Installed({ skills, error, ready, reload, t }) {
378
+ const [busy, setBusy] = (0, react_1.useState)(undefined);
379
+ const [notes, setNotes] = (0, react_1.useState)([]);
380
+ const run = (id, work) => {
381
+ setBusy(id);
382
+ setNotes([]);
383
+ work().catch((failure) => { setNotes([{ ok: false, text: (0, shared_1.messageOf)(failure) }]); }).finally(() => {
384
+ setBusy(undefined);
385
+ reload();
386
+ });
387
+ };
388
+ const update = async (skill) => {
389
+ try {
390
+ const result = await (0, shared_1.callHost)('POST', `skills/update?id=${encodeURIComponent(skill.skillId)}`);
391
+ setNotes(list => [...list, { ok: true, text: (0, i18n_1.fill)(t('installed.result'), { name: skill.name, message: result.message }) }]);
392
+ return true;
393
+ }
394
+ catch (failure) {
395
+ setNotes(list => [...list, { ok: false, text: (0, i18n_1.fill)(t('installed.result'), { name: skill.name, message: (0, shared_1.messageOf)(failure) }) }]);
396
+ return false;
397
+ }
398
+ };
399
+ // One after another, stopping at the first failure, as VulcanCode does.
400
+ const updateAll = () => {
401
+ setBusy('*');
402
+ setNotes([]);
403
+ void (async () => {
404
+ for (const skill of skills ?? []) {
405
+ if (skill.source === undefined)
406
+ continue;
407
+ if (!await update(skill))
408
+ break;
409
+ }
410
+ })().finally(() => {
411
+ setBusy(undefined);
412
+ reload();
413
+ });
414
+ };
415
+ if (skills === undefined)
416
+ return (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('loading') });
417
+ return ((0, jsx_runtime_1.jsxs)("section", { className: "vac-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-section-head", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("h3", { className: "vac-section-title", children: t('tab.installed') }) }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: busy !== undefined, onClick: reload, children: t('installed.refresh') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: !ready || busy !== undefined || skills.length === 0, onClick: updateAll, children: t('installed.updateAll') })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vac-section-body flush", children: [error === undefined ? null : (0, jsx_runtime_1.jsx)("p", { className: "vac-error vls-pad", children: error }), skills.length === 0 ? (0, jsx_runtime_1.jsx)("p", { className: "vac-hint vls-pad", children: t('installed.empty') }) : null, (0, jsx_runtime_1.jsx)("ul", { className: "vls-list", children: skills.map(skill => ((0, jsx_runtime_1.jsxs)("li", { className: "vls-row", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vls-row-main", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("strong", { children: skill.name }), (0, jsx_runtime_1.jsx)("span", { className: "vac-hint vac-mono", children: skill.version }), (0, jsx_runtime_1.jsx)("span", { className: "vac-badge outline", children: t(`installed.layer.${skill.root}`) }), !skill.enabled ? (0, jsx_runtime_1.jsx)("span", { className: "vac-badge warn", children: t('installed.disabled') })
418
+ : ready && !skill.loaded ? (0, jsx_runtime_1.jsx)("span", { className: "vac-badge bad", children: t('installed.notLoaded') }) : null] }), (0, jsx_runtime_1.jsxs)("p", { className: "vac-hint vac-mono", children: [skill.skillId, skill.source === undefined ? '' : ` · ${skill.source.type}:${skill.source.locator}`, skill.tools.length === 0 ? '' : ` · ${(0, i18n_1.fill)(t('installed.tools'), { count: skill.tools.length })}`] }), skill.tools.length === 0 ? null : (0, jsx_runtime_1.jsx)("p", { className: "vls-tools vac-mono", children: skill.tools.join(' ') })] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: !ready || busy !== undefined, onClick: () => { run(skill.skillId, () => (0, shared_1.callHost)('POST', `skills/enabled?id=${encodeURIComponent(skill.skillId)}&enabled=${String(!skill.enabled)}`)); }, children: skill.enabled ? t('installed.disable') : t('installed.enable') }), skill.source === undefined ? null : ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: !ready || busy !== undefined, onClick: () => { run(skill.skillId, () => update(skill)); }, children: t('installed.update') })), skill.root !== 'USER' ? null : ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm ghost danger", disabled: !ready || busy !== undefined, onClick: () => {
419
+ if (window.confirm((0, i18n_1.fill)(t('installed.uninstallConfirm'), { name: skill.name }))) {
420
+ run(skill.skillId, () => (0, shared_1.callHost)('POST', `skills/uninstall?id=${encodeURIComponent(skill.skillId)}`));
421
+ }
422
+ }, children: t('installed.uninstall') }))] })] }, `${skill.root}:${skill.skillId}`))) }), notes.length === 0 ? null : ((0, jsx_runtime_1.jsx)("div", { className: "vls-pad", children: notes.map((note, index) => (0, jsx_runtime_1.jsx)("p", { className: note.ok ? 'vac-hint' : 'vac-error', children: note.text }, index)) }))] })] }));
423
+ }
424
+ function Hub({ live, ready, installed, reload, view, t }) {
425
+ const [query, setQuery] = (0, react_1.useState)('');
426
+ const [items, setItems] = (0, react_1.useState)(undefined);
427
+ const [cursor, setCursor] = (0, react_1.useState)(null);
428
+ const [last, setLast] = (0, react_1.useState)('');
429
+ const [loading, setLoading] = (0, react_1.useState)(false);
430
+ const [error, setError] = (0, react_1.useState)(undefined);
431
+ const [installing, setInstalling] = (0, react_1.useState)(undefined);
432
+ const [detail, setDetail] = (0, react_1.useState)(undefined);
433
+ const [switching, setSwitching] = (0, react_1.useState)(false);
434
+ const lang = t('hubLang');
435
+ const hub = live?.settings.network.officialSkillHubBaseUrl;
436
+ const site = live?.hubSites.find(item => item.url === hub)?.site;
437
+ // The Hub limits searches per address, so it is asked only on Enter and on "load more".
438
+ const search = (text, after) => {
439
+ setLoading(true);
440
+ setError(undefined);
441
+ const params = new URLSearchParams({ q: text, lang });
442
+ if (after !== null)
443
+ params.set('cursor', after);
444
+ (0, shared_1.callHost)('GET', `hub/search?${params.toString()}`).then((page) => {
445
+ setItems(previous => (after === null ? page.items : [...previous ?? [], ...page.items]));
446
+ setCursor(page.nextCursor);
447
+ setLast(text);
448
+ }, (failure) => { setError((0, shared_1.messageOf)(failure)); }).finally(() => { setLoading(false); });
449
+ };
450
+ // A new site means a new catalog.
451
+ (0, react_1.useEffect)(() => {
452
+ setItems(undefined);
453
+ setCursor(null);
454
+ }, [hub]);
455
+ const submit = (event) => {
456
+ event.preventDefault();
457
+ search(query, null);
458
+ };
459
+ const install = (skill) => {
460
+ setInstalling(skill.skill_id);
461
+ setError(undefined);
462
+ (0, shared_1.callHost)('POST', `skills/install?id=${encodeURIComponent(skill.skill_id)}`).then(() => { reload(); }, (failure) => { setError((0, shared_1.messageOf)(failure)); }).finally(() => { setInstalling(undefined); });
463
+ };
464
+ const open = (skill) => {
465
+ setError(undefined);
466
+ (0, shared_1.callHost)('GET', `hub/skill?${new URLSearchParams({ id: skill.skill_id, lang }).toString()}`).then(setDetail, (failure) => { setError((0, shared_1.messageOf)(failure)); });
467
+ };
468
+ const switchSite = (url) => {
469
+ if (live == null || url === hub)
470
+ return;
471
+ setSwitching(true);
472
+ setError(undefined);
473
+ (0, shared_1.callHost)('POST', 'settings', { ...live.settings, network: { ...live.settings.network, officialSkillHubBaseUrl: url } })
474
+ .catch((failure) => { setError((0, shared_1.messageOf)(failure)); })
475
+ .finally(() => {
476
+ setSwitching(false);
477
+ view.refresh();
478
+ });
479
+ };
480
+ const installedIds = new Set(installed.map(skill => skill.skillId));
481
+ return ((0, jsx_runtime_1.jsxs)("section", { className: "vac-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-section-head", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "vac-section-title", children: "LuaSkills Hub" }), (0, jsx_runtime_1.jsx)("p", { className: "vac-section-lead vac-mono", children: hub })] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", title: t('hub.siteHint'), children: [live?.hubSites.map(item => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: site === item.site ? 'vls-seg on' : 'vls-seg', disabled: switching || !(0, shared_1.isInstalled)(live.state) || live.state.kind === 'starting', onClick: () => { switchSite(item.url); }, children: t(`hub.site.${item.site}`) }, item.site))), site === undefined && hub !== undefined ? (0, jsx_runtime_1.jsx)("span", { className: "vls-seg on", children: t('hub.site.custom') }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vac-section-body", children: [(0, jsx_runtime_1.jsx)("form", { onSubmit: submit, children: (0, jsx_runtime_1.jsx)("input", { className: "vls-input vls-search", type: "search", placeholder: t('hub.search'), value: query, onChange: (event) => { setQuery(event.target.value); } }) }), error === undefined ? null : (0, jsx_runtime_1.jsx)("p", { className: "vac-error", role: "alert", children: error }), items === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: loading ? t('loading') : t('hub.idle') }) : null, items !== undefined && items.length === 0 ? (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('hub.empty') }) : null, items === undefined || items.length === 0 ? null : ((0, jsx_runtime_1.jsx)("ul", { className: "vls-cards", children: items.map((skill) => {
482
+ const content = skill.content ?? undefined;
483
+ const summary = content?.summary || skill.summary;
484
+ const has = installedIds.has(skill.skill_id);
485
+ return ((0, jsx_runtime_1.jsxs)("li", { className: "vls-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-between", children: [(0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("strong", { children: skill.display_name || skill.skill_id }), skill.latest_version ? (0, jsx_runtime_1.jsx)("span", { className: "vac-hint vac-mono", children: skill.latest_version }) : null, content?.kind === 'translation' ? (0, jsx_runtime_1.jsx)("span", { className: "vac-badge info", title: t('hub.translatedTitle'), children: t('hub.translated') }) : null] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm ghost", onClick: () => { open(skill); }, children: t('hub.details') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: !ready || has || installing !== undefined, onClick: () => { install(skill); }, children: has ? t('hub.installed') : installing === skill.skill_id ? t('hub.installing') : t('hub.install') })] })] }), (0, jsx_runtime_1.jsx)("p", { className: "vac-hint vac-mono", children: [skill.skill_id, skill.publisher, skill.license].filter(Boolean).join(' · ') }), summary ? (0, jsx_runtime_1.jsx)("p", { className: "vls-summary", children: summary }) : null] }, skill.skill_id));
486
+ }) })), cursor === null ? null : ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn", disabled: loading, onClick: () => { search(last, cursor); }, children: loading ? t('loading') : t('hub.more') }))] }), detail === undefined ? null : (0, jsx_runtime_1.jsx)(HubDetailSheet, { detail: detail, close: () => { setDetail(undefined); }, t: t })] }));
487
+ }
488
+ function HubDetailSheet({ detail, close, t }) {
489
+ const content = detail.skill.content ?? detail.original ?? undefined;
490
+ const readme = content?.readme || detail.latest.readme;
491
+ (0, react_1.useEffect)(() => {
492
+ const onKey = (event) => { if (event.key === 'Escape')
493
+ close(); };
494
+ window.addEventListener('keydown', onKey);
495
+ return () => { window.removeEventListener('keydown', onKey); };
496
+ }, [close]);
497
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "vls-sheet", role: "dialog", "aria-modal": "true", "aria-label": detail.skill.display_name || detail.skill.skill_id, children: [(0, jsx_runtime_1.jsxs)("div", { className: "vls-sheet-head", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("strong", { children: detail.skill.display_name || detail.skill.skill_id }), (0, jsx_runtime_1.jsxs)("p", { className: "vac-hint vac-mono", children: [(0, i18n_1.fill)(t('hub.version'), { version: detail.latest.version }), " \u00B7 ", detail.skill.skill_id] })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", onClick: close, children: t('hub.close') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vls-sheet-body", children: [content?.intro ? (0, jsx_runtime_1.jsx)("p", { children: content.intro }) : null, content?.features !== undefined && content.features.length > 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h4", { children: t('hub.features') }), (0, jsx_runtime_1.jsx)("ul", { children: content.features.map((feature, index) => (0, jsx_runtime_1.jsx)("li", { children: feature }, index)) })] })) : null, detail.skill.repository_url ? ((0, jsx_runtime_1.jsx)("p", { children: (0, jsx_runtime_1.jsx)("a", { className: "vac-link", href: detail.skill.repository_url, target: "_blank", rel: "noopener noreferrer", children: t('hub.repository') }) })) : null, readme ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h4", { children: t('hub.readme') }), (0, jsx_runtime_1.jsx)("pre", { className: "vls-readme", children: readme })] })) : null] })] }));
498
+ }
499
+
500
+ },
501
+ "./runtime": function (module, exports, require) {
502
+ "use strict";
503
+ Object.defineProperty(exports, "__esModule", { value: true });
504
+ exports.useRuntime = useRuntime;
505
+ exports.RuntimeSection = RuntimeSection;
506
+ const jsx_runtime_1 = require("react/jsx-runtime");
507
+ /** The runtime section: install prompt, install progress, status, restart and removal. */
508
+ const react_1 = require("react");
509
+ const i18n_1 = require("./i18n");
510
+ const shared_1 = require("./shared");
511
+ /** Poll the Host while it is busy, so progress moves and the end shows on its own. */
512
+ function useRuntime(view) {
513
+ const live = (0, react_1.useSyncExternalStore)(view.subscribe, view.getSnapshot);
514
+ const busy = live != null && (live.state.kind === 'installing' || live.state.kind === 'starting');
515
+ (0, react_1.useEffect)(() => {
516
+ view.refresh();
517
+ if (!busy)
518
+ return undefined;
519
+ const timer = setInterval(() => { view.refresh(); }, 700);
520
+ return () => { clearInterval(timer); };
521
+ }, [view, busy]);
522
+ return live;
523
+ }
524
+ function RuntimeSection({ view, live, t }) {
525
+ const [busy, setBusy] = (0, react_1.useState)(false);
526
+ const [error, setError] = (0, react_1.useState)(undefined);
527
+ const act = (work) => {
528
+ setBusy(true);
529
+ setError(undefined);
530
+ work().catch((failure) => { setError((0, shared_1.messageOf)(failure)); }).finally(() => {
531
+ setBusy(false);
532
+ view.refresh();
533
+ });
534
+ };
535
+ const install = () => { act(() => (0, shared_1.callHost)('POST', 'install')); };
536
+ const remove = () => {
537
+ if (window.confirm(t('runtime.removeConfirm')))
538
+ act(() => (0, shared_1.callHost)('POST', 'remove'));
539
+ };
540
+ const state = live.state;
541
+ const now = Date.now();
542
+ // When this page first saw the current archive fully downloaded; the SDK then verifies and
543
+ // unpacks it with no progress of its own, so the time since is shown instead.
544
+ const downloaded = state.kind === 'installing' && state.total !== null && state.received >= state.total ? state.phase : undefined;
545
+ const unpackedFrom = (0, react_1.useRef)(undefined);
546
+ if (downloaded === undefined)
547
+ unpackedFrom.current = undefined;
548
+ else if (unpackedFrom.current?.phase !== downloaded)
549
+ unpackedFrom.current = { phase: downloaded, at: now };
550
+ const unpackingSince = unpackedFrom.current?.at;
551
+ let body;
552
+ switch (state.kind) {
553
+ case 'absent':
554
+ body = ((0, jsx_runtime_1.jsxs)("div", { className: "vls-banner", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('runtime.absent') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: (0, i18n_1.fill)(t('runtime.absentLead'), { size: live.sizeMb, location: live.location }) })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn primary", disabled: busy, onClick: install, children: t('runtime.install') })] }));
555
+ break;
556
+ case 'installing': {
557
+ const index = shared_1.PHASES.indexOf(state.phase);
558
+ const unpacking = unpackingSince !== undefined;
559
+ const share = !unpacking && state.total !== null && state.total > 0 ? Math.min(1, state.received / state.total) : null;
560
+ body = ((0, jsx_runtime_1.jsxs)("div", { className: "vls-progress", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-between", children: [(0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("span", { className: "vac-badge info", children: (0, i18n_1.fill)(t('runtime.step'), { index: index + 1, count: shared_1.PHASES.length }) }), (0, jsx_runtime_1.jsx)("strong", { children: t(`runtime.phase.${state.phase}`) }), unpacking ? ((0, jsx_runtime_1.jsx)("span", { className: "vac-hint", children: (0, i18n_1.fill)(t('runtime.unpacking'), { seconds: Math.max(0, Math.floor((now - unpackingSince) / 1000)) }) })) : null] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [state.received > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "vac-hint vac-mono", children: state.total === null
561
+ ? (0, i18n_1.fill)(t('runtime.bytesOnly'), { received: mb(state.received) })
562
+ : (0, i18n_1.fill)(t('runtime.bytes'), { received: mb(state.received), total: mb(state.total) }) })) : null, (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: busy, onClick: () => { act(() => (0, shared_1.callHost)('POST', 'install/cancel')); }, children: t('runtime.cancel') })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "vls-bar", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": share === null ? undefined : Math.round(share * 100), children: (0, jsx_runtime_1.jsx)("span", { className: share === null ? 'vls-bar-fill indeterminate' : 'vls-bar-fill', style: share === null ? undefined : { width: `${share * 100}%` } }) }), (0, jsx_runtime_1.jsx)("ol", { className: "vls-steps", children: shared_1.PHASES.map((phase, at) => ((0, jsx_runtime_1.jsx)("li", { className: at < index ? 'done' : at === index ? 'now' : '', children: t(`runtime.phase.${phase}`) }, phase))) })] }));
563
+ break;
564
+ }
565
+ case 'starting':
566
+ body = (0, jsx_runtime_1.jsxs)("div", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("span", { className: "vac-badge info", children: t('runtime.starting') }), (0, jsx_runtime_1.jsx)(Versions, { versions: live.versions, t: t })] });
567
+ break;
568
+ case 'ready':
569
+ body = ((0, jsx_runtime_1.jsxs)("div", { className: "vac-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("span", { className: "vac-badge ok", children: t('runtime.ready') }), (0, jsx_runtime_1.jsx)(Versions, { versions: live.versions, t: t })] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: busy, onClick: () => { act(() => (0, shared_1.callHost)('POST', 'restart')); }, children: t('runtime.restart') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm ghost danger", disabled: busy, onClick: remove, children: t('runtime.remove') })] })] }));
570
+ break;
571
+ case 'outdated':
572
+ body = ((0, jsx_runtime_1.jsxs)("div", { className: "vls-banner warn", children: [(0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: (0, i18n_1.fill)(t('runtime.outdated'), { installed: versionText(state.installed), wanted: versionText(live.versions) }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn primary", disabled: busy, onClick: () => { act(async () => { await (0, shared_1.callHost)('POST', 'remove'); await (0, shared_1.callHost)('POST', 'install'); }); }, children: t('runtime.reinstall') })] }));
573
+ break;
574
+ case 'failed':
575
+ body = state.installed ? ((0, jsx_runtime_1.jsxs)("div", { className: "vls-banner bad", children: [(0, jsx_runtime_1.jsx)("p", { className: "vac-error", children: (0, i18n_1.fill)(t('runtime.engineFailed'), { error: state.error }) }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm", disabled: busy, onClick: () => { act(() => (0, shared_1.callHost)('POST', 'restart')); }, children: t('runtime.restart') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn sm ghost danger", disabled: busy, onClick: remove, children: t('runtime.remove') })] })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "vls-banner bad", children: [(0, jsx_runtime_1.jsx)("p", { className: "vac-error", children: (0, i18n_1.fill)(t('runtime.failed'), { error: state.error }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn primary", disabled: busy, onClick: install, children: t('runtime.retry') })] }));
576
+ break;
577
+ }
578
+ return ((0, jsx_runtime_1.jsxs)("section", { className: "vac-section", children: [(0, jsx_runtime_1.jsx)("div", { className: "vac-section-head", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "vac-section-title", children: t('runtime.title') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-section-lead vac-mono", children: (0, i18n_1.fill)(t('runtime.location'), { location: live.location }) })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "vac-section-body", children: [body, error === undefined ? null : (0, jsx_runtime_1.jsx)("p", { className: "vac-error", role: "alert", children: error })] })] }));
579
+ }
580
+ function Versions({ versions, t }) {
581
+ return (0, jsx_runtime_1.jsx)("span", { className: "vac-hint vac-mono", children: (0, i18n_1.fill)(t('runtime.versions'), { ...versions }) });
582
+ }
583
+ function versionText(versions) {
584
+ return `${versions.sdk} / ${versions.luaskills} / ${versions.luaRuntime}`;
585
+ }
586
+ function mb(bytes) {
587
+ return (bytes / 1_048_576).toFixed(1);
588
+ }
589
+
590
+ },
591
+ "./settings": function (module, exports, require) {
592
+ "use strict";
593
+ Object.defineProperty(exports, "__esModule", { value: true });
594
+ exports.SettingsPage = SettingsPage;
595
+ const jsx_runtime_1 = require("react/jsx-runtime");
596
+ /**
597
+ * Settings › LuaSkills: the runtime section, then the VM and runtime settings. The settings are
598
+ * shown before the runtime is installed but stay locked until it is.
599
+ */
600
+ const react_1 = require("react");
601
+ const i18n_1 = require("./i18n");
602
+ const runtime_1 = require("./runtime");
603
+ const shared_1 = require("./shared");
604
+ function SettingsPage({ view, t }) {
605
+ const live = (0, runtime_1.useRuntime)(view);
606
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "vac vac-page", "data-vulcan-settings-width": "full", children: [(0, jsx_runtime_1.jsxs)("header", { className: "vac-page-head", "data-vulcan-settings-header": true, children: [(0, jsx_runtime_1.jsx)("h2", { children: t('settingsPage.title') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-lead", children: t('settingsPage.lead') })] }), live === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('loading') })
607
+ : live === null ? (0, jsx_runtime_1.jsx)("div", { className: "vac-alert bad", children: t('unavailable') })
608
+ : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(runtime_1.RuntimeSection, { view: view, live: live, t: t }), (0, jsx_runtime_1.jsx)(SettingsSection, { view: view, live: live, t: t })] }))] }));
609
+ }
610
+ const POOL_FIELDS = [['minSize', 'settings.minSize'], ['maxSize', 'settings.maxSize'], ['idleTtlSecs', 'settings.idleTtl']];
611
+ const CACHE_FIELDS = [['maxEntries', 'settings.maxEntries'], ['defaultTtlSecs', 'settings.defaultTtl'], ['maxTtlSecs', 'settings.maxTtl']];
612
+ const MANAGED_FIELDS = [
613
+ ['workerPoolMaxSizePerEnvironment', 'settings.managedWorkerPoolMax'],
614
+ ['workerIdleTtlSecs', 'settings.managedWorkerIdleTtl'],
615
+ ['persistentSessionLimitPerEngine', 'settings.managedSessionLimit'],
616
+ ['persistentSessionDefaultBufferLimitBytesPerStream', 'settings.managedSessionBuffer'],
617
+ ['invokeDefaultTimeoutMs', 'settings.managedInvokeTimeout'],
618
+ ];
619
+ const NUMBER_PATHS = [
620
+ ...POOL_FIELDS.map(([field]) => ['vmPool', field]),
621
+ ...POOL_FIELDS.map(([field]) => ['runLuaPool', field]),
622
+ ...CACHE_FIELDS.map(([field]) => ['toolCache', field]),
623
+ ...MANAGED_FIELDS.map(([field]) => ['managedRuntime', field]),
624
+ ];
625
+ function draftOf(settings) {
626
+ const numbers = {};
627
+ for (const [group, field] of NUMBER_PATHS)
628
+ numbers[`${group}.${field}`] = String(settings[group][field]);
629
+ return { settings, numbers };
630
+ }
631
+ /** The settings value a draft stands for, or the key of what is wrong with it. */
632
+ function settle(draft) {
633
+ const value = structuredClone(draft.settings);
634
+ for (const [group, field] of NUMBER_PATHS) {
635
+ const text = draft.numbers[`${group}.${field}`]?.trim() ?? '';
636
+ if (!/^[1-9]\d*$/.test(text) || !Number.isSafeInteger(Number(text)))
637
+ return 'settings.validationPositive';
638
+ value[group][field] = Number(text);
639
+ }
640
+ const settings = value;
641
+ if (settings.vmPool.maxSize < settings.vmPool.minSize || settings.runLuaPool.maxSize < settings.runLuaPool.minSize)
642
+ return 'settings.validationPoolOrder';
643
+ if (settings.toolCache.maxTtlSecs < settings.toolCache.defaultTtlSecs)
644
+ return 'settings.validationCacheOrder';
645
+ const urls = [settings.network.githubBaseUrl, settings.network.githubApiBaseUrl, settings.network.officialSkillHubBaseUrl];
646
+ if (!urls.every(url => url === null || /^https?:\/\/[^\s/]+/i.test(url)))
647
+ return 'settings.validationUrl';
648
+ return settings;
649
+ }
650
+ function SettingsSection({ view, live, t }) {
651
+ const saved = live.settings;
652
+ const [draft, setDraft] = (0, react_1.useState)(() => draftOf(saved));
653
+ const [dirty, setDirty] = (0, react_1.useState)(false);
654
+ const [busy, setBusy] = (0, react_1.useState)(false);
655
+ const [note, setNote] = (0, react_1.useState)(undefined);
656
+ // Follow the saved settings until the user starts editing.
657
+ const savedText = JSON.stringify(saved);
658
+ (0, react_1.useEffect)(() => {
659
+ if (!dirty)
660
+ setDraft(draftOf(saved));
661
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- `savedText` stands for `saved`.
662
+ }, [savedText, dirty]);
663
+ const locked = !(0, shared_1.isInstalled)(live.state) || live.state.kind === 'starting' || busy;
664
+ const settled = settle(draft);
665
+ const edit = (change) => {
666
+ setDraft(change);
667
+ setDirty(true);
668
+ setNote(undefined);
669
+ };
670
+ const setNumber = (key, text) => { edit(current => ({ ...current, numbers: { ...current.numbers, [key]: text } })); };
671
+ const setField = (group, field, value) => {
672
+ edit(current => ({ ...current, settings: { ...current.settings, [group]: { ...current.settings[group], [field]: value } } }));
673
+ };
674
+ const save = () => {
675
+ if (typeof settled === 'string')
676
+ return;
677
+ setBusy(true);
678
+ setNote(undefined);
679
+ (0, shared_1.callHost)('POST', 'settings', settled).then(() => {
680
+ setDirty(false);
681
+ setNote({ ok: true, text: t('settings.saved') });
682
+ }, (failure) => {
683
+ setNote({ ok: false, text: (0, shared_1.messageOf)(failure) });
684
+ }).finally(() => {
685
+ setBusy(false);
686
+ view.refresh();
687
+ });
688
+ };
689
+ const numberField = (group, field, label) => {
690
+ const key = `${group}.${field}`;
691
+ return ((0, jsx_runtime_1.jsxs)("label", { className: "vls-field", children: [(0, jsx_runtime_1.jsx)("span", { children: t(label) }), (0, jsx_runtime_1.jsx)("input", { className: "vls-input vac-mono", inputMode: "numeric", disabled: locked, value: draft.numbers[key] ?? '', onChange: (event) => { setNumber(key, event.target.value); } })] }, key));
692
+ };
693
+ const toggle = (group, field, label) => ((0, jsx_runtime_1.jsxs)("label", { className: "vls-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", disabled: locked, checked: draft.settings[group][field], onChange: (event) => { setField(group, field, event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t(label) })] }));
694
+ const urlField = (field, label, fallback) => ((0, jsx_runtime_1.jsxs)("label", { className: "vls-field wide", children: [(0, jsx_runtime_1.jsx)("span", { children: t(label) }), (0, jsx_runtime_1.jsx)("input", { className: "vls-input vac-mono", disabled: locked, placeholder: (0, i18n_1.fill)(t('settings.defaultPlaceholder'), { url: fallback }), value: draft.settings.network[field] ?? '', onChange: (event) => { setField('network', field, event.target.value.trim() === '' ? null : event.target.value.trim()); } })] }));
695
+ return ((0, jsx_runtime_1.jsxs)("section", { className: "vac-section", children: [(0, jsx_runtime_1.jsx)("div", { className: "vac-section-head", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "vac-section-title", children: t('settings.title') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-section-lead", children: (0, shared_1.isInstalled)(live.state) ? t('settings.lead') : t('settings.locked') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "vac-section-body", children: [live.settingsError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "vac-alert warn", children: (0, i18n_1.fill)(t('settings.invalid'), { error: live.settingsError }) }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.mainPool') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('settings.poolHint') }), (0, jsx_runtime_1.jsx)("div", { className: "vls-grid", children: POOL_FIELDS.map(([field, label]) => numberField('vmPool', field, label)) })] }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.runLuaPool') }), (0, jsx_runtime_1.jsx)("div", { className: "vls-grid", children: POOL_FIELDS.map(([field, label]) => numberField('runLuaPool', field, label)) })] }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.toolCache') }), (0, jsx_runtime_1.jsx)("div", { className: "vls-grid", children: CACHE_FIELDS.map(([field, label]) => numberField('toolCache', field, label)) })] }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.managedRuntime') }), (0, jsx_runtime_1.jsx)("p", { className: "vac-hint", children: t('settings.managedRuntimeHint') }), (0, jsx_runtime_1.jsx)("div", { className: "vls-grid", children: MANAGED_FIELDS.map(([field, label]) => numberField('managedRuntime', field, label)) })] }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.capabilities') }), (0, jsx_runtime_1.jsxs)("label", { className: "vls-field", children: [(0, jsx_runtime_1.jsx)("span", { children: t('settings.defaultEncoding') }), (0, jsx_runtime_1.jsxs)("select", { className: "vls-input", disabled: locked, value: draft.settings.capabilities.defaultTextEncoding ?? '', onChange: (event) => { setField('capabilities', 'defaultTextEncoding', event.target.value === '' ? null : event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: t('settings.autoEncoding') }), shared_1.TEXT_ENCODINGS.map(encoding => (0, jsx_runtime_1.jsx)("option", { value: encoding, children: encoding }, encoding))] })] }), toggle('capabilities', 'enableSkillManagementBridge', 'settings.skillManagementBridge'), toggle('capabilities', 'enableManagedIoCompat', 'settings.managedIoCompat')] }), (0, jsx_runtime_1.jsxs)("fieldset", { className: "vls-group", disabled: locked, children: [(0, jsx_runtime_1.jsx)("legend", { children: t('settings.network') }), toggle('network', 'allowDownloads', 'settings.allowDownloads'), urlField('githubBaseUrl', 'settings.githubBaseUrl', 'https://github.com'), urlField('githubApiBaseUrl', 'settings.githubApiBaseUrl', 'https://api.github.com'), (0, jsx_runtime_1.jsxs)("label", { className: "vls-field wide", children: [(0, jsx_runtime_1.jsx)("span", { children: t('settings.skillHubBaseUrl') }), (0, jsx_runtime_1.jsx)("input", { className: "vls-input vac-mono", disabled: locked, value: draft.settings.network.officialSkillHubBaseUrl, onChange: (event) => { setField('network', 'officialSkillHubBaseUrl', event.target.value.trim()); } }), (0, jsx_runtime_1.jsx)("span", { className: "vac-inline", children: live.hubSites.map(site => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-link", disabled: locked, onClick: () => { setField('network', 'officialSkillHubBaseUrl', site.url); }, children: t(`hub.site.${site.site}`) }, site.site))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vac-between", children: [(0, jsx_runtime_1.jsxs)("span", { children: [typeof settled === 'string' && dirty ? (0, jsx_runtime_1.jsx)("span", { className: "vac-error", children: t(settled) }) : null, note === undefined ? null : (0, jsx_runtime_1.jsx)("span", { className: note.ok ? 'vac-hint' : 'vac-error', role: note.ok ? undefined : 'alert', children: note.text })] }), (0, jsx_runtime_1.jsxs)("span", { className: "vac-inline", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn", disabled: locked || !dirty, onClick: () => { setDirty(false); setDraft(draftOf(saved)); setNote(undefined); }, children: t('settings.revert') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vac-btn primary", disabled: locked || !dirty || typeof settled === 'string', onClick: save, children: busy ? t('settings.saving') : t('settings.save') })] })] })] })] }));
696
+ }
697
+
698
+ },
699
+ "./shared": function (module, exports, require) {
700
+ "use strict";
701
+ /** Facts the browser half shares with the Host half. */
702
+ Object.defineProperty(exports, "__esModule", { value: true });
703
+ exports.HostWatch = exports.TEXT_ENCODINGS = exports.PHASES = exports.PANEL_ID = exports.SETTINGS_SECTION = exports.PACKAGE_NAME = void 0;
704
+ exports.callHost = callHost;
705
+ exports.messageOf = messageOf;
706
+ exports.isInstalled = isInstalled;
707
+ /** Checked against `package.json` by `scripts/bundle-client.mjs`. */
708
+ exports.PACKAGE_NAME = '@openvulcan/dsh-vulcan-luaskills';
709
+ /** The Settings dialog entry this plugin adds. */
710
+ exports.SETTINGS_SECTION = 'vulcan-luaskills';
711
+ /** The main panel the sidebar entry opens. */
712
+ exports.PANEL_ID = 'vulcan-luaskills';
713
+ /** Mirrors `ROUTE_PREFIX` in `src/index.ts`, below the page's origin. */
714
+ const ROUTE_BASE = '/api/vulcan-luaskills/';
715
+ /** Mirrors `PHASES` in `src/runtime.ts`. */
716
+ exports.PHASES = ['sdk', 'lua', 'core', 'engine', 'skill'];
717
+ /** Mirrors `TEXT_ENCODINGS` in `src/settings.ts`. */
718
+ exports.TEXT_ENCODINGS = ['utf-8', 'system', 'oem', 'gbk', 'gb18030', 'latin1', 'base64'];
719
+ async function callHost(method, route, body) {
720
+ const response = await fetch(`${ROUTE_BASE}${route}`, {
721
+ method,
722
+ ...body === undefined ? {} : { body: JSON.stringify(body), headers: { 'content-type': 'application/json' } },
723
+ });
724
+ const answer = await response.json().catch(() => undefined);
725
+ if (answer?.ok !== true)
726
+ throw new Error(answer?.error?.message ?? `HTTP ${response.status}`);
727
+ return answer.value;
728
+ }
729
+ function messageOf(error) {
730
+ return error instanceof Error ? error.message : String(error);
731
+ }
732
+ /** Whether the runtime is on disk, whatever its engine is doing. */
733
+ function isInstalled(state) {
734
+ return state.kind === 'ready' || state.kind === 'starting' || (state.kind === 'failed' && state.installed);
735
+ }
736
+ /**
737
+ * Latest-answer-wins view of one Host fact, shared by every rendered entry. `undefined` means
738
+ * unknown: before the first answer, or after a failed read, so nothing is shown as a guess.
739
+ */
740
+ class HostWatch {
741
+ read;
742
+ #value;
743
+ #listeners = new Set();
744
+ #generation = 0;
745
+ constructor(read) {
746
+ this.read = read;
747
+ }
748
+ subscribe = (listener) => {
749
+ this.#listeners.add(listener);
750
+ return () => { this.#listeners.delete(listener); };
751
+ };
752
+ getSnapshot = () => this.#value;
753
+ /** Re-read the fact; an older answer never replaces a newer one. */
754
+ refresh() {
755
+ const generation = ++this.#generation;
756
+ this.read().then((value) => {
757
+ if (generation === this.#generation)
758
+ this.#set(value);
759
+ }, () => {
760
+ if (generation === this.#generation)
761
+ this.#set(undefined);
762
+ });
763
+ }
764
+ /** Stop publishing answers that are still in flight. */
765
+ close() {
766
+ ++this.#generation;
767
+ this.#listeners.clear();
768
+ }
769
+ #set(value) {
770
+ if (Object.is(value, this.#value))
771
+ return;
772
+ this.#value = value;
773
+ for (const listener of this.#listeners)
774
+ listener();
775
+ }
776
+ }
777
+ exports.HostWatch = HostWatch;
778
+
779
+ },
780
+ "./style": function (module, exports, require) {
781
+ "use strict";
782
+ /**
783
+ * The plugin's look, after VulcanCode's ui-kit (`apps/vulcan-code-web/src/ui-kit/styles`): the
784
+ * same `.vac` tokens and rules as the account plugin, plus the LuaSkills page, install progress,
785
+ * settings groups and Hub cards under `vls-*`. Every rule is scoped under `.vac` or `vls-`, so
786
+ * nothing leaks into dsh; dark values follow dsh's `body[data-ds-dark-theme]`.
787
+ */
788
+ Object.defineProperty(exports, "__esModule", { value: true });
789
+ exports.installStyle = installStyle;
790
+ const CSS = String.raw `
791
+ .vac {
792
+ --vk-u: 4px;
793
+ --vk-panel: #fff; --vk-sunken: #f6f7f9; --vk-hover: #eef1f4; --vk-select: #e3e9f8;
794
+ --vk-line: #dde1e6; --vk-line-strong: #c3c9d1; --vk-line-soft: #eaecef;
795
+ --vk-ink: #14171c; --vk-ink-2: #4a515c; --vk-ink-3: #626973;
796
+ --vk-ember: #e2511a; --vk-signal: #2e58cc; --vk-ok: #18774a; --vk-warn: #945d09; --vk-bad: #c3303d;
797
+ --vk-shadow-1: 0 1px 2px rgba(20, 23, 28, 0.06);
798
+ --vk-shadow-2: 0 16px 40px rgba(20, 23, 28, 0.18), 0 2px 8px rgba(20, 23, 28, 0.08);
799
+ --vk-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
800
+ font-size: 13px; line-height: 1.5; color: var(--vk-ink);
801
+ }
802
+ body[data-ds-dark-theme] .vac {
803
+ --vk-panel: #15181d; --vk-sunken: #0f1215; --vk-hover: #1e2329; --vk-select: #1c2537;
804
+ --vk-line: #23282f; --vk-line-strong: #343b45; --vk-line-soft: #1a1e24;
805
+ --vk-ink: #e6e9ed; --vk-ink-2: #a2aab5; --vk-ink-3: #848c97;
806
+ --vk-ember: #ff6a2b; --vk-signal: #7d9dff; --vk-ok: #3fc48a; --vk-warn: #e0a83a; --vk-bad: #f0646f;
807
+ --vk-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
808
+ --vk-shadow-2: 0 16px 40px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4);
809
+ }
810
+ .vac *, .vac *::before, .vac *::after { box-sizing: border-box; }
811
+ .vac-page { display: flex; flex-direction: column; gap: calc(var(--vk-u) * 4); counter-reset: vac-section; padding-bottom: calc(var(--vk-u) * 2); }
812
+ .vac-page-head h2 { margin: 0; font-size: 16px; font-weight: 600; }
813
+ .vac-lead { margin: calc(var(--vk-u) * 1) 0 0; color: var(--vk-ink-2); }
814
+ .vac-hint { margin: 0; color: var(--vk-ink-3); font-size: 12px; }
815
+ .vac-error { margin: 0; color: var(--vk-bad); font-size: 12px; overflow-wrap: anywhere; }
816
+
817
+ .vac-section { position: relative; border: 1px solid var(--vk-line); background: var(--vk-panel); box-shadow: var(--vk-shadow-1); }
818
+ .vac-section::before { content: ""; position: absolute; left: -1px; top: -1px; width: calc(var(--vk-u) * 7); height: 2px; background: var(--vk-ember); }
819
+ .vac-section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: calc(var(--vk-u) * 3); padding: calc(var(--vk-u) * 3.5) calc(var(--vk-u) * 4) 0; }
820
+ .vac-section-title { display: flex; align-items: center; gap: calc(var(--vk-u) * 2); margin: 0; font-size: 15px; font-weight: 600; }
821
+ .vac-section-title::before { counter-increment: vac-section; content: counter(vac-section, decimal-leading-zero); border: 1px solid var(--vk-line); color: var(--vk-ink-3); font-family: var(--vk-mono); font-size: 10px; font-weight: 400; letter-spacing: .06em; padding: 0 5px; line-height: 16px; }
822
+ .vac-section-lead { margin: calc(var(--vk-u) * 1) 0 0; color: var(--vk-ink-3); font-size: 12px; }
823
+ .vac-section-body { display: flex; flex-direction: column; gap: calc(var(--vk-u) * 3); padding: calc(var(--vk-u) * 3) calc(var(--vk-u) * 4) calc(var(--vk-u) * 4); }
824
+ .vac-section-body.flush { padding: calc(var(--vk-u) * 3) 0 0; gap: 0; }
825
+
826
+ .vac-inline { display: flex; align-items: center; gap: calc(var(--vk-u) * 2); flex-wrap: wrap; }
827
+ .vac-between { display: flex; align-items: center; justify-content: space-between; gap: calc(var(--vk-u) * 3); flex-wrap: wrap; }
828
+
829
+ .vac-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 28px; padding: 0 calc(var(--vk-u) * 3); border: 1px solid var(--vk-line-strong); background: var(--vk-panel); color: var(--vk-ink); font: inherit; font-size: 12px; font-weight: 500; cursor: pointer; white-space: nowrap; border-radius: 0; }
830
+ .vac-btn:hover:not(:disabled) { background: var(--vk-hover); }
831
+ .vac-btn:disabled { cursor: default; opacity: .55; }
832
+ .vac-btn.sm { height: 24px; padding: 0 calc(var(--vk-u) * 2); }
833
+ .vac-btn.primary { background: var(--vk-ink); border-color: var(--vk-ink); color: var(--vk-panel); }
834
+ .vac-btn.primary:hover:not(:disabled) { background: var(--vk-ink-2); }
835
+ .vac-btn.ghost { border-color: transparent; background: transparent; }
836
+ .vac-btn.ghost:hover:not(:disabled) { background: var(--vk-hover); }
837
+ .vac-link { border: 0; padding: 0; background: none; color: var(--vk-signal); font: inherit; font-size: 12px; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
838
+
839
+ .vac-btn:focus-visible, .vac-site:focus-visible { outline: 2px solid var(--vk-signal); outline-offset: 1px; }
840
+
841
+ .vac-badge { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border: 1px solid color-mix(in srgb, var(--tone, var(--vk-ink-3)) 32%, transparent); background: color-mix(in srgb, var(--tone, var(--vk-ink-3)) 9%, transparent); color: var(--tone, var(--vk-ink-2)); font-size: 11px; font-weight: 500; white-space: nowrap; }
842
+ .vac-badge.ok { --tone: var(--vk-ok); }
843
+ .vac-badge.warn { --tone: var(--vk-warn); }
844
+ .vac-badge.bad { --tone: var(--vk-bad); }
845
+ .vac-badge.info { --tone: var(--vk-signal); }
846
+ .vac-badge.outline { --tone: var(--vk-ink-3); background: transparent; }
847
+
848
+ .vac-alert { padding: calc(var(--vk-u) * 2.5) calc(var(--vk-u) * 3); border: 1px solid var(--vk-line); border-left: 3px solid var(--tone, var(--vk-ink-3)); background: var(--vk-sunken); color: var(--vk-ink-2); font-size: 12px; overflow-wrap: anywhere; }
849
+ .vac-alert.warn { --tone: var(--vk-warn); }
850
+ .vac-alert.bad { --tone: var(--vk-bad); }
851
+
852
+ .vac-btn.danger { color: var(--vk-bad); }
853
+ .vac-btn.danger:hover:not(:disabled) { background: color-mix(in srgb, var(--vk-bad) 9%, transparent); }
854
+ .vac-alert.info { --tone: var(--vk-signal); }
855
+
856
+ /* The LuaSkills page fills dsh's main column and scrolls on its own. */
857
+ .vls-panel { height: 100%; overflow-y: auto; background: var(--vk-sunken); }
858
+ .vls-panel-inner { max-width: 960px; margin: 0 auto; padding: calc(var(--vk-u) * 6) calc(var(--vk-u) * 6) calc(var(--vk-u) * 8); }
859
+ .vls-pad { padding: 0 calc(var(--vk-u) * 4) calc(var(--vk-u) * 3); }
860
+
861
+ .vls-banner { display: flex; align-items: center; justify-content: space-between; gap: calc(var(--vk-u) * 3); flex-wrap: wrap; padding: calc(var(--vk-u) * 3); border: 1px solid var(--vk-line); border-left: 3px solid var(--tone, var(--vk-ember)); background: var(--vk-sunken); }
862
+ .vls-banner > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
863
+ .vls-banner.warn { --tone: var(--vk-warn); }
864
+ .vls-banner.bad { --tone: var(--vk-bad); }
865
+
866
+ .vls-progress { display: flex; flex-direction: column; gap: calc(var(--vk-u) * 2.5); }
867
+ .vls-bar { position: relative; height: 4px; overflow: hidden; background: var(--vk-line-soft); }
868
+ .vls-bar-fill { position: absolute; inset: 0 auto 0 0; background: var(--vk-ember); transition: width .2s linear; }
869
+ .vls-bar-fill.indeterminate { width: 30%; animation: vls-slide 1.2s ease-in-out infinite; }
870
+ @keyframes vls-slide { from { left: -30%; } to { left: 100%; } }
871
+ @media (prefers-reduced-motion: reduce) { .vls-bar-fill.indeterminate { animation: none; width: 100%; opacity: .5; } }
872
+ .vls-steps { display: flex; flex-wrap: wrap; gap: calc(var(--vk-u) * 1) calc(var(--vk-u) * 4); margin: 0; padding: 0; list-style: none; counter-reset: vls-step; color: var(--vk-ink-3); font-size: 12px; }
873
+ .vls-steps li { display: flex; align-items: center; gap: 6px; }
874
+ .vls-steps li::before { counter-increment: vls-step; content: counter(vls-step); display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border: 1px solid var(--vk-line-strong); font-family: var(--vk-mono); font-size: 10px; }
875
+ .vls-steps li.done { color: var(--vk-ink-2); }
876
+ .vls-steps li.done::before { content: "\2713"; border-color: var(--vk-ok); color: var(--vk-ok); }
877
+ .vls-steps li.now { color: var(--vk-ink); font-weight: 500; }
878
+ .vls-steps li.now::before { border-color: var(--vk-ember); color: var(--vk-ember); }
879
+
880
+ .vls-group { display: flex; flex-direction: column; gap: calc(var(--vk-u) * 2.5); margin: 0; padding: calc(var(--vk-u) * 3); border: 1px solid var(--vk-line-soft); min-width: 0; }
881
+ .vls-group:disabled { opacity: .6; }
882
+ .vls-group legend { padding: 0 calc(var(--vk-u) * 1); font-size: 12px; font-weight: 600; color: var(--vk-ink-2); }
883
+ .vls-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: calc(var(--vk-u) * 3); }
884
+ .vls-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; font-size: 12px; color: var(--vk-ink-2); }
885
+ .vls-field.wide { grid-column: 1 / -1; }
886
+ .vls-input { height: 28px; padding: 0 calc(var(--vk-u) * 2); border: 1px solid var(--vk-line-strong); border-radius: 0; background: var(--vk-panel); color: var(--vk-ink); font: inherit; font-size: 12px; min-width: 0; }
887
+ .vls-input:focus { outline: 2px solid var(--vk-signal); outline-offset: -1px; }
888
+ .vls-input:disabled { background: var(--vk-sunken); color: var(--vk-ink-3); }
889
+ .vls-check { display: flex; align-items: center; gap: calc(var(--vk-u) * 2); font-size: 12px; color: var(--vk-ink-2); cursor: pointer; }
890
+ .vls-check input { margin: 0; accent-color: var(--vk-ember); }
891
+
892
+ .vls-tabs { display: flex; gap: 0; border-bottom: 1px solid var(--vk-line); }
893
+ .vls-tab { height: 34px; padding: 0 calc(var(--vk-u) * 4); border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; background: transparent; color: var(--vk-ink-3); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer; }
894
+ .vls-tab:hover { color: var(--vk-ink); }
895
+ .vls-tab.on { color: var(--vk-ink); border-bottom-color: var(--vk-ember); }
896
+ .vls-seg { height: 24px; padding: 0 calc(var(--vk-u) * 2.5); border: 1px solid var(--vk-line-strong); background: var(--vk-panel); color: var(--vk-ink-2); font: inherit; font-size: 12px; cursor: pointer; display: inline-flex; align-items: center; }
897
+ .vls-seg + .vls-seg { margin-left: calc(var(--vk-u) * -2 - 1px); }
898
+ .vls-seg.on { border-color: var(--vk-ink); background: var(--vk-ink); color: var(--vk-panel); }
899
+ .vls-seg:disabled { cursor: default; opacity: .55; }
900
+ .vls-tab:focus-visible, .vls-seg:focus-visible, .vac-link:focus-visible { outline: 2px solid var(--vk-signal); outline-offset: 1px; }
901
+
902
+ .vls-list { margin: 0; padding: 0; list-style: none; }
903
+ .vls-row { display: flex; align-items: center; justify-content: space-between; gap: calc(var(--vk-u) * 3); padding: calc(var(--vk-u) * 3) calc(var(--vk-u) * 4); border-top: 1px solid var(--vk-line-soft); }
904
+ .vls-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
905
+ .vls-row-main .vac-hint { overflow-wrap: anywhere; }
906
+ .vls-tools { margin: 0; color: var(--vk-ink-3); font-size: 11px; overflow-wrap: anywhere; }
907
+
908
+ .vls-search { width: 100%; height: 32px; font-size: 13px; }
909
+ .vls-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: calc(var(--vk-u) * 2.5); margin: 0; padding: 0; list-style: none; }
910
+ .vls-card { display: flex; flex-direction: column; gap: calc(var(--vk-u) * 1.5); padding: calc(var(--vk-u) * 3); border: 1px solid var(--vk-line); background: var(--vk-panel); min-width: 0; }
911
+ .vls-card:hover { border-color: var(--vk-line-strong); }
912
+ .vls-card .vac-hint { overflow-wrap: anywhere; }
913
+ .vls-summary { margin: 0; color: var(--vk-ink-2); font-size: 12px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
914
+
915
+ .vls-sheet { position: fixed; top: 0; right: 0; bottom: 0; z-index: 50; display: flex; flex-direction: column; width: min(560px, 100vw); border-left: 1px solid var(--vk-line); background: var(--vk-panel); box-shadow: var(--vk-shadow-2); }
916
+ .vls-sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: calc(var(--vk-u) * 3); padding: calc(var(--vk-u) * 4); border-bottom: 1px solid var(--vk-line); }
917
+ .vls-sheet-head strong { font-size: 15px; }
918
+ .vls-sheet-body { flex: 1; overflow-y: auto; padding: calc(var(--vk-u) * 4); display: flex; flex-direction: column; gap: calc(var(--vk-u) * 2); }
919
+ .vls-sheet-body h4 { margin: calc(var(--vk-u) * 2) 0 0; font-size: 13px; }
920
+ .vls-sheet-body p, .vls-sheet-body ul { margin: 0; color: var(--vk-ink-2); }
921
+ .vls-readme { margin: 0; padding: calc(var(--vk-u) * 3); border: 1px solid var(--vk-line-soft); background: var(--vk-sunken); font-family: var(--vk-mono); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
922
+ `;
923
+ /** Add the stylesheet once per page; returns a function that removes it again. */
924
+ function installStyle() {
925
+ const existing = document.querySelector('style[data-plugin="vulcan-luaskills"]');
926
+ if (existing !== null)
927
+ existing.remove();
928
+ const tag = document.createElement('style');
929
+ tag.dataset['plugin'] = 'vulcan-luaskills';
930
+ tag.textContent = CSS;
931
+ document.head.appendChild(tag);
932
+ return () => { tag.remove(); };
933
+ }
934
+
935
+ },
936
+ };
937
+ var cache = {};
938
+ function load(request) {
939
+ if (!(request in definitions)) return platformRequire(request);
940
+ if (!(request in cache)) {
941
+ var module = { exports: {} };
942
+ cache[request] = module;
943
+ definitions[request](module, module.exports, load);
944
+ }
945
+ return cache[request].exports;
946
+ }
947
+ return load('./index');
948
+ }
949
+ });