@dsh-workbench/shared 0.3.11 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/api/blocker-table.d.ts +3 -3
  4. package/dist/api/blocker-table.js +47 -23
  5. package/dist/api/dsh.d.ts +1 -1
  6. package/dist/api/workbench-client.js +2 -1
  7. package/dist/components/Activity.css +0 -1
  8. package/dist/components/ApprovalDetail.css +1 -2
  9. package/dist/components/ApprovalDetail.d.ts +1 -1
  10. package/dist/components/ApprovalPlan.css +0 -1
  11. package/dist/components/Card.css +0 -1
  12. package/dist/components/Card.d.ts +1 -1
  13. package/dist/components/CardBoundary.d.ts +1 -1
  14. package/dist/components/CardHead.css +0 -1
  15. package/dist/components/CardHead.d.ts +1 -1
  16. package/dist/components/ChoiceGroup.css +1 -2
  17. package/dist/components/ConfirmBar.d.ts +1 -1
  18. package/dist/components/ConfirmBar.js +1 -1
  19. package/dist/components/Form.css +1 -1
  20. package/dist/components/FormActions.js +1 -1
  21. package/dist/components/LongTaskRow.css +1 -2
  22. package/dist/components/LongTaskRow.d.ts +1 -1
  23. package/dist/components/LongTaskRow.js +1 -1
  24. package/dist/components/Note.css +0 -1
  25. package/dist/components/ResourceStates.css +0 -1
  26. package/dist/components/SettingsSection.css +0 -1
  27. package/dist/components/Spinner.css +0 -1
  28. package/dist/components/Stack.css +0 -1
  29. package/dist/components/StateBlock.css +0 -1
  30. package/dist/components/board-module.d.ts +3 -3
  31. package/dist/components/icons.d.ts +1 -1
  32. package/dist/components/icons.js +11 -4
  33. package/dist/config/constants.d.ts +2 -2
  34. package/dist/config/constants.js +2 -2
  35. package/dist/contract/adapters.d.ts +10 -0
  36. package/dist/contract/cli.d.ts +3 -0
  37. package/dist/contract/data.d.ts +126 -0
  38. package/dist/{api → contract}/facts.d.ts +12 -3
  39. package/dist/{api → contract}/facts.js +19 -1
  40. package/dist/contract/needs.d.ts +132 -0
  41. package/dist/contract/needs.js +232 -0
  42. package/dist/contract/plugin-source.d.ts +1 -0
  43. package/dist/contract/protocol/bundle-install.d.ts +136 -0
  44. package/dist/contract/protocol/bundle-install.js +12 -0
  45. package/dist/contract/protocol/config-sync.d.ts +55 -0
  46. package/dist/contract/protocol/config-sync.js +2 -0
  47. package/dist/contract/protocol/diy.d.ts +4 -0
  48. package/dist/contract/protocol/diy.js +4 -0
  49. package/dist/contract/protocol/dsh-plugins.d.ts +11 -0
  50. package/dist/contract/protocol/dsh-plugins.js +1 -0
  51. package/dist/contract/protocol/long-tasks.d.ts +13 -0
  52. package/dist/contract/protocol/long-tasks.js +1 -0
  53. package/dist/contract/protocol/market-index.d.ts +195 -0
  54. package/dist/contract/protocol/market-index.js +7 -0
  55. package/dist/contract/protocol/platform.d.ts +44 -0
  56. package/dist/contract/protocol/platform.js +1 -0
  57. package/dist/contract/protocol/preflight-wake.d.ts +7 -0
  58. package/dist/contract/protocol/preflight-wake.js +1 -0
  59. package/dist/contract/protocol/profile-create.d.ts +30 -0
  60. package/dist/contract/protocol/profile-create.js +2 -0
  61. package/dist/contract/protocol/sidebar-edition.d.ts +14 -0
  62. package/dist/contract/protocol/sidebar-edition.js +2 -0
  63. package/dist/contract/protocol/unit-manifests.d.ts +6 -0
  64. package/dist/contract/protocol/unit-manifests.js +1 -0
  65. package/dist/contract/unit-board.js +1 -0
  66. package/dist/contract/unit-capability.d.ts +34 -0
  67. package/dist/contract/unit-capability.js +1 -0
  68. package/dist/{host → contract}/unit-declaration.d.ts +7 -5
  69. package/dist/{api → contract}/unit-declaration.js +19 -13
  70. package/dist/contract/unit.d.ts +57 -0
  71. package/dist/contract/unit.js +24 -0
  72. package/dist/contract/workbench-contract.d.ts +15 -0
  73. package/dist/contract/workbench-contract.js +1 -0
  74. package/dist/host/adapter-set.d.ts +26 -0
  75. package/dist/host/adapter-set.js +243 -0
  76. package/dist/host/adapter-types.d.ts +79 -0
  77. package/dist/host/adapter-types.js +23 -0
  78. package/dist/host/adapters.d.ts +22 -0
  79. package/dist/host/adapters.js +9 -0
  80. package/dist/host/browser.d.ts +3 -0
  81. package/dist/host/browser.js +3 -0
  82. package/dist/host/changelog.d.ts +21 -0
  83. package/dist/host/changelog.js +188 -0
  84. package/dist/host/channel-plugin.d.ts +15 -0
  85. package/dist/host/channel-plugin.js +42 -0
  86. package/dist/host/cli.d.ts +4 -0
  87. package/dist/host/cli.js +7 -0
  88. package/dist/host/command-name.d.ts +1 -0
  89. package/dist/host/command-name.js +14 -0
  90. package/dist/host/data-error.d.ts +13 -0
  91. package/dist/host/data-error.js +20 -0
  92. package/dist/host/data-root.js +3 -0
  93. package/dist/host/diy-debug.js +2 -1
  94. package/dist/host/diy-record.js +2 -1
  95. package/dist/host/facts.d.ts +1 -1
  96. package/dist/host/facts.js +3 -2
  97. package/dist/host/git.js +2 -2
  98. package/dist/host/http.js +1 -1
  99. package/dist/host/lib-capabilities.d.ts +22 -0
  100. package/dist/host/lib-capabilities.js +37 -0
  101. package/dist/host/lib-install.d.ts +9 -0
  102. package/dist/host/lib-install.js +10 -0
  103. package/dist/host/long-task.d.ts +1 -1
  104. package/dist/host/long-task.js +4 -3
  105. package/dist/host/market-index.d.ts +22 -0
  106. package/dist/host/market-index.js +420 -0
  107. package/dist/host/needs.d.ts +4 -0
  108. package/dist/host/needs.js +2 -0
  109. package/dist/host/patch.d.ts +9 -0
  110. package/dist/host/patch.js +78 -0
  111. package/dist/host/paths.d.ts +12 -0
  112. package/dist/host/paths.js +28 -0
  113. package/dist/host/platform.d.ts +14 -0
  114. package/dist/host/platform.js +40 -0
  115. package/dist/host/plugin-source.d.ts +8 -6
  116. package/dist/host/plugin-source.js +43 -33
  117. package/dist/host/plugin.d.ts +4 -0
  118. package/dist/host/plugin.js +39 -0
  119. package/dist/host/port-types.d.ts +191 -0
  120. package/dist/host/port-types.js +1 -0
  121. package/dist/host/preflight.d.ts +28 -0
  122. package/dist/host/preflight.js +1 -0
  123. package/dist/host/profile-port.d.ts +4 -0
  124. package/dist/host/profile-port.js +4 -0
  125. package/dist/host/provision.d.ts +2 -2
  126. package/dist/host/provision.js +5 -3
  127. package/dist/host/recipe-rules.d.ts +5 -0
  128. package/dist/host/recipe-rules.js +382 -0
  129. package/dist/host/recipe.d.ts +14 -0
  130. package/dist/host/recipe.js +283 -0
  131. package/dist/host/shell-text.d.ts +9 -2
  132. package/dist/host/shell-text.js +15 -3
  133. package/dist/host/shell.d.ts +2 -0
  134. package/dist/host/shell.js +7 -0
  135. package/dist/host/spec.d.ts +8 -0
  136. package/dist/host/spec.js +24 -0
  137. package/dist/host/supply-index.d.ts +34 -0
  138. package/dist/host/supply-index.js +202 -0
  139. package/dist/host/supply-port.d.ts +5 -0
  140. package/dist/host/supply-port.js +39 -0
  141. package/dist/host/time.d.ts +12 -0
  142. package/dist/host/time.js +19 -0
  143. package/dist/host/tokens.d.ts +26 -0
  144. package/dist/host/tokens.js +154 -0
  145. package/dist/host/tool-kit.js +1 -1
  146. package/dist/host/unit-face.d.ts +5 -4
  147. package/dist/host/version-range.d.ts +2 -0
  148. package/dist/host/version-range.js +73 -0
  149. package/dist/host/version.d.ts +3 -0
  150. package/dist/host/version.js +29 -0
  151. package/dist/host.d.ts +47 -16
  152. package/dist/host.js +47 -16
  153. package/dist/i18n/en.js +224 -71
  154. package/dist/i18n/index.d.ts +298 -73
  155. package/dist/i18n/merge.js +1 -1
  156. package/dist/i18n/need-text.d.ts +26 -0
  157. package/dist/i18n/need-text.js +26 -0
  158. package/dist/i18n/settings.d.ts +70 -0
  159. package/dist/i18n/settings.js +136 -0
  160. package/dist/i18n/zh.d.ts +297 -72
  161. package/dist/i18n/zh.js +226 -73
  162. package/dist/index.d.ts +23 -7
  163. package/dist/index.js +23 -7
  164. package/dist/{api → lib}/dsh-client.d.ts +11 -1
  165. package/dist/lib/dsh-client.js +1 -0
  166. package/dist/lib/market-index.d.ts +7 -0
  167. package/dist/lib/market-index.js +25 -0
  168. package/dist/lib/react.d.ts +0 -40
  169. package/dist/lib/react.js +0 -36
  170. package/dist/lib/ui.js +3 -9
  171. package/dist/testing/data.d.ts +13 -0
  172. package/dist/testing/data.js +46 -0
  173. package/dist/testing/declaration.d.ts +1 -1
  174. package/dist/testing/declaration.js +1 -1
  175. package/dist/testing/host-fakes.d.ts +0 -13
  176. package/dist/testing/host-fakes.js +0 -24
  177. package/dist/testing/needs.d.ts +16 -0
  178. package/dist/testing/needs.js +46 -0
  179. package/dist/testing.d.ts +2 -0
  180. package/dist/testing.js +2 -0
  181. package/package.json +18 -2
  182. package/src/api/__tests__/blocker-table.test.ts +135 -86
  183. package/src/api/blocker-table.ts +52 -26
  184. package/src/api/dsh.ts +1 -1
  185. package/src/api/host-write.ts +0 -1
  186. package/src/api/workbench-client.test.ts +2 -2
  187. package/src/api/workbench-client.ts +2 -1
  188. package/src/components/Activity.css +0 -1
  189. package/src/components/ApprovalDetail.css +1 -2
  190. package/src/components/ApprovalDetail.tsx +1 -1
  191. package/src/components/ApprovalPlan.css +0 -1
  192. package/src/components/Card.css +0 -1
  193. package/src/components/Card.tsx +1 -1
  194. package/src/components/CardAnchor.test.tsx +1 -1
  195. package/src/components/CardBoundary.tsx +1 -1
  196. package/src/components/CardHead.css +0 -1
  197. package/src/components/CardHead.tsx +1 -1
  198. package/src/components/ChoiceGroup.css +1 -2
  199. package/src/components/ConfirmBar.tsx +1 -1
  200. package/src/components/Form.css +1 -1
  201. package/src/components/Form.tsx +1 -1
  202. package/src/components/FormActions.tsx +1 -1
  203. package/src/components/LongTaskRow.css +1 -2
  204. package/src/components/LongTaskRow.tsx +1 -1
  205. package/src/components/Note.css +0 -1
  206. package/src/components/ResourceStates.css +0 -1
  207. package/src/components/SelectFieldNodes.tsx +0 -1
  208. package/src/components/SettingsSection.css +0 -1
  209. package/src/components/Spinner.css +0 -1
  210. package/src/components/Stack.css +0 -1
  211. package/src/components/StateBlock.css +0 -1
  212. package/src/components/__tests__/long-task-row.test.ts +1 -1
  213. package/src/components/board-module.ts +3 -3
  214. package/src/components/icons.tsx +16 -8
  215. package/src/config/constants.ts +2 -2
  216. package/src/{api → contract}/__tests__/facts.test.ts +73 -25
  217. package/src/{api → contract}/__tests__/long-task.test.ts +3 -3
  218. package/src/contract/__tests__/needs.test.ts +74 -0
  219. package/src/{host → contract}/__tests__/unit-declaration.test.ts +1 -1
  220. package/src/contract/__tests__/unit.test.ts +43 -0
  221. package/src/contract/adapters.ts +9 -0
  222. package/src/contract/cli.ts +3 -0
  223. package/src/contract/data.ts +145 -0
  224. package/src/{api → contract}/facts.ts +34 -4
  225. package/src/contract/needs.ts +331 -0
  226. package/src/contract/plugin-source.ts +1 -0
  227. package/src/contract/protocol/bundle-install.ts +198 -0
  228. package/src/contract/protocol/config-sync.ts +65 -0
  229. package/src/contract/protocol/diy.ts +4 -0
  230. package/src/contract/protocol/dsh-plugins.ts +13 -0
  231. package/src/contract/protocol/long-tasks.ts +16 -0
  232. package/src/contract/protocol/market-index.ts +246 -0
  233. package/src/contract/protocol/platform.ts +47 -0
  234. package/src/contract/protocol/preflight-wake.ts +17 -0
  235. package/src/contract/protocol/profile-create.ts +36 -0
  236. package/src/contract/protocol/sidebar-edition.ts +19 -0
  237. package/src/contract/protocol/unit-manifests.ts +8 -0
  238. package/src/{api → contract}/unit-board.ts +0 -1
  239. package/src/contract/unit-capability.ts +37 -0
  240. package/src/{host → contract}/unit-declaration.ts +22 -18
  241. package/src/contract/unit.ts +76 -0
  242. package/src/contract/workbench-contract.ts +30 -0
  243. package/src/host/__tests__/adapter-set.test.ts +228 -0
  244. package/src/host/__tests__/adapters.test.ts +27 -0
  245. package/src/host/__tests__/changelog.test.ts +102 -0
  246. package/src/host/__tests__/command-name.test.ts +16 -0
  247. package/src/host/__tests__/diy-record.test.ts +3 -3
  248. package/src/host/__tests__/facts.test.ts +5 -5
  249. package/src/host/__tests__/long-task.test.ts +1 -1
  250. package/src/host/__tests__/market-index.test.ts +179 -0
  251. package/src/host/__tests__/plugin-ledger.test.ts +10 -10
  252. package/src/host/__tests__/provision.test.ts +7 -6
  253. package/src/host/__tests__/shell-text.test.ts +16 -1
  254. package/src/host/__tests__/supply-index.test.ts +137 -0
  255. package/src/host/__tests__/tokens.test.ts +110 -0
  256. package/src/host/__tests__/version-range.test.ts +21 -0
  257. package/src/host/adapter-set.ts +298 -0
  258. package/src/host/adapter-types.ts +105 -0
  259. package/src/host/adapters.ts +44 -0
  260. package/src/host/browser.ts +3 -0
  261. package/src/host/changelog.ts +212 -0
  262. package/src/host/channel-plugin.ts +55 -0
  263. package/src/host/cli.ts +11 -0
  264. package/src/host/command-name.ts +15 -0
  265. package/src/host/data-error.ts +21 -0
  266. package/src/host/data-root.ts +2 -0
  267. package/src/host/diy-debug.ts +2 -1
  268. package/src/host/diy-record.ts +2 -1
  269. package/src/host/facts.ts +4 -3
  270. package/src/host/git.ts +2 -2
  271. package/src/host/http.ts +1 -1
  272. package/src/host/lib-capabilities.ts +52 -0
  273. package/src/host/lib-install.ts +18 -0
  274. package/src/host/long-task.ts +4 -3
  275. package/src/host/market-index.ts +413 -0
  276. package/src/host/needs.ts +6 -0
  277. package/src/host/patch.ts +93 -0
  278. package/src/host/paths.ts +37 -0
  279. package/src/host/platform.ts +48 -0
  280. package/src/host/plugin-source.ts +48 -56
  281. package/src/host/plugin.ts +39 -0
  282. package/src/host/port-types.ts +222 -0
  283. package/src/host/preflight.ts +31 -0
  284. package/src/host/profile-port.ts +9 -0
  285. package/src/host/provision.ts +7 -4
  286. package/src/host/recipe-rules.ts +330 -0
  287. package/src/host/recipe.test.ts +334 -0
  288. package/src/host/recipe.ts +323 -0
  289. package/src/host/shell-text.ts +15 -3
  290. package/src/host/shell.ts +9 -0
  291. package/src/host/spec.ts +32 -0
  292. package/src/host/supply-index.ts +256 -0
  293. package/src/host/supply-port.ts +45 -0
  294. package/src/host/time.ts +22 -0
  295. package/src/host/tokens.ts +186 -0
  296. package/src/host/tool-kit.ts +1 -1
  297. package/src/host/unit-face.ts +5 -4
  298. package/src/host/version-range.ts +71 -0
  299. package/src/host/version.ts +30 -0
  300. package/src/host.ts +47 -16
  301. package/src/i18n/en.ts +224 -71
  302. package/src/i18n/merge.test.ts +6 -6
  303. package/src/i18n/merge.ts +1 -1
  304. package/src/i18n/need-text.ts +27 -0
  305. package/src/i18n/settings.ts +141 -0
  306. package/src/i18n/zh.ts +227 -73
  307. package/src/index.ts +23 -7
  308. package/src/lib/blocker-action.ts +0 -1
  309. package/src/{api → lib}/dsh-client.ts +12 -1
  310. package/src/lib/market-index.ts +36 -0
  311. package/src/lib/react.ts +0 -40
  312. package/src/lib/text.test.ts +2 -2
  313. package/src/lib/ui.test.ts +6 -5
  314. package/src/lib/ui.ts +3 -9
  315. package/src/testing/__tests__/declaration.test.ts +1 -1
  316. package/src/testing/data.ts +66 -0
  317. package/src/testing/declaration.ts +2 -2
  318. package/src/testing/host-fakes.ts +0 -38
  319. package/src/testing/needs.ts +80 -0
  320. package/src/testing.ts +2 -0
  321. package/dist/api/unit-declaration.d.ts +0 -65
  322. package/dist/api/unit.d.ts +0 -85
  323. package/dist/api/unit.js +0 -8
  324. package/dist/api/workbench-contract.d.ts +0 -44
  325. package/dist/components/MockStrip.css +0 -39
  326. package/dist/components/MockStrip.d.ts +0 -15
  327. package/dist/components/MockStrip.js +0 -8
  328. package/dist/components/SaveBar.css +0 -7
  329. package/dist/host/browser-find.d.ts +0 -38
  330. package/dist/host/browser-find.js +0 -242
  331. package/dist/host/browser-read.d.ts +0 -28
  332. package/dist/host/browser-read.js +0 -243
  333. package/dist/host/opencli-runtime.d.ts +0 -25
  334. package/dist/host/opencli-runtime.js +0 -56
  335. package/dist/host/opencli-window.d.ts +0 -2
  336. package/dist/host/opencli-window.js +0 -8
  337. package/dist/host/opencli.d.ts +0 -37
  338. package/dist/host/opencli.js +0 -155
  339. package/dist/host/unit-declaration.js +0 -213
  340. package/dist/host/unit-libs.d.ts +0 -37
  341. package/dist/lib/diy-debug.d.ts +0 -80
  342. package/dist/lib/diy-debug.js +0 -88
  343. package/dist/lib/diy-record.d.ts +0 -135
  344. package/dist/lib/diy-record.js +0 -162
  345. package/dist/lib/lint-probe.d.ts +0 -1
  346. package/dist/lib/lint-probe.js +0 -6
  347. package/dist/lib/panel-state.d.ts +0 -120
  348. package/dist/lib/panel-state.js +0 -176
  349. package/src/api/__tests__/unit.test.ts +0 -38
  350. package/src/api/unit.ts +0 -93
  351. package/src/api/workbench-contract.ts +0 -59
  352. package/src/host/__tests__/browser-find.test.ts +0 -330
  353. package/src/host/__tests__/browser-read.test.ts +0 -228
  354. package/src/host/__tests__/opencli-runtime.test.ts +0 -46
  355. package/src/host/browser-find.ts +0 -311
  356. package/src/host/browser-read.ts +0 -311
  357. package/src/host/opencli-runtime.ts +0 -79
  358. package/src/host/opencli-window.ts +0 -11
  359. package/src/host/opencli.ts +0 -213
  360. package/src/host/unit-libs.ts +0 -41
  361. /package/dist/{api/blocker.js → contract/adapters.js} +0 -0
  362. /package/dist/{api → contract}/blocker.d.ts +0 -0
  363. /package/dist/{api/dsh-client.js → contract/blocker.js} +0 -0
  364. /package/dist/{api/unit-board.js → contract/cli.js} +0 -0
  365. /package/dist/{api/workbench-contract.js → contract/data.js} +0 -0
  366. /package/dist/{api → contract}/long-task.d.ts +0 -0
  367. /package/dist/{api → contract}/long-task.js +0 -0
  368. /package/dist/{host/unit-libs.js → contract/plugin-source.js} +0 -0
  369. /package/dist/{api → contract}/unit-board.d.ts +0 -0
  370. /package/src/{api → contract}/blocker.ts +0 -0
  371. /package/src/{api → contract}/long-task.ts +0 -0
