@dsh-workbench/shared 1.1.8 → 1.1.10

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 (226) hide show
  1. package/dist/api/blocker-table.d.ts +1 -0
  2. package/dist/api/blocker-table.js +1 -1
  3. package/dist/components/SelectField.css +0 -6
  4. package/dist/components/SelectField.d.ts +2 -3
  5. package/dist/components/SelectField.js +9 -30
  6. package/dist/components/SelectFieldNodes.d.ts +3 -1
  7. package/dist/components/SelectFieldNodes.js +2 -1
  8. package/dist/components/SelectFieldWheel.d.ts +9 -0
  9. package/dist/components/SelectFieldWheel.js +35 -0
  10. package/dist/config/constants.d.ts +4 -4
  11. package/dist/config/constants.js +4 -4
  12. package/dist/contract/capabilities.d.ts +29 -0
  13. package/dist/contract/capabilities.js +1 -0
  14. package/dist/contract/needs.d.ts +3 -3
  15. package/dist/contract/needs.js +1 -1
  16. package/dist/contract/plugin-source.d.ts +19 -0
  17. package/dist/contract/protocol/bundle-install.d.ts +3 -1
  18. package/dist/contract/protocol/bundle-install.js +3 -0
  19. package/dist/contract/protocol/market-index.d.ts +1 -1
  20. package/dist/contract/protocol/platform.d.ts +1 -1
  21. package/dist/contract/runner.d.ts +6 -0
  22. package/dist/contract/runner.js +1 -0
  23. package/dist/contract/unit.d.ts +4 -4
  24. package/dist/host/adapter-contract.d.ts +3 -0
  25. package/dist/host/adapter-contract.js +93 -0
  26. package/dist/host/adapter-set.js +6 -4
  27. package/dist/host/adapter-types.d.ts +1 -1
  28. package/dist/host/bundle-manager.d.ts +3 -0
  29. package/dist/host/bundle-manager.js +181 -0
  30. package/dist/host/cli.js +3 -1
  31. package/dist/host/config-sync.d.ts +48 -0
  32. package/dist/host/config-sync.js +342 -0
  33. package/dist/host/dsh-plugins.d.ts +5 -0
  34. package/dist/host/dsh-plugins.js +51 -0
  35. package/dist/host/extension.js +1 -1
  36. package/dist/host/flow/check.d.ts +9 -0
  37. package/dist/host/flow/check.js +179 -0
  38. package/dist/host/flow/expr.d.ts +30 -0
  39. package/dist/host/flow/expr.js +99 -0
  40. package/dist/host/flow/kit.d.ts +14 -0
  41. package/dist/host/flow/kit.js +13 -0
  42. package/dist/host/flow/run.d.ts +13 -0
  43. package/dist/host/flow/run.js +287 -0
  44. package/dist/host/flow/types.d.ts +188 -0
  45. package/dist/host/flow/types.js +1 -0
  46. package/dist/host/host-actions.d.ts +2 -0
  47. package/dist/host/host-actions.js +5 -0
  48. package/dist/host/host-kit.d.ts +19 -0
  49. package/dist/host/host-kit.js +14 -0
  50. package/dist/host/http.d.ts +2 -6
  51. package/dist/host/http.js +2 -2
  52. package/dist/host/installed-module.d.ts +23 -0
  53. package/dist/host/installed-module.js +264 -0
  54. package/dist/host/lib-install.d.ts +7 -9
  55. package/dist/host/lib-install.js +9 -12
  56. package/dist/host/lib-runners.d.ts +3 -5
  57. package/dist/host/lib-runners.js +2 -2
  58. package/dist/host/local-declaration.d.ts +7 -0
  59. package/dist/host/local-declaration.js +33 -0
  60. package/dist/host/module-root.d.ts +1 -0
  61. package/dist/host/module-root.js +5 -0
  62. package/dist/host/npm-registry.d.ts +10 -0
  63. package/dist/host/npm-registry.js +16 -0
  64. package/dist/host/opencli-runner.d.ts +2 -1
  65. package/dist/host/package-content.d.ts +7 -0
  66. package/dist/host/package-content.js +69 -0
  67. package/dist/host/package-kind.d.ts +13 -0
  68. package/dist/host/package-kind.js +51 -0
  69. package/dist/host/package-route.d.ts +31 -0
  70. package/dist/host/package-route.js +57 -0
  71. package/dist/host/paths.d.ts +11 -19
  72. package/dist/host/paths.js +16 -43
  73. package/dist/host/platform.js +1 -1
  74. package/dist/host/plugin-ledger.d.ts +8 -8
  75. package/dist/host/plugin-ledger.js +23 -16
  76. package/dist/host/plugin.d.ts +1 -2
  77. package/dist/host/plugin.js +4 -5
  78. package/dist/host/port-types.d.ts +42 -9
  79. package/dist/host/preflight.d.ts +3 -2
  80. package/dist/host/profile-create.d.ts +18 -0
  81. package/dist/host/profile-create.js +118 -0
  82. package/dist/host/profile-registries.d.ts +10 -0
  83. package/dist/host/profile-registries.js +150 -0
  84. package/dist/host/registry-declaration.d.ts +21 -0
  85. package/dist/host/registry-declaration.js +33 -0
  86. package/dist/host/release-probe.d.ts +34 -0
  87. package/dist/host/release-probe.js +88 -0
  88. package/dist/host/runner.d.ts +26 -0
  89. package/dist/host/runner.js +50 -0
  90. package/dist/host/shell.d.ts +0 -2
  91. package/dist/host/shell.js +0 -7
  92. package/dist/host/spec.js +1 -1
  93. package/dist/host/supply-index.d.ts +1 -0
  94. package/dist/host/supply-index.js +8 -7
  95. package/dist/host/supply-port.js +13 -3
  96. package/dist/host/unit-face.d.ts +2 -1
  97. package/dist/host/version.js +11 -6
  98. package/dist/host.d.ts +24 -6
  99. package/dist/host.js +23 -6
  100. package/dist/i18n/en.js +23 -24
  101. package/dist/i18n/index.d.ts +23 -24
  102. package/dist/i18n/runtime-terms.d.ts +15 -0
  103. package/dist/i18n/runtime-terms.js +22 -0
  104. package/dist/i18n/zh.d.ts +22 -23
  105. package/dist/i18n/zh.js +22 -23
  106. package/dist/index.d.ts +4 -0
  107. package/dist/index.js +4 -0
  108. package/dist/testing/fake-adapter-set.d.ts +5 -0
  109. package/dist/testing/fake-adapter-set.js +150 -0
  110. package/dist/testing/needs.js +1 -1
  111. package/dist/testing.d.ts +1 -0
  112. package/dist/testing.js +1 -0
  113. package/package.json +1 -1
  114. package/src/api/__tests__/blocker-table.test.ts +25 -0
  115. package/src/api/{workbench-client.test.ts → __tests__/workbench-client.test.ts} +2 -2
  116. package/src/api/blocker-table.ts +6 -2
  117. package/src/components/SelectField.css +0 -6
  118. package/src/components/SelectField.tsx +7 -36
  119. package/src/components/SelectFieldNodes.tsx +4 -1
  120. package/src/components/{Card.test.tsx → __tests__/Card.test.tsx} +2 -2
  121. package/src/components/{CardAnchor.test.tsx → __tests__/CardAnchor.test.tsx} +3 -3
  122. package/src/components/{CardHead.test.tsx → __tests__/CardHead.test.tsx} +1 -1
  123. package/src/components/{ChoiceGroup.test.tsx → __tests__/ChoiceGroup.test.tsx} +2 -2
  124. package/src/components/{ConfirmBar.test.tsx → __tests__/ConfirmBar.test.tsx} +5 -5
  125. package/src/components/{Field.test.tsx → __tests__/Field.test.tsx} +1 -1
  126. package/src/components/{Form.test.tsx → __tests__/Form.test.tsx} +5 -5
  127. package/src/components/{FormActions.test.tsx → __tests__/FormActions.test.tsx} +3 -3
  128. package/src/components/{FormRows.test.tsx → __tests__/FormRows.test.tsx} +2 -2
  129. package/src/components/{FormTypes.test.ts → __tests__/FormTypes.test.ts} +1 -1
  130. package/src/components/{FormWiring.test.tsx → __tests__/FormWiring.test.tsx} +4 -4
  131. package/src/components/{Link.test.tsx → __tests__/Link.test.tsx} +1 -1
  132. package/src/components/{Rows.test.tsx → __tests__/Rows.test.tsx} +2 -2
  133. package/src/components/{SelectField.test.tsx → __tests__/SelectField.test.tsx} +7 -37
  134. package/src/components/{Spinner.test.tsx → __tests__/Spinner.test.tsx} +4 -4
  135. package/src/config/{constants.test.ts → __tests__/constants.test.ts} +1 -1
  136. package/src/config/{storage.test.ts → __tests__/storage.test.ts} +1 -1
  137. package/src/config/constants.ts +4 -4
  138. package/src/contract/capabilities.ts +30 -0
  139. package/src/contract/needs.ts +4 -4
  140. package/src/contract/plugin-source.ts +24 -0
  141. package/src/contract/protocol/bundle-install.ts +7 -1
  142. package/src/contract/protocol/market-index.ts +1 -0
  143. package/src/contract/protocol/platform.ts +1 -1
  144. package/src/contract/runner.ts +6 -0
  145. package/src/contract/unit.ts +4 -4
  146. package/src/host/{extension.test.ts → __tests__/extension.test.ts} +4 -4
  147. package/src/host/{install-failure.test.ts → __tests__/install-failure.test.ts} +1 -1
  148. package/src/host/{installed-sources.test.ts → __tests__/installed-sources.test.ts} +1 -1
  149. package/src/host/__tests__/lib-runners.test.ts +11 -2
  150. package/src/host/__tests__/plugin-ledger.test.ts +19 -6
  151. package/src/host/{recipe.test.ts → __tests__/recipe.test.ts} +3 -3
  152. package/src/host/__tests__/runtime-layout.test.ts +14 -0
  153. package/src/host/__tests__/supply-index.test.ts +2 -2
  154. package/src/host/__tests__/supply-port.test.ts +32 -0
  155. package/src/host/adapter-contract.ts +93 -0
  156. package/src/host/adapter-set.ts +6 -4
  157. package/src/host/adapter-types.ts +1 -1
  158. package/src/host/bundle-manager.ts +195 -0
  159. package/src/host/cli.ts +3 -1
  160. package/src/host/config-sync.ts +386 -0
  161. package/src/host/dsh-plugins.ts +60 -0
  162. package/src/host/extension.ts +1 -1
  163. package/src/host/flow/__tests__/advanced.test.ts +302 -0
  164. package/src/host/flow/__tests__/check.test.ts +169 -0
  165. package/src/host/flow/__tests__/run.test.ts +301 -0
  166. package/src/host/flow/check.ts +216 -0
  167. package/src/host/flow/expr.ts +94 -0
  168. package/src/host/flow/kit.ts +30 -0
  169. package/src/host/flow/run.ts +325 -0
  170. package/src/host/flow/types.ts +199 -0
  171. package/src/host/host-actions.ts +7 -0
  172. package/src/host/host-kit.ts +26 -0
  173. package/src/host/http.ts +6 -8
  174. package/src/host/installed-module.ts +272 -0
  175. package/src/host/lib-install.ts +14 -12
  176. package/src/host/lib-runners.ts +6 -8
  177. package/src/host/local-declaration.ts +37 -0
  178. package/src/host/module-root.ts +6 -0
  179. package/src/host/npm-registry.ts +21 -0
  180. package/src/host/package-content.ts +76 -0
  181. package/src/host/package-kind.ts +63 -0
  182. package/src/host/package-route.ts +93 -0
  183. package/src/host/paths.ts +27 -52
  184. package/src/host/platform.ts +1 -1
  185. package/src/host/plugin-ledger.ts +25 -18
  186. package/src/host/plugin.ts +4 -5
  187. package/src/host/port-types.ts +43 -9
  188. package/src/host/preflight.ts +3 -2
  189. package/src/host/profile-create.ts +133 -0
  190. package/src/host/profile-registries.ts +145 -0
  191. package/src/host/registry-declaration.ts +70 -0
  192. package/src/host/release-probe.ts +202 -0
  193. package/src/host/shell.ts +0 -9
  194. package/src/host/spec.ts +1 -1
  195. package/src/host/supply-index.ts +9 -7
  196. package/src/host/supply-port.ts +13 -3
  197. package/src/host/unit-face.ts +2 -1
  198. package/src/host/version.ts +12 -7
  199. package/src/host.ts +34 -6
  200. package/src/i18n/{index.test.ts → __tests__/index.test.ts} +3 -3
  201. package/src/i18n/{merge.test.ts → __tests__/merge.test.ts} +1 -1
  202. package/src/i18n/{zh.test.ts → __tests__/zh.test.ts} +2 -2
  203. package/src/i18n/en.ts +23 -25
  204. package/src/i18n/runtime-terms.ts +26 -0
  205. package/src/i18n/zh.ts +22 -24
  206. package/src/index.ts +4 -0
  207. package/src/lib/{board-fact.test.ts → __tests__/board-fact.test.ts} +1 -1
  208. package/src/lib/{busy.test.ts → __tests__/busy.test.ts} +1 -1
  209. package/src/lib/{form-problem.test.ts → __tests__/form-problem.test.ts} +1 -1
  210. package/src/lib/{git-address.test.ts → __tests__/git-address.test.ts} +1 -1
  211. package/src/lib/{react.test.ts → __tests__/react.test.ts} +1 -1
  212. package/src/lib/{text.test.ts → __tests__/text.test.ts} +1 -1
  213. package/src/lib/{ui.test.ts → __tests__/ui.test.ts} +1 -1
  214. package/src/testing/__tests__/fake-adapter-set.test.ts +28 -0
  215. package/src/testing/fake-adapter-set.ts +173 -0
  216. package/src/testing/needs.ts +1 -1
  217. package/src/testing.ts +1 -0
  218. package/src/host/__tests__/command-name.test.ts +0 -16
  219. package/src/host/__tests__/opencli-runner.test.ts +0 -120
  220. package/src/host/channel-plugin.ts +0 -55
  221. package/src/host/command-name.ts +0 -15
  222. package/src/host/opencli-runner.ts +0 -76
  223. package/src/host/paths.test.ts +0 -26
  224. package/src/host/plugin-source.ts +0 -137
  225. package/src/host/runtime-links.test.ts +0 -31
  226. package/src/host/runtime-links.ts +0 -23
