@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
@@ -1,11 +1,9 @@
1
- import type { PluginSource } from '../api/unit.js';
1
+ import type { SupplySource } from '../contract/needs.js';
2
+ import type { ProvisionProblem } from '../contract/plugin-source.js';
2
3
  import { quoteShellArg } from './shell-text.js';
3
- import { npmCacheDir, toolchainOpencliDir, vendorPeerLink, vendorPrefix } from '../host/opencli-runtime.js';
4
+ import { npmCacheDir, toolchainOpencliDir, vendorPeerLink, vendorPrefix } from './paths.js';
4
5
 
5
- export type PluginSourceProblem =
6
- | "not-declared"
7
- | "env-missing"
8
- | "malformed";
6
+ export type { ProvisionProblem } from '../contract/plugin-source.js';
9
7
 
10
8
  export interface PluginSourceCommand {
11
9
  readonly line: string;
@@ -20,7 +18,7 @@ export type ResolvedPluginSource =
20
18
  }
21
19
  | {
22
20
  readonly ok: false;
23
- readonly problem: PluginSourceProblem;
21
+ readonly problem: ProvisionProblem;
24
22
  readonly env?: string;
25
23
  };
26
24
 
@@ -28,15 +26,11 @@ export interface PluginSourceOptions {
28
26
  readonly command?: string;
29
27
  readonly plugin?: string;
30
28
  readonly version?: string;
31
- readonly mode?: "install" | "update";
29
+ readonly mode?: 'install' | 'update';
32
30
  }
33
31
 
34
32
  function mergeLines(commands: readonly PluginSourceCommand[]): string {
35
- return commands
36
- .map((item) =>
37
- item.optional === true ? `(${item.line} || true)` : item.line,
38
- )
39
- .join(" && ");
33
+ return commands.map((item) => (item.optional === true ? `(${item.line} || true)` : item.line)).join(' && ');
40
34
  }
41
35
 
