@dsh-workbench/shared 0.3.10 → 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 (391) 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 +19 -1
  6. package/dist/api/host-write.d.ts +0 -15
  7. package/dist/api/host-write.js +1 -35
  8. package/dist/api/workbench-client.js +2 -1
  9. package/dist/components/Activity.css +0 -1
  10. package/dist/components/ApprovalDetail.css +1 -2
  11. package/dist/components/ApprovalDetail.d.ts +1 -1
  12. package/dist/components/ApprovalPlan.css +0 -1
  13. package/dist/components/Card.css +0 -1
  14. package/dist/components/Card.d.ts +1 -1
  15. package/dist/components/CardBoundary.d.ts +1 -1
  16. package/dist/components/CardHead.css +0 -1
  17. package/dist/components/CardHead.d.ts +1 -1
  18. package/dist/components/ChoiceGroup.css +1 -2
  19. package/dist/components/ConfirmBar.d.ts +1 -1
  20. package/dist/components/ConfirmBar.js +1 -1
  21. package/dist/components/Form.css +1 -1
  22. package/dist/components/FormActions.js +1 -1
  23. package/dist/components/LongTaskRow.css +1 -2
  24. package/dist/components/LongTaskRow.d.ts +1 -1
  25. package/dist/components/LongTaskRow.js +1 -1
  26. package/dist/components/Note.css +0 -1
  27. package/dist/components/ResourceStates.css +0 -1
  28. package/dist/components/SettingsSection.css +0 -1
  29. package/dist/components/Spinner.css +0 -1
  30. package/dist/components/Stack.css +0 -1
  31. package/dist/components/StateBlock.css +0 -1
  32. package/dist/components/board-module.d.ts +3 -3
  33. package/dist/components/icons.d.ts +1 -7
  34. package/dist/components/icons.js +11 -16
  35. package/dist/config/constants.d.ts +2 -2
  36. package/dist/config/constants.js +2 -2
  37. package/dist/config/storage.d.ts +0 -4
  38. package/dist/config/storage.js +0 -11
  39. package/dist/contract/adapters.d.ts +10 -0
  40. package/dist/contract/cli.d.ts +3 -0
  41. package/dist/contract/data.d.ts +126 -0
  42. package/dist/{api → contract}/facts.d.ts +12 -3
  43. package/dist/{api → contract}/facts.js +19 -1
  44. package/dist/contract/needs.d.ts +132 -0
  45. package/dist/contract/needs.js +232 -0
  46. package/dist/contract/plugin-source.d.ts +1 -0
  47. package/dist/contract/plugin-source.js +1 -0
  48. package/dist/contract/protocol/bundle-install.d.ts +136 -0
  49. package/dist/contract/protocol/bundle-install.js +12 -0
  50. package/dist/contract/protocol/config-sync.d.ts +55 -0
  51. package/dist/contract/protocol/config-sync.js +2 -0
  52. package/dist/contract/protocol/diy.d.ts +4 -0
  53. package/dist/contract/protocol/diy.js +4 -0
  54. package/dist/contract/protocol/dsh-plugins.d.ts +11 -0
  55. package/dist/contract/protocol/dsh-plugins.js +1 -0
  56. package/dist/contract/protocol/long-tasks.d.ts +13 -0
  57. package/dist/contract/protocol/long-tasks.js +1 -0
  58. package/dist/contract/protocol/market-index.d.ts +195 -0
  59. package/dist/contract/protocol/market-index.js +7 -0
  60. package/dist/contract/protocol/platform.d.ts +44 -0
  61. package/dist/contract/protocol/platform.js +1 -0
  62. package/dist/contract/protocol/preflight-wake.d.ts +7 -0
  63. package/dist/contract/protocol/preflight-wake.js +1 -0
  64. package/dist/contract/protocol/profile-create.d.ts +30 -0
  65. package/dist/contract/protocol/profile-create.js +2 -0
  66. package/dist/contract/protocol/sidebar-edition.d.ts +14 -0
  67. package/dist/contract/protocol/sidebar-edition.js +2 -0
  68. package/dist/contract/protocol/unit-manifests.d.ts +6 -0
  69. package/dist/contract/protocol/unit-manifests.js +1 -0
  70. package/dist/contract/unit-board.d.ts +18 -0
  71. package/dist/contract/unit-board.js +1 -0
  72. package/dist/contract/unit-capability.d.ts +34 -0
  73. package/dist/contract/unit-capability.js +1 -0
  74. package/dist/{api → contract}/unit-declaration.d.ts +7 -5
  75. package/dist/{api → contract}/unit-declaration.js +19 -13
  76. package/dist/contract/unit.d.ts +57 -0
  77. package/dist/contract/unit.js +24 -0
  78. package/dist/contract/workbench-contract.d.ts +15 -0
  79. package/dist/contract/workbench-contract.js +1 -0
  80. package/dist/host/adapter-set.d.ts +26 -0
  81. package/dist/host/adapter-set.js +243 -0
  82. package/dist/host/adapter-types.d.ts +79 -0
  83. package/dist/host/adapter-types.js +23 -0
  84. package/dist/host/adapters.d.ts +22 -0
  85. package/dist/host/adapters.js +9 -0
  86. package/dist/host/browser.d.ts +3 -0
  87. package/dist/host/browser.js +3 -0
  88. package/dist/host/changelog.d.ts +21 -0
  89. package/dist/host/changelog.js +188 -0
  90. package/dist/host/channel-plugin.d.ts +15 -0
  91. package/dist/host/channel-plugin.js +42 -0
  92. package/dist/host/cli.d.ts +4 -0
  93. package/dist/host/cli.js +7 -0
  94. package/dist/host/command-name.d.ts +1 -0
  95. package/dist/host/command-name.js +14 -0
  96. package/dist/host/data-error.d.ts +13 -0
  97. package/dist/host/data-error.js +20 -0
  98. package/dist/host/data-root.js +3 -0
  99. package/dist/host/diy-debug.js +2 -1
  100. package/dist/host/diy-record.js +2 -1
  101. package/dist/host/facts.d.ts +1 -1
  102. package/dist/host/facts.js +3 -2
  103. package/dist/host/git.js +2 -2
  104. package/dist/host/http.js +1 -1
  105. package/dist/host/lib-capabilities.d.ts +22 -0
  106. package/dist/host/lib-capabilities.js +37 -0
  107. package/dist/host/lib-install.d.ts +9 -0
  108. package/dist/host/lib-install.js +10 -0
  109. package/dist/host/long-task.d.ts +1 -1
  110. package/dist/host/long-task.js +4 -3
  111. package/dist/host/market-index.d.ts +22 -0
  112. package/dist/host/market-index.js +420 -0
  113. package/dist/host/needs.d.ts +4 -0
  114. package/dist/host/needs.js +2 -0
  115. package/dist/host/patch.d.ts +9 -0
  116. package/dist/host/patch.js +78 -0
  117. package/dist/host/paths.d.ts +12 -0
  118. package/dist/host/paths.js +28 -0
  119. package/dist/host/platform.d.ts +14 -0
  120. package/dist/host/platform.js +40 -0
  121. package/dist/host/plugin-source.d.ts +8 -6
  122. package/dist/host/plugin-source.js +43 -33
  123. package/dist/host/plugin.d.ts +4 -0
  124. package/dist/host/plugin.js +39 -0
  125. package/dist/host/port-types.d.ts +191 -0
  126. package/dist/host/port-types.js +1 -0
  127. package/dist/host/preflight.d.ts +28 -0
  128. package/dist/host/preflight.js +1 -0
  129. package/dist/host/profile-port.d.ts +4 -0
  130. package/dist/host/profile-port.js +4 -0
  131. package/dist/host/provision.d.ts +2 -2
  132. package/dist/host/provision.js +5 -3
  133. package/dist/host/recipe-rules.d.ts +5 -0
  134. package/dist/host/recipe-rules.js +382 -0
  135. package/dist/host/recipe.d.ts +14 -0
  136. package/dist/host/recipe.js +283 -0
  137. package/dist/host/shell-text.d.ts +9 -2
  138. package/dist/host/shell-text.js +15 -3
  139. package/dist/host/shell.d.ts +2 -0
  140. package/dist/host/shell.js +7 -0
  141. package/dist/host/spec.d.ts +8 -0
  142. package/dist/host/spec.js +24 -0
  143. package/dist/host/supply-index.d.ts +34 -0
  144. package/dist/host/supply-index.js +202 -0
  145. package/dist/host/supply-port.d.ts +5 -0
  146. package/dist/host/supply-port.js +39 -0
  147. package/dist/host/time.d.ts +12 -0
  148. package/dist/host/time.js +19 -0
  149. package/dist/host/tokens.d.ts +26 -0
  150. package/dist/host/tokens.js +154 -0
  151. package/dist/host/tool-approval.d.ts +12 -0
  152. package/dist/host/tool-approval.js +4 -0
  153. package/dist/host/tool-kit.js +1 -1
  154. package/dist/host/unit-face.d.ts +5 -4
  155. package/dist/host/version-range.d.ts +2 -0
  156. package/dist/host/version-range.js +73 -0
  157. package/dist/host/version.d.ts +3 -0
  158. package/dist/host/version.js +29 -0
  159. package/dist/host.d.ts +47 -16
  160. package/dist/host.js +47 -16
  161. package/dist/i18n/en.js +259 -86
  162. package/dist/i18n/index.d.ts +333 -88
  163. package/dist/i18n/merge.js +1 -1
  164. package/dist/i18n/need-text.d.ts +26 -0
  165. package/dist/i18n/need-text.js +26 -0
  166. package/dist/i18n/settings.d.ts +70 -0
  167. package/dist/i18n/settings.js +136 -0
  168. package/dist/i18n/zh.d.ts +332 -87
  169. package/dist/i18n/zh.js +260 -87
  170. package/dist/index.d.ts +24 -8
  171. package/dist/index.js +24 -8
  172. package/dist/lib/blocker-action.d.ts +0 -15
  173. package/dist/lib/blocker-action.js +1 -25
  174. package/dist/{api → lib}/dsh-client.d.ts +12 -1
  175. package/dist/lib/dsh-client.js +1 -0
  176. package/dist/lib/market-index.d.ts +7 -0
  177. package/dist/lib/market-index.js +25 -0
  178. package/dist/lib/react-types.d.ts +5 -0
  179. package/dist/lib/react-types.js +1 -0
  180. package/dist/lib/react.d.ts +1 -40
  181. package/dist/lib/react.js +0 -36
  182. package/dist/lib/ui.js +3 -9
  183. package/dist/testing/data.d.ts +13 -0
  184. package/dist/testing/data.js +46 -0
  185. package/dist/testing/declaration.d.ts +1 -1
  186. package/dist/testing/declaration.js +1 -1
  187. package/dist/testing/host-fakes.d.ts +0 -13
  188. package/dist/testing/host-fakes.js +0 -24
  189. package/dist/testing/needs.d.ts +16 -0
  190. package/dist/testing/needs.js +46 -0
  191. package/dist/testing.d.ts +2 -0
  192. package/dist/testing.js +2 -0
  193. package/package.json +18 -2
  194. package/src/api/__tests__/blocker-table.test.ts +135 -86
  195. package/src/api/blocker-table.ts +52 -26
  196. package/src/api/dsh.ts +17 -1
  197. package/src/api/host-write.ts +0 -43
  198. package/src/api/workbench-client.test.ts +2 -2
  199. package/src/api/workbench-client.ts +2 -1
  200. package/src/components/Activity.css +0 -1
  201. package/src/components/ApprovalDetail.css +1 -2
  202. package/src/components/ApprovalDetail.tsx +1 -1
  203. package/src/components/ApprovalPlan.css +0 -1
  204. package/src/components/Card.css +0 -1
  205. package/src/components/Card.tsx +1 -1
  206. package/src/components/CardAnchor.test.tsx +1 -1
  207. package/src/components/CardBoundary.tsx +1 -1
  208. package/src/components/CardHead.css +0 -1
  209. package/src/components/CardHead.tsx +1 -1
  210. package/src/components/ChoiceGroup.css +1 -2
  211. package/src/components/ConfirmBar.tsx +1 -1
  212. package/src/components/Form.css +1 -1
  213. package/src/components/Form.tsx +1 -1
  214. package/src/components/FormActions.tsx +1 -1
  215. package/src/components/LongTaskRow.css +1 -2
  216. package/src/components/LongTaskRow.tsx +1 -1
  217. package/src/components/Note.css +0 -1
  218. package/src/components/ResourceStates.css +0 -1
  219. package/src/components/SelectFieldNodes.tsx +0 -1
  220. package/src/components/SettingsSection.css +0 -1
  221. package/src/components/Spinner.css +0 -1
  222. package/src/components/Stack.css +0 -1
  223. package/src/components/StateBlock.css +0 -1
  224. package/src/components/__tests__/long-task-row.test.ts +1 -1
  225. package/src/components/board-module.ts +3 -3
  226. package/src/components/icons.tsx +16 -24
  227. package/src/config/constants.ts +2 -2
  228. package/src/config/storage.test.ts +1 -25
  229. package/src/config/storage.ts +0 -12
  230. package/src/{api → contract}/__tests__/facts.test.ts +73 -25
  231. package/src/{api → contract}/__tests__/long-task.test.ts +3 -3
  232. package/src/contract/__tests__/needs.test.ts +74 -0
  233. package/src/{host → contract}/__tests__/unit-declaration.test.ts +1 -1
  234. package/src/contract/__tests__/unit.test.ts +43 -0
  235. package/src/contract/adapters.ts +9 -0
  236. package/src/contract/cli.ts +3 -0
  237. package/src/contract/data.ts +145 -0
  238. package/src/{api → contract}/facts.ts +34 -4
  239. package/src/contract/needs.ts +331 -0
  240. package/src/contract/plugin-source.ts +1 -0
  241. package/src/contract/protocol/bundle-install.ts +198 -0
  242. package/src/contract/protocol/config-sync.ts +65 -0
  243. package/src/contract/protocol/diy.ts +4 -0
  244. package/src/contract/protocol/dsh-plugins.ts +13 -0
  245. package/src/contract/protocol/long-tasks.ts +16 -0
  246. package/src/contract/protocol/market-index.ts +246 -0
  247. package/src/contract/protocol/platform.ts +47 -0
  248. package/src/contract/protocol/preflight-wake.ts +17 -0
  249. package/src/contract/protocol/profile-create.ts +36 -0
  250. package/src/contract/protocol/sidebar-edition.ts +19 -0
  251. package/src/contract/protocol/unit-manifests.ts +8 -0
  252. package/src/contract/unit-board.ts +23 -0
  253. package/src/contract/unit-capability.ts +37 -0
  254. package/src/{host → contract}/unit-declaration.ts +22 -18
  255. package/src/contract/unit.ts +76 -0
  256. package/src/contract/workbench-contract.ts +30 -0
  257. package/src/host/__tests__/adapter-set.test.ts +228 -0
  258. package/src/host/__tests__/adapters.test.ts +27 -0
  259. package/src/host/__tests__/changelog.test.ts +102 -0
  260. package/src/host/__tests__/command-name.test.ts +16 -0
  261. package/src/host/__tests__/diy-record.test.ts +3 -3
  262. package/src/host/__tests__/facts.test.ts +5 -5
  263. package/src/host/__tests__/long-task.test.ts +1 -1
  264. package/src/host/__tests__/market-index.test.ts +179 -0
  265. package/src/host/__tests__/plugin-ledger.test.ts +10 -10
  266. package/src/host/__tests__/provision.test.ts +7 -6
  267. package/src/host/__tests__/shell-text.test.ts +16 -1
  268. package/src/host/__tests__/supply-index.test.ts +137 -0
  269. package/src/host/__tests__/tokens.test.ts +110 -0
  270. package/src/host/__tests__/version-range.test.ts +21 -0
  271. package/src/host/adapter-set.ts +298 -0
  272. package/src/host/adapter-types.ts +105 -0
  273. package/src/host/adapters.ts +44 -0
  274. package/src/host/browser.ts +3 -0
  275. package/src/host/changelog.ts +212 -0
  276. package/src/host/channel-plugin.ts +55 -0
  277. package/src/host/cli.ts +11 -0
  278. package/src/host/command-name.ts +15 -0
  279. package/src/host/data-error.ts +21 -0
  280. package/src/host/data-root.ts +2 -0
  281. package/src/host/diy-debug.ts +2 -1
  282. package/src/host/diy-record.ts +2 -1
  283. package/src/host/facts.ts +4 -3
  284. package/src/host/git.ts +2 -2
  285. package/src/host/http.ts +1 -1
  286. package/src/host/lib-capabilities.ts +52 -0
  287. package/src/host/lib-install.ts +18 -0
  288. package/src/host/long-task.ts +4 -3
  289. package/src/host/market-index.ts +413 -0
  290. package/src/host/needs.ts +6 -0
  291. package/src/host/patch.ts +93 -0
  292. package/src/host/paths.ts +37 -0
  293. package/src/host/platform.ts +48 -0
  294. package/src/host/plugin-source.ts +48 -56
  295. package/src/host/plugin.ts +39 -0
  296. package/src/host/port-types.ts +222 -0
  297. package/src/host/preflight.ts +31 -0
  298. package/src/host/profile-port.ts +9 -0
  299. package/src/host/provision.ts +7 -4
  300. package/src/host/recipe-rules.ts +330 -0
  301. package/src/host/recipe.test.ts +334 -0
  302. package/src/host/recipe.ts +323 -0
  303. package/src/host/shell-text.ts +15 -3
  304. package/src/host/shell.ts +9 -0
  305. package/src/host/spec.ts +32 -0
  306. package/src/host/supply-index.ts +256 -0
  307. package/src/host/supply-port.ts +45 -0
  308. package/src/host/time.ts +22 -0
  309. package/src/host/tokens.ts +186 -0
  310. package/src/host/tool-approval.ts +17 -0
  311. package/src/host/tool-kit.ts +1 -1
  312. package/src/host/unit-face.ts +5 -4
  313. package/src/host/version-range.ts +71 -0
  314. package/src/host/version.ts +30 -0
  315. package/src/host.ts +47 -16
  316. package/src/i18n/en.ts +261 -86
  317. package/src/i18n/merge.test.ts +6 -6
  318. package/src/i18n/merge.ts +1 -1
  319. package/src/i18n/need-text.ts +27 -0
  320. package/src/i18n/settings.ts +141 -0
  321. package/src/i18n/zh.ts +263 -87
  322. package/src/index.ts +24 -8
  323. package/src/lib/blocker-action.ts +0 -28
  324. package/src/{api → lib}/dsh-client.ts +16 -2
  325. package/src/lib/market-index.ts +36 -0
  326. package/src/lib/react-types.ts +5 -0
  327. package/src/lib/react.ts +1 -40
  328. package/src/lib/text.test.ts +2 -2
  329. package/src/lib/ui.test.ts +6 -5
  330. package/src/lib/ui.ts +3 -9
  331. package/src/testing/__tests__/declaration.test.ts +1 -1
  332. package/src/testing/data.ts +66 -0
  333. package/src/testing/declaration.ts +2 -2
  334. package/src/testing/host-fakes.ts +0 -38
  335. package/src/testing/needs.ts +80 -0
  336. package/src/testing.ts +2 -0
  337. package/dist/api/unit-board.d.ts +0 -39
  338. package/dist/api/unit-board.js +0 -45
  339. package/dist/api/unit.d.ts +0 -85
  340. package/dist/api/unit.js +0 -8
  341. package/dist/api/workbench-contract.d.ts +0 -44
  342. package/dist/components/MockStrip.css +0 -39
  343. package/dist/components/MockStrip.d.ts +0 -15
  344. package/dist/components/MockStrip.js +0 -8
  345. package/dist/components/SaveBar.css +0 -7
  346. package/dist/host/browser-find.d.ts +0 -38
  347. package/dist/host/browser-find.js +0 -242
  348. package/dist/host/browser-read.d.ts +0 -28
  349. package/dist/host/browser-read.js +0 -243
  350. package/dist/host/opencli-runtime.d.ts +0 -25
  351. package/dist/host/opencli-runtime.js +0 -56
  352. package/dist/host/opencli-window.d.ts +0 -2
  353. package/dist/host/opencli-window.js +0 -8
  354. package/dist/host/opencli.d.ts +0 -37
  355. package/dist/host/opencli.js +0 -155
  356. package/dist/host/unit-declaration.d.ts +0 -65
  357. package/dist/host/unit-declaration.js +0 -213
  358. package/dist/host/unit-libs.d.ts +0 -37
  359. package/dist/lib/diy-debug.d.ts +0 -80
  360. package/dist/lib/diy-debug.js +0 -88
  361. package/dist/lib/diy-record.d.ts +0 -135
  362. package/dist/lib/diy-record.js +0 -162
  363. package/dist/lib/lint-probe.d.ts +0 -1
  364. package/dist/lib/lint-probe.js +0 -6
  365. package/dist/lib/panel-state.d.ts +0 -120
  366. package/dist/lib/panel-state.js +0 -176
  367. package/src/api/__tests__/host-write.test.ts +0 -75
  368. package/src/api/__tests__/unit-board.test.ts +0 -76
  369. package/src/api/__tests__/unit.test.ts +0 -38
  370. package/src/api/unit-board.ts +0 -69
  371. package/src/api/unit.ts +0 -93
  372. package/src/api/workbench-contract.ts +0 -59
  373. package/src/host/__tests__/browser-find.test.ts +0 -330
  374. package/src/host/__tests__/browser-read.test.ts +0 -228
  375. package/src/host/__tests__/opencli-runtime.test.ts +0 -46
  376. package/src/host/browser-find.ts +0 -311
  377. package/src/host/browser-read.ts +0 -311
  378. package/src/host/opencli-runtime.ts +0 -79
  379. package/src/host/opencli-window.ts +0 -11
  380. package/src/host/opencli.ts +0 -213
  381. package/src/host/unit-libs.ts +0 -41
  382. package/src/lib/blocker-action.test.ts +0 -40
  383. /package/dist/{api/blocker.js → contract/adapters.js} +0 -0
  384. /package/dist/{api → contract}/blocker.d.ts +0 -0
  385. /package/dist/{api/dsh-client.js → contract/blocker.js} +0 -0
  386. /package/dist/{api/workbench-contract.js → contract/cli.js} +0 -0
  387. /package/dist/{host/unit-libs.js → contract/data.js} +0 -0
  388. /package/dist/{api → contract}/long-task.d.ts +0 -0
  389. /package/dist/{api → contract}/long-task.js +0 -0
  390. /package/src/{api → contract}/blocker.ts +0 -0
  391. /package/src/{api → contract}/long-task.ts +0 -0