@@ -0,0 +1,70 @@
1
+ import type { DshShell } from '../api/dsh.js';
2
+ import { runShell } from './shell.js';
3
+ import { quoteShellArg } from './shell-text.js';
4
+ import { parseJsonLoose } from '../lib/text.js';
5
+ import { VERSION_CHECK_TIMEOUT_MS, VERSION_CHECK_TTL_MS } from '../config/constants.js';
6
+
7
+ function recordOf(value: unknown): Readonly<Record<string, unknown>> | undefined {
8
+ return typeof value === 'object' && value !== null ? (value as Readonly<Record<string, unknown>>) : undefined;
9
+ }
10
+
11
+ export interface RegistryDshLookup {
12
+ readonly readable: boolean;
13
+ readonly raw: unknown;
14
+ }
15
+
16
+ export interface RegistryLookup {
17
+ registryDshOf(options: RegistryDshOptions): Promise<RegistryDshLookup>;
18
+ registryDeclarationOf(options: RegistryDeclarationOptions): Promise<unknown | undefined>;
19
+ }
20
+
21
+ interface RegistryDshOptions {
22
+ readonly shell: DshShell;
23
+ readonly name: string;
24
+ readonly registry?: string | undefined;
25
+ readonly force?: boolean;
26
+ readonly cacheDir?: string | undefined;
27
+ }
28
+
29
+ interface RegistryDeclarationOptions extends RegistryDshOptions {
30
+ readonly registry: string;
31
+ }
32
+
33
+ export function createRegistryLookup(): RegistryLookup {
34
+ const cache = new Map<string, { at: number; raw: unknown }>();
35
+ return {
36
+ registryDshOf: (options) => dshOf(cache, options),
37
+ registryDeclarationOf: async (options) => {
38
+ const found = await dshOf(cache, options);
39
+ return found.readable ? recordOf(found.raw)?.workbench : undefined;
40
+ },
41
+ };
42
+ }
43
+
44
+ async function dshOf(cache: Map<string, { at: number; raw: unknown }>, options: {
45
+ shell: DshShell;
46
+ name: string;
47
+ registry?: string | undefined;
48
+ force?: boolean;
49
+ cacheDir?: string | undefined;
50
+ }): Promise<RegistryDshLookup> {
51
+ const { shell, name, registry, force = false, cacheDir } = options;
52
+ const key = `${registry ?? ''}|${name}`;
53
+ const hit = cache.get(key);
54
+ if (!force && hit !== undefined && Date.now() - hit.at < VERSION_CHECK_TTL_MS) {
55
+ return { readable: true, raw: hit.raw };
56
+ }
57
+
58
+ const at = registry === undefined ? '' : ` --registry ${quoteShellArg(registry)}`;
59
+ const cached = cacheDir === undefined ? '' : ` --cache ${quoteShellArg(cacheDir)}`;
60
+ const result = await runShell(
61
+ shell,
62
+ `npm view ${quoteShellArg(name)} dsh --json${at}${cached}`,
63
+ { timeoutMs: VERSION_CHECK_TIMEOUT_MS },
64
+ ).catch(() => undefined);
65
+ const parsed = result?.exitCode === 0 ? parseJsonLoose(result.stdout) : undefined;
66
+ if (parsed === undefined) return { readable: false, raw: undefined };
67
+ cache.set(key, { at: Date.now(), raw: parsed });
68
+ return { readable: true, raw: parsed };
69
+ }
70
+
@@ -0,0 +1,202 @@
1
+ import type { DshShell } from '../api/dsh.js';
2
+ import type { PluginRelease } from '../contract/unit.js';
3
+
4
+ import { RELEASE_PACKAGES } from './release-packages.generated.js';
5
+ import { VERSION_CHECK_TIMEOUT_MS, VERSION_CHECK_TTL_MS } from '../config/constants.js';
6
+ import { isValidVersion } from './version.js';
7
+ import { parseJsonLoose } from '../lib/text.js';
8
+ import { quoteShellArg } from './shell-text.js';
9
+ import { runShell } from './shell.js';
10
+
11
+ function cacheFlag(cacheDir: string | undefined): string {
12
+ return cacheDir === undefined ? '' : ` --cache ${quoteShellArg(cacheDir)}`;
13
+ }
14
+
15
+ export function parseLedgerVersion(
16
+ stdout: string,
17
+ name: string,
18
+ ): string | undefined {
19
+ const parsed = parseJsonLoose(stdout);
20
+ if (typeof parsed !== "object" || parsed === null) return undefined;
21
+ const entry = (parsed as { dependencies?: Record<string, unknown> })
22
+ .dependencies?.[name];
23
+ if (typeof entry !== "object" || entry === null) return undefined;
24
+ const version = (entry as { version?: unknown }).version;
25
+ return typeof version === "string" && isValidVersion(version.trim())
26
+ ? version.trim()
27
+ : undefined;
28
+ }
29
+
30
+ function parseVersion(stdout: string): string | undefined {
31
+ const value = stdout.trim();
32
+ return isValidVersion(value) ? value : undefined;
33
+ }
34
+
35
+ interface CacheEntry {
36
+ readonly at: number;
37
+ readonly value: string | undefined;
38
+ }
39
+
40
+
41
+ export interface ReleaseProbe {
42
+ latestVersion(options: LatestVersionOptions): Promise<string | undefined>;
43
+ missingReleaseParts(options: MissingPartsOptions): Promise<readonly string[]>;
44
+ probeRelease(options: ProbeReleaseOptions): Promise<PluginRelease | undefined>;
45
+ reset(): void;
46
+ }
47
+
48
+ export function createReleaseProbe(): ReleaseProbe {
49
+ const latestCache = new Map<string, CacheEntry>();
50
+ const existsCache = new Map<string, ExistsEntry>();
51
+
52
+ return {
53
+ latestVersion: async (options) => latestVersionOf(latestCache, options),
54
+ missingReleaseParts: async (options) => missingPartsOf(latestCache, existsCache, options),
55
+ probeRelease: async (options) => probeOf(latestCache, options),
56
+ reset: () => {
57
+ latestCache.clear();
58
+ existsCache.clear();
59
+ },
60
+ };
61
+ }
62
+
63
+ interface LatestVersionOptions {
64
+ readonly shell: DshShell;
65
+ readonly name: string;
66
+ readonly registry: string;
67
+ readonly force?: boolean;
68
+ readonly cacheDir?: string | undefined;
69
+ }
70
+
71
+ interface MissingPartsOptions {
72
+ readonly shell: DshShell;
73
+ readonly name: string;
74
+ readonly registry: string;
75
+ readonly version: string;
76
+ readonly force?: boolean;
77
+ readonly cacheDir?: string | undefined;
78
+ }
79
+
80
+ interface ProbeReleaseOptions {
81
+ readonly shell: DshShell;
82
+ readonly package: string;
83
+ readonly registry?: string | undefined;
84
+ readonly force?: boolean;
85
+ readonly cacheDir?: string | undefined;
86
+ readonly prefix?: string | undefined;
87
+ }
88
+
89
+ async function latestVersionOf(latestCache: Map<string, CacheEntry>, options: {
90
+ shell: DshShell;
91
+ name: string;
92
+ registry: string;
93
+ force?: boolean;
94
+ cacheDir?: string | undefined;
95
+ }): Promise<string | undefined> {
96
+ const { shell, name, registry, force = false, cacheDir } = options;
97
+ const key = `${registry}|${name}`;
98
+ const hit = latestCache.get(key);
99
+ if (!force && hit !== undefined && Date.now() - hit.at < VERSION_CHECK_TTL_MS)
100
+ return hit.value;
101
+
102
+ const result = await runShell(
103
+ shell,
104
+ `npm view ${quoteShellArg(name)} version --registry ${quoteShellArg(registry)}${cacheFlag(cacheDir)}`,
105
+ { timeoutMs: VERSION_CHECK_TIMEOUT_MS },
106
+ ).catch(() => undefined);
107
+ const read = result?.exitCode === 0 ? parseVersion(result.stdout) : undefined;
108
+ latestCache.set(key, { at: Date.now(), value: read });
109
+ return read;
110
+ }
111
+
112
+ interface ExistsEntry {
113
+ readonly at: number;
114
+ readonly value: boolean;
115
+ }
116
+
117
+
118
+ async function versionExists(
119
+ existsCache: Map<string, ExistsEntry>,
120
+ options: {
121
+ shell: DshShell;
122
+ name: string;
123
+ version: string;
124
+ registry: string;
125
+ force?: boolean;
126
+ cacheDir?: string | undefined;
127
+ }): Promise<boolean> {
128
+ const { shell, name, version, registry, force = false, cacheDir } = options;
129
+ const key = `${registry}|${name}@${version}`;
130
+ const hit = existsCache.get(key);
131
+ if (!force && hit !== undefined && (hit.value || Date.now() - hit.at < VERSION_CHECK_TTL_MS))
132
+ return hit.value;
133
+
134
+ const result = await runShell(
135
+ shell,
136
+ `npm view ${quoteShellArg(`${name}@${version}`)} version --registry ${quoteShellArg(registry)}${cacheFlag(cacheDir)}`,
137
+ { timeoutMs: VERSION_CHECK_TIMEOUT_MS },
138
+ ).catch(() => undefined);
139
+ const value = result?.exitCode === 0 && parseVersion(result.stdout) !== undefined;
140
+ existsCache.set(key, { at: Date.now(), value });
141
+ return value;
142
+ }
143
+
144
+ async function missingPartsOf(
145
+ latestCache: Map<string, CacheEntry>,
146
+ existsCache: Map<string, ExistsEntry>,
147
+ options: {
148
+ shell: DshShell;
149
+ name: string;
150
+ registry: string;
151
+ version: string;
152
+ force?: boolean;
153
+ cacheDir?: string | undefined;
154
+ }): Promise<readonly string[]> {
155
+ const { shell, name, registry, version, force = false, cacheDir } = options;
156
+ const checked = await Promise.all(
157
+ RELEASE_PACKAGES.filter((part) => part !== name).map(async (part) => ({
158
+ part,
159
+ present: await versionExists(existsCache, { shell, name: part, version, registry, force, cacheDir }),
160
+ })),
161
+ );
162
+ return checked.filter((entry) => !entry.present).map((entry) => entry.part);
163
+ }
164
+
165
+ async function probeOf(
166
+ latestCache: Map<string, CacheEntry>,
167
+ options: {
168
+ shell: DshShell;
169
+ package: string;
170
+ registry?: string | undefined;
171
+ force?: boolean;
172
+ cacheDir?: string | undefined;
173
+ prefix?: string | undefined;
174
+ }): Promise<PluginRelease | undefined> {
175
+ const { shell, package: pkg, registry, force = false, cacheDir, prefix } = options;
176
+ if (pkg === "") return undefined;
177
+
178
+ const ledger = await runShell(
179
+ shell,
180
+ `npm ls --prefix ${quoteShellArg(prefix ?? '')} ${quoteShellArg(pkg)} --json --depth=0${cacheFlag(cacheDir)}`,
181
+ { timeoutMs: VERSION_CHECK_TIMEOUT_MS },
182
+ ).catch(() => undefined);
183
+ const installed =
184
+ ledger === undefined ? undefined : parseLedgerVersion(ledger.stdout, pkg);
185
+ if (installed === undefined) return undefined;
186
+
187
+ const source =
188
+ registry === undefined || registry.trim() === ""
189
+ ? undefined
190
+ : registry.trim();
191
+ const latest =
192
+ source === undefined
193
+ ? undefined
194
+ : await latestVersionOf(latestCache, { shell, name: pkg, registry: source, force, cacheDir });
195
+
196
+ return {
197
+ installed,
198
+ ...(latest === undefined ? {} : { latest }),
199
+ };
200
+ }
201
+
202
+
package/src/host/shell.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { DshShell } from '../api/dsh.js';
2
2
  import { GIT_TIMEOUT_MS } from '../config/constants.js';