@@ -0,0 +1,188 @@
1
+ import dayjs from 'dayjs';
2
+ export const CHANGELOG_FILE = 'CHANGELOG.md';
3
+ export const CHANGELOG_KINDS = ['added', 'changed', 'fixed', 'removed', 'security', 'deprecated'];
4
+ const KIND_LABELS = {
5
+ added: '✨ 新增',
6
+ changed: '⚡ 改进',
7
+ fixed: '🐛 修复',
8
+ removed: '🗑️ 移除',
9
+ security: '🔒 安全',
10
+ deprecated: '⚠️ 弃用',
11
+ };
12
+ const VERSION_HEADING = /^##[ \t]+\[?v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\]?[ \t]*(?:-[ \t]*.*)?$/;
13
+ const ANY_SECTION = /^##[ \t]/;
14
+ const SUBSECTION = /^###[ \t]/;
15
+ export function changelogVersion(value) {
16
+ return String(value ?? '')
17
+ .trim()
18
+ .replace(/^v/, '');
19
+ }
20
+ export function changelogDate(now = new Date()) {
21
+ return dayjs(now).format('YYYY-MM-DD');
22
+ }
23
+ export function normalizeChangelogText(text) {
24
+ return String(text ?? '').replace(/\r\n?/g, '\n');
25
+ }
26
+ function linesOf(text) {
27
+ return normalizeChangelogText(text).split('\n');
28
+ }
29
+ function bodyOf(rows) {
30
+ return rows.join('\n').trim();
31
+ }
32
+ function sectionRange(rows, version) {
33
+ const wanted = changelogVersion(version);
34
+ for (let index = 0; index < rows.length; index += 1) {
35
+ const row = rows[index] ?? '';
36
+ if (!ANY_SECTION.test(row))
37
+ continue;
38
+ const match = VERSION_HEADING.exec(row);
39
+ if (match === null || changelogVersion(match[1] ?? '') !== wanted)
40
+ continue;
41
+ let end = rows.length;
42
+ for (let next = index + 1; next < rows.length; next += 1) {
43
+ if (ANY_SECTION.test(rows[next] ?? '')) {
44
+ end = next;
45
+ break;
46
+ }
47
+ }
48
+ return { start: index, end };
49
+ }
50
+ return undefined;
51
+ }
52
+ export function changelogSkeleton() {
53
+ return '# 更新日志\n';
54
+ }
55
+ export function parseChangelog(text) {
56
+ const rows = linesOf(text);
57
+ const sections = [];
58
+ let current;
59
+ for (let index = 0; index < rows.length; index += 1) {
60
+ const row = rows[index] ?? '';
61
+ if (!ANY_SECTION.test(row))
62
+ continue;
63
+ if (current !== undefined) {
64
+ sections.push({ version: current.version, body: bodyOf(rows.slice(current.from, index)) });
65
+ }
66
+ const match = VERSION_HEADING.exec(row);
67
+ current =
68
+ match === null
69
+ ? undefined
70
+ : { version: changelogVersion(match[1] ?? ''), from: index + 1 };
71
+ }
72
+ if (current !== undefined) {
73
+ sections.push({ version: current.version, body: bodyOf(rows.slice(current.from)) });
74
+ }
75
+ return sections;
76
+ }
77
+ export function changelogSectionOf(text, version) {
78
+ const wanted = changelogVersion(version);
79
+ return parseChangelog(text).find((one) => one.version === wanted)?.body;
80
+ }
81
+ export function changelogHasEntry(text, version) {
82
+ const body = changelogSectionOf(text, version);
83
+ if (body === undefined)
84
+ return false;
85
+ return body
86
+ .split('\n')
87
+ .map((one) => one.trim())
88
+ .some((one) => one !== '' && !one.startsWith('#') && !one.startsWith('<!--') && !/^`[^`]*`$/.test(one));
89
+ }
90
+ function bulletsOf(note) {
91
+ return note
92
+ .split('\n')
93
+ .map((one) => one.trim())
94
+ .filter((one) => one !== '')
95
+ .map((one) => `- ${one}`);
96
+ }
97
+ function blockOf(options, label, bullets) {
98
+ const date = (options.date ?? '').trim();
99
+ return [
100
+ `## v${changelogVersion(options.version)}`,
101
+ ...(date === '' ? [] : ['', `\`${date}\``]),
102
+ '',
103
+ `### ${label}`,
104
+ '',
105
+ ...bullets,
106
+ ];
107
+ }
108
+ function insertBlock(rows, at, block) {
109
+ const before = rows.slice(0, at);
110
+ while (before.length > 0 && (before[before.length - 1] ?? '').trim() === '')
111
+ before.pop();
112
+ const after = rows.slice(at);
113
+ while (after.length > 0 && (after[0] ?? '').trim() === '')
114
+ after.shift();
115
+ const out = [...before];
116
+ if (out.length > 0)
117
+ out.push('');
118
+ out.push(...block);
119
+ if (after.length > 0) {
120
+ out.push('');
121
+ out.push(...after);
122
+ }
123
+ return out;
124
+ }
125
+ function newSectionAt(rows) {
126
+ for (let index = 0; index < rows.length; index += 1) {
127
+ if (/^##[ \t]+\[?unreleased\]?[ \t]*$/i.test(rows[index] ?? '')) {
128
+ for (let next = index + 1; next < rows.length; next += 1) {
129
+ if (ANY_SECTION.test(rows[next] ?? ''))
130
+ return next;
131
+ }
132
+ return rows.length;
133
+ }
134
+ }
135
+ for (let index = 0; index < rows.length; index += 1) {
136
+ if (ANY_SECTION.test(rows[index] ?? ''))
137
+ return index;
138
+ }
139
+ return rows.length;
140
+ }
141
+ export function appendChangelogEntry(text, options) {
142
+ const kind = options.kind ?? 'changed';
143
+ const label = KIND_LABELS[kind];
144
+ const bullets = bulletsOf(options.note);
145
+ if (bullets.length === 0)
146
+ return normalizeChangelogText(text);
147
+ const blocks = blockOf(options, label, bullets);
148
+ const source = normalizeChangelogText(text).trim() === '' ? changelogSkeleton() : normalizeChangelogText(text);
149
+ const rows = linesOf(source);
150
+ const range = sectionRange(rows, options.version);
151
+ if (range === undefined)
152
+ return `${insertBlock(rows, newSectionAt(rows), blocks).join('\n').replace(/\n+$/, '')}\n`;
153
+ let subsection = -1;
154
+ for (let index = range.start + 1; index < range.end; index += 1) {
155
+ const heading = (rows[index] ?? '').trim();
156
+ if (SUBSECTION.test(heading) && heading.includes(label)) {
157
+ subsection = index;
158
+ break;
159
+ }
160
+ }
161
+ if (subsection === -1) {
162
+ const out = [...rows];
163
+ out.splice(range.end, 0, '', `### ${label}`, '', ...bullets);
164
+ return `${normalizeWhitespace(out)}\n`;
165
+ }
166
+ let end = range.end;
167
+ for (let index = subsection + 1; index < range.end; index += 1) {
168
+ if (SUBSECTION.test(rows[index] ?? '')) {
169
+ end = index;
170
+ break;
171
+ }
172
+ }
173
+ const out = [...rows];
174
+ let at = end;
175
+ while (at > subsection + 1 && (out[at - 1] ?? '').trim() === '')
176
+ at -= 1;
177
+ out.splice(at, 0, ...bullets);
178
+ return `${normalizeWhitespace(out)}\n`;
179
+ }
180
+ function normalizeWhitespace(rows) {
181
+ const out = [];
182
+ for (const row of rows) {
183
+ if (row.trim() === '' && out.length > 0 && (out[out.length - 1] ?? '').trim() === '')
184
+ continue;
185
+ out.push(row);
186
+ }
187
+ return out.join('\n').replace(/\n+$/, '');
188
+ }
@@ -0,0 +1,15 @@
1
+ export declare const CHANNEL_PLUGIN_NAME = "opencli-plugin-workbench";
2
+ export declare const CHANNEL_PLUGIN_SITE = "workbench";
3
+ export interface ChannelPluginPlan {
4
+ readonly dest: string;
5
+ readonly version: string;
6
+ readonly commands: readonly string[];
7
+ readonly line: string;
8
+ }
9
+ export declare function channelVersionOf(dir: string): string | undefined;
10
+ export declare function channelPluginPlan(options: {
11
+ readonly channelDir: string;
12
+ readonly command?: string;
13
+ }): ChannelPluginPlan | undefined;
14
+ export declare function channelInstalledVersion(): string | undefined;
15
+ export declare function channelSiteInstalled(): boolean;
@@ -0,0 +1,42 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { isolatedHome, toolchainOpencliDir, vendorPeerLink, vendorPluginsDir } from './paths.js';
4
+ import { quoteShellArg } from './shell-text.js';
5
+ export const CHANNEL_PLUGIN_NAME = 'opencli-plugin-workbench';
6
+ export const CHANNEL_PLUGIN_SITE = 'workbench';
7
+ function textOf(value) {
8
+ return typeof value === 'string' ? value.trim() : '';
9
+ }
10
+ export function channelVersionOf(dir) {
11
+ try {
12
+ const parsed = JSON.parse(readFileSync(join(dir, 'opencli-plugin.json'), 'utf8'));
13
+ if (typeof parsed !== 'object' || parsed === null)
14
+ return undefined;
15
+ const version = textOf(parsed['version']);
16
+ return version === '' ? undefined : version;
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ export function channelPluginPlan(options) {
23
+ const version = channelVersionOf(options.channelDir);
24
+ if (version === undefined)
25
+ return undefined;
26
+ const command = options.command ?? 'opencli';
27
+ const dest = join(vendorPluginsDir(), CHANNEL_PLUGIN_NAME);
28
+ const peer = vendorPeerLink();
29
+ const commands = [
30
+ `rm -rf ${quoteShellArg(dest)} && mkdir -p ${quoteShellArg(dest)} && cp -R ${quoteShellArg(options.channelDir)}/. ${quoteShellArg(dest)}/`,
31
+ `rm -rf ${quoteShellArg(peer.dir)} && mkdir -p ${quoteShellArg(peer.parent)} && ln -s ${quoteShellArg(toolchainOpencliDir())} ${quoteShellArg(peer.dir)}`,
32
+ `(${quoteShellArg(command)} plugin uninstall ${quoteShellArg(CHANNEL_PLUGIN_SITE)} || true)`,
33
+ `${quoteShellArg(command)} plugin install ${quoteShellArg(dest)}`,
34
+ ];
35
+ return { dest, version, commands, line: commands.join(' && ') };
36
+ }
37
+ export function channelInstalledVersion() {
38
+ return channelVersionOf(join(vendorPluginsDir(), CHANNEL_PLUGIN_NAME));
39
+ }
40
+ export function channelSiteInstalled() {
41
+ return existsSync(join(isolatedHome(), '.opencli', 'plugins', CHANNEL_PLUGIN_SITE));
42
+ }
@@ -0,0 +1,4 @@
1
+ import type { DshHostContext } from '../api/dsh.js';
2
+ import type { CliPort } from '../contract/cli.js';
3
+ export declare function cliPortOf(ctx: DshHostContext): CliPort;
4
+ export declare function cliCommandOf(ctx: DshHostContext): string;
@@ -0,0 +1,7 @@
1
+ import { adaptersOf } from './adapters.js';
2
+ export function cliPortOf(ctx) {
3
+ return { command: adaptersOf(ctx).runtime.opencliCommand(ctx).command };
4
+ }
5
+ export function cliCommandOf(ctx) {
6
+ return cliPortOf(ctx).command;
7
+ }
@@ -0,0 +1 @@
1
+ export declare function commandNamesMatch(declared: string, resolved: string): boolean;
@@ -0,0 +1,14 @@
1
+ function baseName(value) {
2
+ const parts = value.trim().split(/[\\/]/);
3
+ return parts[parts.length - 1] ?? '';
4
+ }
5
+ function isOpencli(name) {
6
+ return name === 'opencli' || name === 'opencli.cmd' || name === 'opencli.exe';
7
+ }
8
+ export function commandNamesMatch(declared, resolved) {
9
+ const left = baseName(declared);
10
+ const right = baseName(resolved);
11
+ if (left === '' || right === '')
12
+ return false;
13
+ return left === right || (isOpencli(left) && isOpencli(right));
14
+ }
@@ -0,0 +1,13 @@
1
+ export declare class WorkbenchDataError extends Error {
2
+ readonly code: string;
3
+ readonly detail?: string;
4
+ readonly hint?: string;
5
+ readonly project?: unknown;
6
+ readonly helpUrl?: string;
7
+ constructor(code: string, message: string, extra?: {
8
+ detail?: string;
9
+ hint?: string;
10
+ project?: unknown;
11
+ helpUrl?: string;
12
+ });
13
+ }
@@ -0,0 +1,20 @@
1
+ export class WorkbenchDataError extends Error {
2
+ code;
3
+ detail;
4
+ hint;
5
+ project;
6
+ helpUrl;
7
+ constructor(code, message, extra = {}) {
8
+ super(message);
9
+ this.name = 'WorkbenchDataError';
10
+ this.code = code;
11
+ if (extra.detail !== undefined)
12
+ this.detail = extra.detail;
13
+ if (extra.hint !== undefined)
14
+ this.hint = extra.hint;
15
+ if (extra.project !== undefined)
16
+ this.project = extra.project;
17
+ if (extra.helpUrl !== undefined)
18
+ this.helpUrl = extra.helpUrl;
19
+ }
20
+ }
@@ -5,6 +5,9 @@ export function dshHome() {
5
5
  return `${process.env.HOME ?? ''}/.dsh`;
6
6
  }
7
7
  export function workbenchRoot() {
8
+ const configured = process.env.DSH_WORKBENCH_HOME?.trim();
9
+ if (configured !== undefined && configured !== '')
10
+ return configured;
8
11
  return `${dshHome()}/workbench`;
9
12
  }
10
13
  export function workspacesRoot() {
@@ -1,3 +1,4 @@
1
+ import { clockOf } from './time.js';
1
2
  /**
2
3
  * 把工具入参收成人话动作。
3
4
  * @param value - 任意入参值。
@@ -84,5 +85,5 @@ export function createDebugStore() {
84
85
  * @returns 形如「会话 x(自 HH:mm:ssZ 起在调试 y)」的中文串。
85
86
  */
86
87
  export function debugOwnerText(state) {
87
- return `会话 ${state.sessionId}(自 ${new Date(state.startedAt).toISOString().slice(11, 19)}Z 起在调试 ${state.unit})`;
88
+ return `会话 ${state.sessionId}(自 ${clockOf(state.startedAt)}Z 起在调试 ${state.unit})`;
88
89
  }
@@ -1,3 +1,4 @@
1
+ import { clockOf } from './time.js';
1
2
  /**
2
3
  * 录制约定的有效期(15 分钟,毫秒):超过它没动静的约定算过期、当场让人。
3
4
  */
@@ -157,6 +158,6 @@ export function createRecordStore() {
157
158
  * @returns 形如「会话 x(自 HH:mm:ssZ 起在录 y 的「动作」)」的中文串。
158
159
  */
159
160
  export function recordOwnerText(state) {
160
- const at = new Date(state.startedAt).toISOString().slice(11, 19);
161
+ const at = clockOf(state.startedAt);
161
162
  return `会话 ${state.sessionId}(自 ${at}Z 起在录 ${state.unit} 的「${state.action}」)`;
162
163
  }
@@ -1,4 +1,4 @@
1
- import type { UnitManifest } from '../api/unit.js';
1
+ import type { UnitManifest } from '../contract/unit.js';
2
2
  export interface FactChange {
3
3
  readonly rev: number;
4
4
  readonly facts: readonly string[];
@@ -1,6 +1,7 @@
1
- import { FACT_SCOPE_SUFFIX } from '../api/facts.js';
1
+ import { randomUUID } from 'node:crypto';
2
+ import { FACT_SCOPE_SUFFIX } from '../contract/facts.js';
2
3
  export function createFactLog(options = {}) {
3
- const epoch = options.epoch ?? `e${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
4
+ const epoch = options.epoch ?? `e${randomUUID()}`;
4
5
  let rev = 0;
5
6
  const last = new Map();
6
7
  const listeners = new Set();
package/dist/host/git.js CHANGED
@@ -1,5 +1,5 @@
1
- import { quoteShellArg, tailLines } from './shell-text.js';
2
- import { runShell } from './shell.js';
1
+ import { quoteShellArg, tailLines } from '../host/shell-text.js';
2
+ import { runShell } from '../host/shell.js';
3
3
  export function createHeadReader(options) {
4
4
  const { shell, logger } = options;
5
5
  return async function readHead(path) {
package/dist/host/http.js CHANGED
@@ -2,7 +2,7 @@ import { unitFactScope } from './facts.js';
2
2
  import { parseCardsReport, parseCrashReport } from './panel-state.js';
3
3
  import { ACTIONS_PREFIX, API_PREFIX, DIY_DEBUG_PATH, DIY_RECORD_PATH, PANEL_STATE_PREFIX, PLUGIN_ID, PREFS_PREFIX, PROVISION_PREFIX } from '../config/constants.js';
4
4
  import { parseProvisionBody, } from './provision.js';
5
- import { WorkbenchDataError } from '../host/opencli.js';
5
+ import { WorkbenchDataError } from './data-error.js';
6
6
  import { writeResultForClient } from './write-result.js';
7
7
  const MAX_PREFS_BODY_BYTES = 8 * 1024;
8
8
  const PROVISION_FACTS = ['capability', 'panels'];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 跨平台库的「能力 → 首选实现」表:外壳 arch 的 S68 与 DIY 模块的 `source` 判据共用这一份,
3
+ * 避免两边各写一张表后漂开。
4
+ *
5
+ * 能力名是「做什么」,`preferred` 是「用什么」;两者不是同一个层级(类似 datetime → dayjs)。
6
+ * 手写轮子的指纹只认最常见的直连写法;`importsPreferred()` 负责判断这个文件是否已经在用首选库。
7
+ */
8
+ export interface LibCapability {
9
+ readonly capability: string;
10
+ readonly preferred: string;
11
+ readonly pattern: RegExp;
12
+ readonly why: string;
13
+ }
14
+ /** 手写轮子的硬指纹;按能力名稳定排序,方便两边报告与测试对照。 */
15
+ export declare const LIB_CAPABILITIES: readonly LibCapability[];
16
+ /**
17
+ * 这个文件是否已经 import 了某个首选库(静态或动态 import 都算)。
18
+ * @param source 文件全文。
19
+ * @param preferred 首选库包名。
20
+ * @returns 有 import 就 `true`。
21
+ */
22
+ export declare function importsPreferred(source: string, preferred: string): boolean;
@@ -0,0 +1,37 @@
1
+ /** 手写轮子的硬指纹;按能力名稳定排序,方便两边报告与测试对照。 */
2
+ export const LIB_CAPABILITIES = [
3
+ {
4
+ capability: 'process-spawn',
5
+ preferred: 'execa',
6
+ pattern: /from\s+['"]node:child_process['"]/,
7
+ why: '自己起进程要用 execa;同步/跨平台差异交给它',
8
+ },
9
+ {
10
+ capability: 'cli-locate',
11
+ preferred: 'which',
12
+ pattern: /\bprocess\.env\.(?:PATH|PATHEXT)\b/,
13
+ why: '自己扫 PATH/PATHEXT 要用 which(它处理 PATHEXT 与 Path 大小写)',
14
+ },
15
+ {
16
+ capability: 'file-lock',
17
+ preferred: 'proper-lockfile',
18
+ pattern: /\bprocess\.kill\([^)]*,\s*0\)|flag:\s*['"]wx['"]/,
19
+ why: '自己抢文件锁要用 proper-lockfile(stale / 重试 / 跨平台)',
20
+ },
21
+ {
22
+ capability: 'atomic-state',
23
+ preferred: 'write-file-atomic',
24
+ pattern: /writeFileSync\([^)]*\.(?:sync\.json|self-update\.json)/,
25
+ why: '自己直写状态文件要用 write-file-atomic(防写一半)',
26
+ },
27
+ ];
28
+ /**
29
+ * 这个文件是否已经 import 了某个首选库(静态或动态 import 都算)。
30
+ * @param source 文件全文。
31
+ * @param preferred 首选库包名。
32
+ * @returns 有 import 就 `true`。
33
+ */
34
+ export function importsPreferred(source, preferred) {
35
+ const escaped = preferred.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
36
+ return new RegExp(`(?:from\\s*|import\\s*\\(\\s*)['"]${escaped}['"]`).test(source);
37
+ }
@@ -0,0 +1,9 @@
1
+ import type { LibNeed, SupplySource } from '../contract/needs.js';
2
+ export type NpmSource = Extract<SupplySource, {
3
+ kind: 'npm';
4
+ }>;
5
+ export declare function libInstallCommand(options: {
6
+ readonly need: LibNeed;
7
+ readonly source: NpmSource;
8
+ readonly version?: string | undefined;
9
+ }): string;
@@ -0,0 +1,10 @@
1
+ import { npmRegistryOf } from './plugin-source.js';
2
+ import { quoteShellArg } from './shell-text.js';
3
+ import { libsPrefix, npmCacheDir } from './paths.js';
4
+ export function libInstallCommand(options) {
5
+ const { need, source, version } = options;
6
+ const registry = npmRegistryOf(source, process.env);
7
+ const spec = version ?? need.version ?? 'latest';
8
+ const registryFlag = registry.ok ? ` --registry ${quoteShellArg(registry.value)}` : '';
9
+ return `npm i --prefix ${quoteShellArg(libsPrefix())} ${quoteShellArg(`${need.name}@${spec}`)}${registryFlag} --cache ${quoteShellArg(npmCacheDir())}`;
10
+ }
@@ -1,4 +1,4 @@
1
- import { type LongTaskStatus, type LongTaskStep } from '../api/long-task.js';
1
+ import { type LongTaskStatus, type LongTaskStep } from '../contract/long-task.js';
2
2
  export interface LongTaskBase {
3
3
  readonly id: string;
4
4
  readonly workspace: string;
@@ -1,4 +1,5 @@
1
- import { runsRouteOf } from '../api/long-task.js';
1
+ import { epochOf } from './time.js';
2
+ import { runsRouteOf } from '../contract/long-task.js';
2
3
  const LIVE = new Set(['running', 'needs-login']);
3
4
  const RECENT_MS = 10 * 60 * 1000;
4
5
  export function createLongTaskRegistry(deps) {
@@ -43,7 +44,7 @@ export function createLongTaskRegistry(deps) {
43
44
  return null;
44
45
  },
45
46
  current(workspace) {
46
- const floor = Date.parse(now()) - recentMs;
47
+ const floor = epochOf(now()) - recentMs;
47
48
  const newest = new Map();
48
49
  for (const snapshot of runs.values()) {
49
50
  if (snapshot.workspace !== workspace)
@@ -51,7 +52,7 @@ export function createLongTaskRegistry(deps) {
51
52
  newest.set(snapshot.target, snapshot);
52
53
  }
53
54
  return [...newest.values()]
54
- .filter((snapshot) => LIVE.has(snapshot.status) || Date.parse(snapshot.at) >= floor)
55
+ .filter((snapshot) => LIVE.has(snapshot.status) || epochOf(snapshot.at) >= floor)
55
56
  .reverse()
56
57
  .map((snapshot) => ({ ...deps.view(snapshot), id: snapshot.id }));
57
58
  },
@@ -0,0 +1,22 @@
1
+ import type { DiscoverFilter, IndexSourceSpec, MarketIndex, MarketIndexEntry, MarketIndexParse, MarketIndexProblem, MarketIndexVersion, MarketSourceConfig } from '../contract/protocol/market-index.js';
2
+ export { marketBranchOk, marketInstallTarget, marketText } from '../lib/market-index.js';
3
+ export declare const MARKET_INDEX_SEED = "{\n \"format\": 1,\n \"plugins\": []\n}\n";
4
+ export declare const MARKET_INDEX_README_LINES: readonly string[];
5
+ export declare function compareSemver(left: string, right: string): number | undefined;
6
+ export declare function parseMarketIndex(raw: unknown): MarketIndexParse;
7
+ export declare function parseMarketIndexJson(text: string): MarketIndexParse;
8
+ export declare function sortMarketVersions(versions: readonly MarketIndexVersion[]): MarketIndexVersion[];
9
+ export declare function upsertMarketEntry(index: MarketIndex, entry: MarketIndexEntry): MarketIndex;
10
+ export declare function marketEntryLabels(entry: MarketIndexEntry): readonly string[];
11
+ export declare function filterMarketIndex(index: MarketIndex, filter: DiscoverFilter): readonly MarketIndexEntry[];
12
+ export declare function marketSourceKey(source: IndexSourceSpec): string;
13
+ export type SourceConfigParse = {
14
+ readonly ok: true;
15
+ readonly source: MarketSourceConfig;
16
+ } | {
17
+ readonly ok: false;
18
+ readonly problem: MarketIndexProblem;
19
+ };
20
+ export declare function parseSourceConfig(raw: unknown): SourceConfigParse;
21
+ export declare function httpUrlProblem(url: string): string | undefined;
22
+ export declare function gitUrlOk(url: string): boolean;