@@ -0,0 +1,55 @@
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
+
6
+ export const CHANNEL_PLUGIN_NAME = 'opencli-plugin-workbench';
7
+ export const CHANNEL_PLUGIN_SITE = 'workbench';
8
+
9
+ export interface ChannelPluginPlan {
10
+ readonly dest: string;
11
+ readonly version: string;
12
+ readonly commands: readonly string[];
13
+ readonly line: string;
14
+ }
15
+
16
+ function textOf(value: unknown): string {
17
+ return typeof value === 'string' ? value.trim() : '';
18
+ }
19
+
20
+ export function channelVersionOf(dir: string): string | undefined {
21
+ try {
22
+ const parsed: unknown = JSON.parse(readFileSync(join(dir, 'opencli-plugin.json'), 'utf8'));
23
+ if (typeof parsed !== 'object' || parsed === null) return undefined;
24
+ const version = textOf((parsed as Record<string, unknown>)['version']);
25
+ return version === '' ? undefined : version;
26
+ } catch {
27
+ return undefined;
28
+ }
29
+ }
30
+
31
+ export function channelPluginPlan(options: {
32
+ readonly channelDir: string;
33
+ readonly command?: string;
34
+ }): ChannelPluginPlan | undefined {
35
+ const version = channelVersionOf(options.channelDir);
36
+ if (version === undefined) return undefined;
37
+ const command = options.command ?? 'opencli';
38
+ const dest = join(vendorPluginsDir(), CHANNEL_PLUGIN_NAME);
39
+ const peer = vendorPeerLink();
40
+ const commands = [
41
+ `rm -rf ${quoteShellArg(dest)} && mkdir -p ${quoteShellArg(dest)} && cp -R ${quoteShellArg(options.channelDir)}/. ${quoteShellArg(dest)}/`,
42
+ `rm -rf ${quoteShellArg(peer.dir)} && mkdir -p ${quoteShellArg(peer.parent)} && ln -s ${quoteShellArg(toolchainOpencliDir())} ${quoteShellArg(peer.dir)}`,
43
+ `(${quoteShellArg(command)} plugin uninstall ${quoteShellArg(CHANNEL_PLUGIN_SITE)} || true)`,
44
+ `${quoteShellArg(command)} plugin install ${quoteShellArg(dest)}`,
45
+ ];
46
+ return { dest, version, commands, line: commands.join(' && ') };
47
+ }
48
+
49
+ export function channelInstalledVersion(): string | undefined {
50
+ return channelVersionOf(join(vendorPluginsDir(), CHANNEL_PLUGIN_NAME));
51
+ }
52
+
53
+ export function channelSiteInstalled(): boolean {
54
+ return existsSync(join(isolatedHome(), '.opencli', 'plugins', CHANNEL_PLUGIN_SITE));
55
+ }
@@ -0,0 +1,11 @@
1
+ import type { DshHostContext } from '../api/dsh.js';
2
+ import type { CliPort } from '../contract/cli.js';
3
+ import { adaptersOf } from './adapters.js';
4
+
5
+ export function cliPortOf(ctx: DshHostContext): CliPort {
6
+ return { command: adaptersOf(ctx).runtime.opencliCommand(ctx).command };
7
+ }
8
+
9
+ export function cliCommandOf(ctx: DshHostContext): string {
10
+ return cliPortOf(ctx).command;
11
+ }
@@ -0,0 +1,15 @@
1
+ function baseName(value: string): string {
2
+ const parts = value.trim().split(/[\\/]/);
3
+ return parts[parts.length - 1] ?? '';
4
+ }
5
+
6
+ function isOpencli(name: string): boolean {
7
+ return name === 'opencli' || name === 'opencli.cmd' || name === 'opencli.exe';
8
+ }
9
+
10
+ export function commandNamesMatch(declared: string, resolved: string): boolean {
11
+ const left = baseName(declared);
12
+ const right = baseName(resolved);
13
+ if (left === '' || right === '') return false;
14
+ return left === right || (isOpencli(left) && isOpencli(right));
15
+ }
@@ -0,0 +1,21 @@
1
+ export 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
+
8
+ constructor(
9
+ code: string,
10
+ message: string,
11
+ extra: { detail?: string; hint?: string; project?: unknown; helpUrl?: string } = {},
12
+ ) {
13
+ super(message);
14
+ this.name = 'WorkbenchDataError';
15
+ this.code = code;
16
+ if (extra.detail !== undefined) this.detail = extra.detail;
17
+ if (extra.hint !== undefined) this.hint = extra.hint;
18
+ if (extra.project !== undefined) this.project = extra.project;
19
+ if (extra.helpUrl !== undefined) this.helpUrl = extra.helpUrl;
20
+ }
21
+ }
@@ -5,6 +5,8 @@ export function dshHome(): string {
5
5
  }