3
- import { quoteShellArg } from './shell-text.js';
4
3
 
5
4
  export interface ShellResult {
6
5
  readonly exitCode: number | null;
@@ -41,11 +40,3 @@ export async function runShell(
41
40
  truncated: result.stdout.truncated || result.stderr.truncated,
42
41
  };
43
42
  }
44
-
45
- export function backgroundPrefix(): readonly string[] {
46
- return [quoteShellArg('env'), quoteShellArg('OPENCLI_WINDOW=background')];
47
- }
48
-
49
- export function backgroundLine(command: string, argv: readonly string[]): string {
50
- return [...backgroundPrefix(), quoteShellArg(command), ...argv.map(quoteShellArg)].join(' ');
51
- }
package/src/host/spec.ts CHANGED
@@ -28,5 +28,5 @@ export function localDirOf(spec: string): string | undefined {
28
28
  }
29
29
 
30
30
  export function refusalReason(): string {
31
- return '这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上';
31
+ return '这个包既不是工作台的模块,也不是运行时的插件,装了也用不上';
32
32
  }
@@ -1,5 +1,5 @@
1
1
  import type { ExtensionNeed, LibNeed, Need, SupplySource } from '../contract/needs.js';
2
- import { npmRegistryOf } from './plugin-source.js';
2
+ import { npmRegistryOf } from './npm-registry.js';
3
3
 