42
36
  function envValue(
@@ -44,21 +38,21 @@ function envValue(
44
38
  name: string,
45
39
  ): { readonly ok: true; readonly value: string } | { readonly ok: false } {
46
40
  const value = env[name]?.trim();
47
- return value === undefined || value === ""
48
- ? { ok: false }
49
- : { ok: true, value };
41
+ return value === undefined || value === '' ? { ok: false } : { ok: true, value };
50
42
  }
51
43
 
52
44
  export function npmRegistryOf(
53
- source: { readonly registryEnv: string; readonly registryDefault?: string },
45
+ source: { readonly registryEnv?: string; readonly registryDefault?: string },
54
46
  env: Readonly<Record<string, string | undefined>>,
55
- ): { readonly ok: true; readonly value: string } | { readonly ok: false } {
56
- const fromEnv = envValue(env, source.registryEnv);
57
- if (fromEnv.ok) return fromEnv;
47
+ ): { readonly ok: true; readonly value: string } | { readonly ok: false; readonly env: string } {
48
+ const name = source.registryEnv ?? '';
49
+ if (name !== '') {
50
+ const fromEnv = envValue(env, name);
51
+ if (fromEnv.ok) return fromEnv;
52
+ }
58
53
  const fallback = source.registryDefault?.trim();
59
- return fallback === undefined || fallback === ""
60
- ? { ok: false }
61
- : { ok: true, value: fallback };
54
+ if (fallback === undefined || fallback === '') return { ok: false, env: name };
55
+ return { ok: true, value: fallback };
62
56
  }
63
57
 
64
58
  function installOne(command: string, spec: string): ResolvedPluginSource {
@@ -66,28 +60,28 @@ function installOne(command: string, spec: string): ResolvedPluginSource {
66
60
  return { ok: true, commands: [{ line }], line };
67
61
  }
68
62
 
63
+ function pluginPackageOf(source: SupplySource, plugin: string): string {
64
+ if (source.kind === 'npm') {
65
+ const pkg = source.package?.trim() ?? '';
66
+ if (pkg !== '') return pkg;
67
+ return plugin.trim() === '' ? '' : `opencli-plugin-${plugin.trim()}`;
68
+ }
69
+ if (source.kind === 'git') return source.url.trim();
70
+ return '';
71
+ }
72
+
69
73
  function npmSource(
70
- source: {
71
- readonly package: string;
72
- readonly registryEnv: string;
73
- readonly registryDefault?: string;
74
- },
74
+ source: SupplySource & { kind: 'npm' },
75
75
  env: Readonly<Record<string, string | undefined>>,
76
76
  options: PluginSourceOptions,
77
77
  ): ResolvedPluginSource {
78
78
  const registry = npmRegistryOf(source, env);
79
- if (!registry.ok)
80
- return { ok: false, problem: "env-missing", env: source.registryEnv };
81
-
82
- const name = source.package.trim();
83
- if (name === "") return { ok: false, problem: "malformed" };
84
-
85
- const {
86
- command = "opencli",
87
- plugin = "",
88
- version = "latest",
89
- mode = "install",
90
- } = options;
79
+ if (!registry.ok) return { ok: false, problem: 'env-missing', env: registry.env };
80
+
81
+ const { command = 'opencli', plugin = '', version = 'latest', mode = 'install' } = options;
82
+ const name = pluginPackageOf(source, plugin);
83
+ if (name === '') return { ok: false, problem: 'malformed' };
84
+
91
85
  const prefix = vendorPrefix();
92
86
  const dirInPrefix = `${prefix}/node_modules/${name}`;
93
87
  const peer = vendorPeerLink();
@@ -95,20 +89,20 @@ function npmSource(
95
89
  const commands: PluginSourceCommand[] = [
96
90
  {
97
91
  line: [
98
- "npm i",
92
+ 'npm i',
99
93
  `--prefix ${quoteShellArg(prefix)}`,
100
94
  quoteShellArg(`${name}@${version}`),
101
95
  `--registry ${quoteShellArg(registry.value)}`,
102
96
  `--cache ${quoteShellArg(npmCacheDir())}`,
103
- ].join(" "),
97
+ ].join(' '),
104
98
  },
105
99
  {
106
100
  line: `rm -rf ${quoteShellArg(peer.dir)} && mkdir -p ${quoteShellArg(peer.parent)} && ln -s ${quoteShellArg(toolchainOpencliDir())} ${quoteShellArg(peer.dir)}`,
107
101
  },
108
102
  ];
109
103
 
110
- if (mode === "install") {
111
- if (plugin !== "") {
104
+ if (mode === 'install') {
105
+ if (plugin !== '') {
112
106
  commands.push({
113
107
  line: `${quoteShellArg(command)} plugin uninstall ${quoteShellArg(plugin)}`,
114
108
  optional: true,
@@ -123,23 +117,21 @@ function npmSource(
123
117
  }
124
118
 
125
119
  export function resolvePluginSource(
126
- source: PluginSource | undefined,
120
+ source: SupplySource | undefined,
127
121
  env: Readonly<Record<string, string | undefined>>,
128
122
  options: PluginSourceOptions = {},
129
123
  ): ResolvedPluginSource {
130
- if (source === undefined) return { ok: false, problem: "not-declared" };
124
+ if (source === undefined) return { ok: false, problem: 'not-declared' };
131
125
 
132
- const command = options.command ?? "opencli";
133
- if (source.kind === "git") {
126
+ const command = options.command ?? 'opencli';
127
+ if (source.kind === 'git') {
134
128
  const url = source.url.trim();
135
- return url === ""
136
- ? { ok: false, problem: "malformed" }
137
- : installOne(command, url);
129
+ return url === '' ? { ok: false, problem: 'malformed' } : installOne(command, url);
138
130
  }
139
- if (source.kind === "npm") return npmSource(source, env, options);
131
+ if (source.kind === 'npm') return npmSource(source, env, options);
140
132
 
141
- const value = envValue(env, source.env);
142
- return value.ok
143
- ? installOne(command, value.value)
144
- : { ok: false, problem: "env-missing", env: source.env };
133
+ const value = source.env === undefined ? { ok: false as const } : envValue(env, source.env);
134
+ if (value.ok) return installOne(command, value.value);
135
+ if (source.path !== undefined && source.path.trim() !== '') return installOne(command, source.path.trim());
136
+ return { ok: false, problem: 'env-missing', env: source.env ?? '' };
145
137
  }
@@ -0,0 +1,39 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ export const OPENCLI_MANIFEST_FILE = 'opencli-plugin.json';
5
+
6
+ function asRecord(value: unknown): Readonly<Record<string, unknown>> | undefined {
7
+ return typeof value === 'object' && value !== null ? (value as Readonly<Record<string, unknown>>) : undefined;
8
+ }
9
+
10
+ function isCommandFile(name: string): boolean {
11
+ if (name.endsWith('.d.ts') || name.endsWith('.test.ts')) return false;
12
+ if (name.endsWith('.d.js')) return false;
13
+ return name.endsWith('.ts') || name.endsWith('.js');
14
+ }
15
+
16
+ function pluginManifestOf(dir: string): Readonly<Record<string, unknown>> | undefined {
17
+ try {
18
+ const parsed: unknown = JSON.parse(readFileSync(join(dir, OPENCLI_MANIFEST_FILE), 'utf8'));
19
+ if (Array.isArray(parsed)) return undefined;
20
+ return asRecord(parsed);
21
+ } catch {
22
+ return undefined;
23
+ }
24
+ }
25
+
26
+ function hasCommandFile(dir: string): boolean {
27
+ try {
28
+ return readdirSync(dir).some(isCommandFile);
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ export function pluginAt(dir: string): { readonly name?: string } | undefined {
35
+ const manifest = pluginManifestOf(dir);
36
+ if (manifest === undefined || !hasCommandFile(dir)) return undefined;
37
+ const name = manifest.name;
38
+ return typeof name === 'string' && name.trim() !== '' ? { name: name.trim() } : {};
39
+ }
@@ -0,0 +1,222 @@
1
+ import type { DshHostContext, DshShell } from '../api/dsh.js';
2
+ import type { LibNeed, SupplySource } from '../contract/needs.js';
3
+ import type { NeedProbeInput, UnitCapability } from '../contract/unit-capability.js';
4
+ import type { WorkbenchSelfUpdate } from '../contract/protocol/bundle-install.js';
5
+ import type {
6
+ BundleManager,
7
+ InstalledModule,
8
+ OpencliResolution,
9
+ ProfileModule,
10
+ ProfilePackage,
11
+ RegistryNotebook,
12
+ SelfUpdateRequest,
13
+ SelfUpdateStart,
14
+ } from './adapter-types.js';
15
+ import type { PostResource, RouteHandler, RouteTable } from './http.js';
16
+ import type { PluginSourceOptions, ResolvedPluginSource } from './plugin-source.js';
17
+
18
+ export interface LoggerLike {
19
+ info?(message: string): void;
20
+ warn?(message: string): void;
21
+ }
22
+
23
+ export interface ProfilePort {
24
+ dirOf(ctx: DshHostContext): string | null;
25
+ dshPlugins(ctx: DshHostContext): RouteHandler;
26
+ selfUpdateView(root: string, profile: string): WorkbenchSelfUpdate | undefined;
27
+ }
28
+
29
+ export type SupplyPluginSource = ResolvedPluginSource;
30
+
31
+ export interface SupplyPackageRoute {
32
+ readonly kind: 'opencli-plugin' | 'dsh-bundle' | 'neither';
33
+ readonly pkg?: string;
34
+ readonly pluginName?: string;
35
+ }
36
+
37
+ export interface SupplyRelease {
38
+ readonly installed?: string;
39
+ readonly latest?: string;
40
+ readonly missing?: readonly string[];
41
+ }
42
+
43
+ export interface SupplyNpmRef {
44
+ readonly name: string;
45
+ readonly version?: string;
46
+ }
47
+
48
+ export interface SupplyPluginInstallOptions {
49
+ readonly spec: string;
50
+ readonly command: string;
51
+ readonly registry?: string | undefined;
52
+ readonly pluginName?: string | undefined;
53
+ }
54
+
55
+ export interface SupplyLatestOptions {
56
+ readonly shell: DshShell;
57
+ readonly name: string;
58
+ readonly registry: string;
59
+ readonly force?: boolean;
60
+ }
61
+
62
+ export interface SupplyMissingPartsOptions {
63
+ readonly shell: DshShell;
64
+ readonly registry: string;
65
+ readonly version: string;
66
+ readonly force?: boolean;
67
+ }
68
+
69
+ export interface SupplyProbeReleaseOptions {
70
+ readonly shell: DshShell;
71
+ readonly package: string;
72
+ readonly registry?: string | undefined;
73
+ readonly force?: boolean;
74
+ }
75
+
76
+ export interface EnvSupplyPort {
77
+ resolvePluginSource(
78
+ source: SupplySource | undefined,
79
+ env: Readonly<Record<string, string | undefined>>,
80
+ options?: PluginSourceOptions,
81
+ ): ResolvedPluginSource;
82
+ libInstallCommand(options: {
83
+ readonly need: LibNeed;
84
+ readonly source: Extract<SupplySource, { kind: 'npm' }>;
85
+ readonly version?: string | undefined;
86
+ }): string;
87
+ pluginInstallPlan(options: SupplyPluginInstallOptions): ResolvedPluginSource;
88
+ latestVersion(options: SupplyLatestOptions): Promise<string | undefined>;
89
+ missingReleaseParts(options: SupplyMissingPartsOptions): Promise<readonly string[]>;
90
+ probeRelease(options: SupplyProbeReleaseOptions): Promise<SupplyRelease | undefined>;
91
+ splitNpmSpec(spec: string): SupplyNpmRef | undefined;
92
+ }
93
+
94
+ export interface ModulePort {
95
+ isolatedHome(): string;
96
+ cliCatalogPath(): string;
97
+ vendorPluginsDir(): string;
98
+ opencliInstallCommand(): string;
99
+ profileDirOf(ctx: DshHostContext): string | null;
100
+ profileModules(dir: string | null): readonly ProfileModule[];
101
+ readInstalledModule(dir: string | null, pkg: string): InstalledModule;
102
+ readProfilePackage(dir: string | null, pkg: string): ProfilePackage | undefined;
103
+ readBundleManager(ctx: DshHostContext): BundleManager | undefined;
104
+ createRegistryNotebook(dir: string | null): RegistryNotebook;
105
+ declarationGaps(dir: string | null): readonly { readonly pkg: string }[] | undefined;
106
+ moduleDeclarationOf(dir: string | null, pkg: string): unknown;
107
+ registryDeclarationOf(options: {
108
+ readonly shell: DshShell;
109
+ readonly name: string;
110
+ readonly registry: string;
111
+ readonly force?: boolean;
112
+ }): Promise<unknown>;
113
+ pathDeclarationOf(spec: string): unknown;
114
+ declarationRefusalOf(name: string, raw: unknown): readonly string[];
115
+ refusalReason(): string;
116
+ packageRouteOf(options: {
117
+ readonly spec: string;
118
+ readonly shell?: DshShell | undefined;
119
+ readonly registry?: string | undefined;
120
+ readonly force?: boolean;
121
+ }): Promise<SupplyPackageRoute | undefined>;
122
+ isNewerVersion(left: string, right: string): boolean;
123
+ startSelfUpdate(request: SelfUpdateRequest, onError: (message: string) => void): SelfUpdateStart;
124
+ }
125
+
126
+ export interface SupplyPort extends EnvSupplyPort, ModulePort {
127
+ readonly env: EnvSupplyPort;
128
+ readonly modules: ModulePort;
129
+ }
130
+
131
+ export interface ProbeUnitsOptions {
132
+ readonly shell: DshShell;
133
+ readonly runtimeCommands: Readonly<Record<string, string>>;
134
+ readonly units: readonly NeedProbeInput[];
135
+ readonly force?: boolean;
136
+ }
137
+
138
+ export interface ProbePreflightInput {
139
+ readonly routes: RouteTable;
140
+ readonly ctx: DshHostContext;
141
+ readonly shell: DshShell;
142
+ readonly opencliCommand: string;
143
+ readonly installCommand?: string | undefined;
144
+ readonly warmReads: () => readonly (readonly string[])[];
145
+ }
146
+
147
+ export interface ProbePort {
148
+ probeUnits(options: ProbeUnitsOptions): Promise<UnitCapability[]>;
149
+ registerPreflight(input: ProbePreflightInput): void;
150
+ declaredPluginCommands(profileDir: string | null): ReadonlyMap<string, ReadonlySet<string>>;
151
+ }
152
+
153
+ export interface RuntimeSeedOptions {
154
+ readonly corePackageUrl: string;
155
+ readonly log: (message: string) => void;
156
+ }
157
+
158
+ export interface RuntimePort {
159
+ packageRoot(moduleUrl: string): string;
160
+ opencliCommand(ctx: DshHostContext): OpencliResolution;
161
+ seed(ctx: DshHostContext, options: RuntimeSeedOptions): void;
162
+ warnUnwritableRoot(ctx: DshHostContext): void;
163
+ }
164
+
165
+ export interface PluginDeclarationSource {
166
+ readonly pkg: string;
167
+ readonly declaration: unknown;
168
+ }
169
+
170
+ export interface PluginRowRef {
171
+ readonly id: string;
172
+ readonly pkg: string;
173
+ readonly name?: string | undefined;
174
+ }
175
+
176
+ export interface PluginRowsSource {
177
+ listPlugins(workspace: string | null): readonly PluginRowRef[];
178
+ subscribe?(listener: () => void): () => void;
179
+ }
180
+
181
+ export interface PluginUnitsPort {
182
+ refresh(options?: { readonly force?: boolean }): Promise<unknown>;
183
+ touch(): void;
184
+ report(): unknown;
185
+ dispose(): void;
186
+ }
187
+
188
+ export interface PluginUnitsInput {
189
+ readonly registry: { registerPlugin(face: unknown): () => void };
190
+ readonly rows: () => readonly PluginRowRef[];
191
+ readonly declared: (plugin: string) => ReadonlySet<string>;
192
+ readonly toolNames?: () => ReadonlySet<string>;
193
+ readonly logger?: LoggerLike | undefined;
194
+ }
195
+
196
+ export interface PluginSurface {
197
+ declarationLookup(profileDir: string | null): (unit: string) => PluginDeclarationSource | undefined;
198
+ createUnits(input: PluginUnitsInput): PluginUnitsPort;
199
+ }
200
+
201
+ export interface ConfigSyncInput {
202
+ readonly home: string;
203
+ readonly self: string;
204
+ readonly profileDir: string | null;
205
+ readonly reconcile?: (() => Promise<boolean | void>) | undefined;
206
+ }
207
+
208
+ export interface ProfileCreateInput {
209
+ readonly home: string;
210
+ readonly self: string;
211
+ readonly packageRoot: string;
212
+ readonly runSetup?:
213
+ | ((env: Readonly<Record<string, string>>) => Promise<{ ok: boolean; log: string }>)
214
+ | undefined;
215
+ }
216
+
217
+ export interface HostActions {
218
+ configSyncHandler(input: ConfigSyncInput): RouteHandler;
219
+ profileCreateHandler(input: ProfileCreateInput): RouteHandler;
220
+ configSyncAction(input: ConfigSyncInput): PostResource;
221
+ profileCreateAction(input: ProfileCreateInput): PostResource;
222
+ }
@@ -0,0 +1,31 @@
1
+ export type PreflightStepId = 'toolchain' | 'opencli' | 'bridge' | 'diy' | 'warm';
2
+ export type PreflightStepStatus = 'pending' | 'running' | 'ok' | 'warn' | 'failed';
3
+ export type PreflightFailure = 'permission' | 'network' | 'missing' | 'unknown';
4
+ export type PreflightGuidance = 'install' | 'path' | 'shell';
5
+ export type PreflightBridgeIssue = 'daemon' | 'extension' | 'profile' | 'stale' | 'unknown';
6
+
7
+ export interface PreflightStep {
8
+ readonly id: PreflightStepId;
9
+ readonly status: PreflightStepStatus;
10
+ readonly detail?: string;
11
+ readonly action?: string;
12
+ readonly command?: string;
13
+ }
14
+
15
+ export interface PreflightDiyGap {
16
+ readonly rows: readonly string[];
17
+ readonly detail: string;
18
+ readonly command: string;
19
+ }
20
+
21
+ export interface PreflightSnapshot {
22
+ readonly phase: 'idle' | 'checking' | 'installing' | 'ready' | 'failed';
23
+ readonly steps: readonly PreflightStep[];
24
+ readonly at: number;
25
+ readonly error?: string;
26
+ readonly failure?: PreflightFailure;
27
+ readonly guidance?: PreflightGuidance;
28
+ readonly bridgeIssues?: readonly PreflightBridgeIssue[];
29
+ readonly diyGap?: PreflightDiyGap;
30
+ readonly canWakeBrowser?: boolean;
31
+ }
@@ -0,0 +1,9 @@
1
+ import type { DshHostContext } from '../api/dsh.js';
2
+ import { adaptersOf } from './adapters.js';
3
+ import type { ProfilePort } from './port-types.js';
4
+ export type { ProfilePort } from './port-types.js';
5
+
6
+
7
+ export function profilePortOf(ctx: DshHostContext): ProfilePort {
8
+ return adaptersOf(ctx).profile;
9
+ }
@@ -1,4 +1,4 @@
1
- import type { ProvisionAction } from '../api/workbench-contract.js';
1
+ import type { ProvisionAction } from '../contract/workbench-contract.js';
2
2
 
3
3
  export type { ProvisionAction };
4
4
 
@@ -7,6 +7,7 @@ export const PROVISION_ACTIONS = [
7
7
  'update',
8
8
  'uninstall',
9
9
  'install-bundle',
10
+ 'install-version',
10
11
  'update-bundle',
11
12
  'remove-bundle',
12
13
  'cancel-install',
@@ -33,7 +34,7 @@ export type ProvisionTarget = 'unit' | 'id' | 'spec' | 'name' | 'requestId';
33
34
 
34
35
  export function provisionTargetOf(action: ProvisionAction): ProvisionTarget {
35
36
  if (action === 'update-dependency') return 'id';
36
- if (action === 'install-bundle') return 'spec';
37
+ if (action === 'install-bundle' || action === 'install-version') return 'spec';
37
38
  if (action === 'remove-bundle') return 'name';
38
39
  if (action === 'update-plugin' || action === 'uninstall-plugin') return 'name';
39
40
  if (action === 'update-workbench') return 'name';
@@ -77,7 +78,7 @@ function stringsOf(value: unknown): string[] | undefined {
77
78
 
78
79
  function requestOf(action: ProvisionAction, value: string): ProvisionRequest {
79
80
  if (action === 'update-dependency') return { action, id: value };
80
- if (action === 'install-bundle') return { action, spec: value };
81
+ if (action === 'install-bundle' || action === 'install-version') return { action, spec: value };
81
82
  if (action === 'remove-bundle') return { action, name: value };
82
83
  if (action === 'update-plugin' || action === 'uninstall-plugin') return { action, name: value };
83
84
  if (action === 'update-workbench') return { action, name: value };
@@ -111,7 +112,9 @@ export function parseProvisionBody(body: unknown): ProvisionParsed {
111
112
  if (typeof value !== 'string' || value.trim() === '') {
112
113
  return { ok: false, code: TARGET_CODE[target], message: `缺少 ${target}` };
113
114
  }
114
- if (wanted !== 'install-bundle') return { ok: true, request: requestOf(wanted, value.trim()) };
115
+ if (wanted !== 'install-bundle' && wanted !== 'install-version') {
116
+ return { ok: true, request: requestOf(wanted, value.trim()) };
117
+ }
115
118
 
116
119
  const registry = typeof raw.registry === 'string' && raw.registry.trim() !== '' ? raw.registry.trim() : undefined;
117
120
  const approvedBuilds = stringsOf(raw.approvedBuilds);