6
6
 
7
7
  export function workbenchRoot(): string {
8
+ const configured = process.env.DSH_WORKBENCH_HOME?.trim();
9
+ if (configured !== undefined && configured !== '') return configured;
8
10
  return `${dshHome()}/workbench`;
9
11
  }
10
12
 
@@ -1,3 +1,4 @@
1
+ import { clockOf } from './time.js';
1
2
  /**
2
3
  * 调试约定的两个相位:`debugging` 正占着用户的屏,`paused` 已暂停但仍持着约定。
3
4
  */
@@ -156,5 +157,5 @@ export function createDebugStore(): DebugStore {
156
157
  * @returns 形如「会话 x(自 HH:mm:ssZ 起在调试 y)」的中文串。
157
158
  */
158
159
  export function debugOwnerText(state: DebugState): string {
159
- return `会话 ${state.sessionId}(自 ${new Date(state.startedAt).toISOString().slice(11, 19)}Z 起在调试 ${state.unit})`;
160
+ return `会话 ${state.sessionId}(自 ${clockOf(state.startedAt)}Z 起在调试 ${state.unit})`;
160
161
  }
@@ -1,3 +1,4 @@
1
+ import { clockOf } from './time.js';
1
2
  /**
2
3
  * 录制交接的三个相位:`armed` 等用户在外站页面上动手,`recording` 正在录,`finished` 录完待取。
3
4
  */
@@ -274,6 +275,6 @@ export function createRecordStore(): RecordStore {
274
275
  * @returns 形如「会话 x(自 HH:mm:ssZ 起在录 y 的「动作」)」的中文串。
275
276
  */
276
277
  export function recordOwnerText(state: RecordState): string {
277
- const at = new Date(state.startedAt).toISOString().slice(11, 19);
278
+ const at = clockOf(state.startedAt);
278
279
  return `会话 ${state.sessionId}(自 ${at}Z 起在录 ${state.unit} 的「${state.action}」)`;
279
280
  }
package/src/host/facts.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { UnitManifest } from '../api/unit.js';
2
- import { FACT_SCOPE_SUFFIX } from '../api/facts.js';
1
+ import { randomUUID } from 'node:crypto';
2
+ import type { UnitManifest } from '../contract/unit.js';
3
+ import { FACT_SCOPE_SUFFIX } from '../contract/facts.js';
3
4
 
4
5
  export interface FactChange {
5
6
  readonly rev: number;
@@ -19,7 +20,7 @@ export interface FactLog {
19
20
  }
20
21
 
21
22
  export function createFactLog(options: { readonly epoch?: string } = {}): FactLog {
22
- const epoch = options.epoch ?? `e${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
23
+ const epoch = options.epoch ?? `e${randomUUID()}`;
23
24
  let rev = 0;
24
25
  const last = new Map<string, number>();
25
26
  const listeners = new Set<(change: FactChange) => void>();
package/src/host/git.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { DshShell } from '../api/dsh.js';
2
- import { quoteShellArg, tailLines } from './shell-text.js';
3
- import { runShell } from './shell.js';
2
+ import { quoteShellArg, tailLines } from '../host/shell-text.js';
3
+ import { runShell } from '../host/shell.js';
4
4
 
5
5
  export type OriginRead =
6
6
  | { readonly kind: 'ok'; readonly remote: string }
package/src/host/http.ts CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  type ProvisionHandler,
8
8
  type ProvisionRequest,
9
9
  } from './provision.js';
10
- import { WorkbenchDataError } from '../host/opencli.js';
10
+ import { WorkbenchDataError } from './data-error.js';
11
11
  import { writeResultForClient } from './write-result.js';
12
12
 
13
13
  export type RouteHandler = (search: URLSearchParams) => Promise<unknown> | unknown;
@@ -0,0 +1,52 @@
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
+ /** 手写轮子的硬指纹;按能力名稳定排序,方便两边报告与测试对照。 */
16
+ export const LIB_CAPABILITIES: readonly LibCapability[] = [
17
+ {
18
+ capability: 'process-spawn',
19
+ preferred: 'execa',
20
+ pattern: /from\s+['"]node:child_process['"]/,
21
+ why: '自己起进程要用 execa;同步/跨平台差异交给它',
22
+ },
23
+ {
24
+ capability: 'cli-locate',
25
+ preferred: 'which',
26
+ pattern: /\bprocess\.env\.(?:PATH|PATHEXT)\b/,
27
+ why: '自己扫 PATH/PATHEXT 要用 which(它处理 PATHEXT 与 Path 大小写)',
28
+ },
29
+ {
30
+ capability: 'file-lock',
31
+ preferred: 'proper-lockfile',
32
+ pattern: /\bprocess\.kill\([^)]*,\s*0\)|flag:\s*['"]wx['"]/,
33
+ why: '自己抢文件锁要用 proper-lockfile(stale / 重试 / 跨平台)',
34
+ },
35
+ {
36
+ capability: 'atomic-state',
37
+ preferred: 'write-file-atomic',
38
+ pattern: /writeFileSync\([^)]*\.(?:sync\.json|self-update\.json)/,
39
+ why: '自己直写状态文件要用 write-file-atomic(防写一半)',
40
+ },
41
+ ];
42
+
43
+ /**
44
+ * 这个文件是否已经 import 了某个首选库(静态或动态 import 都算)。
45
+ * @param source 文件全文。
46
+ * @param preferred 首选库包名。
47
+ * @returns 有 import 就 `true`。
48
+ */
49
+ export function importsPreferred(source: string, preferred: string): boolean {
50
+ const escaped = preferred.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
51
+ return new RegExp(`(?:from\\s*|import\\s*\\(\\s*)['"]${escaped}['"]`).test(source);
52
+ }
@@ -0,0 +1,18 @@
1
+ import type { LibNeed, SupplySource } from '../contract/needs.js';
2
+ import { npmRegistryOf } from './plugin-source.js';
3
+ import { quoteShellArg } from './shell-text.js';
4
+ import { libsPrefix, npmCacheDir } from './paths.js';
5
+
6
+ export type NpmSource = Extract<SupplySource, { kind: 'npm' }>;
7
+
8
+ export function libInstallCommand(options: {
9
+ readonly need: LibNeed;
10
+ readonly source: NpmSource;
11
+ readonly version?: string | undefined;
12
+ }): string {
13
+ const { need, source, version } = options;
14
+ const registry = npmRegistryOf(source, process.env);
15
+ const spec = version ?? need.version ?? 'latest';
16
+ const registryFlag = registry.ok ? ` --registry ${quoteShellArg(registry.value)}` : '';
17
+ return `npm i --prefix ${quoteShellArg(libsPrefix())} ${quoteShellArg(`${need.name}@${spec}`)}${registryFlag} --cache ${quoteShellArg(npmCacheDir())}`;
18
+ }
@@ -1,4 +1,5 @@
1
- import { runsRouteOf, type LongTaskStatus, type LongTaskStep } from '../api/long-task.js';
1
+ import { epochOf } from './time.js';
2
+ import { runsRouteOf, type LongTaskStatus, type LongTaskStep } from '../contract/long-task.js';
2
3
 
3
4
  const LIVE: ReadonlySet<string> = new Set<LongTaskStatus>(['running', 'needs-login']);
4
5
 
@@ -104,7 +105,7 @@ export function createLongTaskRegistry<S extends LongTaskBase>(deps: LongTaskDep
104
105
  },
105
106
 
106
107
  current(workspace) {
107
- const floor = Date.parse(now()) - recentMs;
108
+ const floor = epochOf(now()) - recentMs;
108
109
  const newest = new Map<string, LongTaskBase>();
109
110
  for (const snapshot of runs.values()) {
110
111
  if (snapshot.workspace !== workspace) continue;
@@ -112,7 +113,7 @@ export function createLongTaskRegistry<S extends LongTaskBase>(deps: LongTaskDep
112
113
  }
113
114
  return [...newest.values()]
114
115
  .filter(
115
- (snapshot) => LIVE.has(snapshot.status) || Date.parse(snapshot.at) >= floor,
116
+ (snapshot) => LIVE.has(snapshot.status) || epochOf(snapshot.at) >= floor,
116
117
  )
117
118
  .reverse()
118
119
  .map((snapshot) => ({ ...deps.view(snapshot as S), id: snapshot.id }));