4
4
  export interface SupplyDeclaration {
5
5
  readonly id: string;
@@ -8,6 +8,7 @@ export interface SupplyDeclaration {
8
8
 
9
9
  export interface SupplyIndexOptions {
10
10
  readonly env?: Readonly<Record<string, string | undefined>>;
11
+ readonly packagePrefix?: string | undefined;
11
12
  }
12
13
 
13
14
  export interface SupplyEntry {
@@ -61,8 +62,8 @@ function text(value: string | undefined): string {
61
62
  return value === undefined ? '' : value.trim();
62
63
  }
63
64
 
64
- function conventionPackage(name: string): string {
65
- return `opencli-plugin-${name}`;
65
+ function conventionPackage(name: string, prefix: string): string {
66
+ return `${prefix}${name}`;
66
67
  }
67
68
 
68
69
  function nativeSourcePackage(source: SupplySource): string {
@@ -71,13 +72,13 @@ function nativeSourcePackage(source: SupplySource): string {
71
72
  return `local:${text(source.env) || text(source.path)}`;
72
73
  }
73
74
 
74
- function packageOf(need: ExtensionNeed | LibNeed): string {
75
+ function packageOf(need: ExtensionNeed | LibNeed, prefix: string): string {
75
76
  if (need.kind === 'lib') return text(need.name);
76
77
  const first = need.sources?.[0];
77
- if (first === undefined) return conventionPackage(need.name);
78
+ if (first === undefined) return conventionPackage(need.name, prefix);
78
79
  if (first.kind === 'npm') {
79
80
  const pkg = text(first.package);
80
- return pkg === '' ? conventionPackage(need.name) : pkg;
81
+ return pkg === '' ? conventionPackage(need.name, prefix) : pkg;
81
82
  }
82
83
  return nativeSourcePackage(first);
83
84
  }
@@ -180,6 +181,7 @@ export function buildSupplyIndex(
180
181
  options: SupplyIndexOptions = {},
181
182
  ): SupplyIndex {
182
183
  const env = options.env ?? {};
184
+ const prefix = options.packagePrefix ?? '';
183
185
  const entries = new Map<string, MutableEntry>();
184
186
  const byName = new Map<string, MutableEntry>();
185
187
  const conflicts: SupplyConflict[] = [];
@@ -206,7 +208,7 @@ export function buildSupplyIndex(
206
208
  for (const declaration of declarations) {
207
209
  for (const need of declaration.needs ?? []) {
208
210
  if (need.kind !== 'extension' && need.kind !== 'lib') continue;
209
- const pkg = packageOf(need);
211
+ const pkg = packageOf(need, prefix);
210
212
  const entry = ensure(need.kind, pkg);
211
213
  if (!entry.names.includes(need.name)) entry.names.push(need.name);
212
214
  if (need.kind === 'extension') {
@@ -8,20 +8,30 @@ export function supplyPortOf(ctx: DshHostContext): SupplyPort {
8
8
  const set = adaptersOf(ctx);
9
9
  const env = set.supply;
10
10
  const modules = set.modules;
11
+ const pluginPackagePrefix = modules.pluginPackagePrefix;
12
+ const pluginManifestFile = modules.pluginManifestFile;
13
+ const cliCatalogPath = modules.cliCatalogPath;
14
+ const vendorPluginsDir = modules.vendorPluginsDir;
15
+ const runtimeInstallCommand = modules.runtimeInstallCommand;
11
16
  return {
12
17
  env,
13
18
  modules,
14
19
  resolvePluginSource: (source, environment, options) => env.resolvePluginSource(source, environment, options),
15
20
  libInstallCommand: (options) => env.libInstallCommand(options),
21
+ libUninstallCommand: (options) => env.libUninstallCommand(options),
16
22
  pluginInstallPlan: (options) => env.pluginInstallPlan(options),
17
23
  latestVersion: (options) => env.latestVersion(options),
18
24
  missingReleaseParts: (options) => env.missingReleaseParts(options),
19
25
  probeRelease: (options) => env.probeRelease(options),
20
26
  splitNpmSpec: (spec) => env.splitNpmSpec(spec),
27
+ isolatedRoot: () => modules.isolatedRoot(),
21
28
  isolatedHome: () => modules.isolatedHome(),
22
- cliCatalogPath: () => modules.cliCatalogPath(),
23
- vendorPluginsDir: () => modules.vendorPluginsDir(),
24
- opencliInstallCommand: () => modules.opencliInstallCommand(),
29
+ ...(pluginPackagePrefix === undefined ? {} : { pluginPackagePrefix: () => pluginPackagePrefix() }),
30
+ ...(pluginManifestFile === undefined ? {} : { pluginManifestFile: () => pluginManifestFile() }),
31
+ ...(cliCatalogPath === undefined ? {} : { cliCatalogPath: () => cliCatalogPath() }),
32
+ ...(vendorPluginsDir === undefined ? {} : { vendorPluginsDir: () => vendorPluginsDir() }),
33
+ ...(runtimeInstallCommand === undefined ? {} : { runtimeInstallCommand: () => runtimeInstallCommand() }),
34
+ afterLibInstall: () => modules.afterLibInstall(),
25
35
  profileDirOf: (context) => modules.profileDirOf(context),
26
36
  profileModules: (dir) => modules.profileModules(dir),
27
37
  readInstalledModule: (dir, pkg) => modules.readInstalledModule(dir, pkg),
@@ -11,13 +11,14 @@ import type { DataReader } from '../contract/data.js';
11
11
  import type { LibReader } from '../contract/lib.js';
12
12
  import type { GitReader } from '../contract/git.js';
13
13
  import type { CommandReader } from '../contract/command.js';
14
+ import type { HostKit } from './host-kit.js';
14
15
 
15
16
  export interface ToolScopeContext {
16
17
  readonly workspace: string | null;
17
18
  readonly preset: string | null;
18
19
  }
19
20
 
20
- export interface UnitMountDeps {
21
+ export interface UnitMountDeps extends HostKit {
21
22
  readonly manifest: UnitManifest;
22
23
  readonly ctx: DshHostContext;
23
24
  readonly logger?: { info?(message: string): void; warn?(message: string): void } | undefined;
@@ -19,12 +19,17 @@ export function isNewerVersion(latest: string, installed: string): boolean {
19
19
  }
20
20
 
21
21
  export function runningVersionOf(moduleUrl: string): string | undefined {
22
- try {
23
- const read = JSON.parse(readFileSync(new URL('../../package.json', moduleUrl), 'utf8')) as {
24
- readonly version?: unknown;
25
- };
26
- return typeof read.version === 'string' && read.version !== '' ? read.version : undefined;
27
- } catch {
28
- return undefined;
22
+ for (const depth of ['../../package.json', '../package.json']) {
23
+ try {
24
+ const read = JSON.parse(readFileSync(new URL(depth, moduleUrl), 'utf8')) as {
25
+ readonly version?: unknown;
26
+ readonly name?: unknown;
27
+ };
28
+ if (typeof read.name !== 'string' || !read.name.startsWith('@dsh-workbench/')) continue;
29
+ return typeof read.version === 'string' && read.version !== '' ? read.version : undefined;
30
+ } catch {
31
+ continue;
32
+ }
29
33
  }
34
+ return undefined;
30
35
  }
package/src/host.ts CHANGED
@@ -19,6 +19,31 @@ export * from './lib/git-address.js';
19
19
  export * from './api/blocker-table.js';
20
20
  export * from './contract/unit-declaration.js';
21
21
  export * from './host/board-fact.js';
22
+ export * from './host/bundle-manager.js';
23
+ export * from './host/installed-module.js';
24
+ export * from './host/local-declaration.js';
25
+ export * from './host/registry-declaration.js';
26
+ export * from './host/release-probe.js';
27
+ export * from './host/package-kind.js';
28
+ export * from './host/package-content.js';
29
+ export * from './host/package-route.js';
30
+ export * from './host/lib-install.js';
31
+ export * from './host/module-root.js';
32
+ export * from './host/dsh-plugins.js';
33
+ export * from './host/profile-registries.js';
34
+ export * from './host/host-actions.js';
35
+ export {
36
+ configSyncAction,
37
+ configSyncApply,
38
+ configSyncHandler,
39
+ configSyncSnapshot,
40
+ mergeBlocks,
41
+ normalizeBlock,
42
+ readPatchBlocks,
43
+ syncRows,
44
+ type ConfigSyncDeps,
45
+ } from './host/config-sync.js';
46
+ export * from './host/profile-create.js';
22
47
  export * from './host/context-ref.js';
23
48
  export * from './host/diy-debug.js';
24
49
  export * from './host/diy-record.js';
@@ -27,6 +52,12 @@ export * from './host/git.js';
27
52
  export * from './host/http.js';
28
53
  export * from './host/lib-capabilities.js';
29
54
  export * from './host/long-task.js';
55
+ export * from './host/flow/types.js';
56
+ export * from './host/flow/expr.js';
57
+ export * from './host/flow/check.js';
58
+ export * from './host/flow/run.js';
59
+ export * from './host/flow/kit.js';
60
+ export * from './host/host-kit.js';
30
61
  export * from './host/panel-state.js';
31
62
  export * from './host/plugin-ledger.js';
32
63
  export * from './host/time.js';
@@ -34,7 +65,6 @@ export * from './host/tokens.js';
34
65
  export * from './host/tool-approval.js';
35
66
  export * from './host/tool-kit.js';
36
67
  export * from './host/unit-face.js';
37
- export * from './host/opencli-runner.js';
38
68
  export * from './host/lib-runners.js';
39
69
  export * from './host/value-handoff.js';
40
70
  export * from './host/workspace-store.js';
@@ -45,9 +75,7 @@ export * from './host/shell-text.js';
45
75
  export * from './host/shell.js';
46
76
  export * from './host/data-error.js';
47
77
  export * from './host/install-failure.js';
48
- export * from './host/runtime-links.js';
49
78
  export * from './host/provision.js';
50
- export * from './host/channel-plugin.js';
51
79
  export * from './host/recipe.js';
52
80
  export * from './host/recipe-rules.js';
53
81
  export * from './host/release-packages.generated.js';
@@ -55,7 +83,6 @@ export * from './contract/unit-capability.js';
55
83
  export * from './contract/plugin-source.js';
56
84
  export * from './contract/cli.js';
57
85
  export * from './host/cli.js';
58
- export * from './host/command-name.js';
59
86
  export * from './host/browser.js';
60
87
  export * from './host/preflight.js';
61
88
  export * from './host/platform.js';
@@ -66,8 +93,8 @@ export * from './host/adapter-types.js';
66
93
  export * from './host/paths.js';
67
94
  export * from './host/plugin.js';
68
95
  export * from './host/spec.js';
69
- export * from './host/plugin-source.js';
70
- export * from './host/lib-install.js';
96
+ export type { PluginSourceCommand, PluginSourceOptions, ResolvedPluginSource } from './contract/plugin-source.js';
97
+ export * from './host/npm-registry.js';
71
98
  export * from './host/supply-index.js';
72
99
  export * from './host/patch.js';
73
100
  export * from './host/adapters.js';
@@ -75,6 +102,7 @@ export * from './host/adapter-set.js';
75
102
  export * from './host/needs.js';
76
103
  export * from './host/extension.js';
77
104
  export * from './host/port-types.js';
105
+ export * from './host/adapter-contract.js';
78
106
  export * from './host/version-range.js';
79
107
  export * from './host/market-index.js';
80
108
  export * from './host/market-index-claim.js';
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { en } from './en.js';
3
- import { dictionaries } from './index.js';
4
- import { zh } from './zh.js';
2
+ import { en } from '../en.js';
3
+ import { dictionaries } from '../index.js';
4
+ import { zh } from '../zh.js';
5
5
 
6
6
  describe('dictionaries', () => {
7
7
  it('同时导出两种语言,且就是那两份字典', () => {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { mergeMessages, mergeMessagesSkipping } from './merge.js';
2
+ import { mergeMessages, mergeMessagesSkipping } from '../merge.js';
3
3
 
4
4
  const base = { zh: { 'board.title': '看板' }, en: { 'board.title': 'Board' } };
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { en } from './en.js';
3
- import { zh } from './zh.js';
2
+ import { en } from '../en.js';
3
+ import { zh } from '../zh.js';
4
4
 
5
5
  function placeholders(text: string): string[] {
6
6
  return [...text.matchAll(/\{(\w+)\}/g)].map((match) => match[1] ?? '').sort();