@dsh-workbench/shared 1.1.14-beta.1 → 1.1.14

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 (144) hide show
  1. package/README.md +1 -1
  2. package/dist/api/dsh.d.ts +12 -0
  3. package/dist/components/SelectFieldWheel.d.ts +9 -0
  4. package/dist/components/SelectFieldWheel.js +35 -0
  5. package/dist/config/constants.d.ts +5 -1
  6. package/dist/config/constants.js +5 -1
  7. package/dist/contract/unit-declaration.js +15 -1
  8. package/dist/contract/unit.d.ts +3 -0
  9. package/dist/host/__scratch-guard.d.ts +1 -0
  10. package/dist/host/__scratch-guard.js +1 -0
  11. package/dist/host/adapter-set.js +0 -1
  12. package/dist/host/changelog.js +2 -1
  13. package/dist/host/channel-plugin.d.ts +15 -0
  14. package/dist/host/channel-plugin.js +42 -0
  15. package/dist/host/command-name.d.ts +1 -0
  16. package/dist/host/command-name.js +14 -0
  17. package/dist/host/config-sync.d.ts +1 -9
  18. package/dist/host/config-sync.js +3 -78
  19. package/dist/host/env-policy.d.ts +75 -0
  20. package/dist/host/env-policy.js +161 -0
  21. package/dist/host/extension.js +2 -1
  22. package/dist/host/flow/run.js +2 -1
  23. package/dist/host/fs-write.d.ts +62 -0
  24. package/dist/host/fs-write.js +112 -0
  25. package/dist/host/host-kit.d.ts +6 -2
  26. package/dist/host/host-kit.js +3 -1
  27. package/dist/host/http.js +11 -5
  28. package/dist/host/installed-sources.js +4 -5
  29. package/dist/host/long-task.js +3 -3
  30. package/dist/host/opencli-runner.d.ts +26 -0
  31. package/dist/host/opencli-runner.js +50 -0
  32. package/dist/host/package-content.d.ts +2 -2
  33. package/dist/host/package-content.js +20 -6
  34. package/dist/host/package-route.d.ts +3 -3
  35. package/dist/host/package-route.js +7 -6
  36. package/dist/host/panel-state.js +2 -1
  37. package/dist/host/patch-blocks.d.ts +13 -0
  38. package/dist/host/patch-blocks.js +52 -0
  39. package/dist/host/patch.d.ts +3 -8
  40. package/dist/host/patch.js +5 -76
  41. package/dist/host/plugin-source.d.ts +33 -0
  42. package/dist/host/plugin-source.js +91 -0
  43. package/dist/host/port-types.d.ts +9 -9
  44. package/dist/host/profile-registries.js +2 -3
  45. package/dist/host/registry-declaration.d.ts +2 -2
  46. package/dist/host/registry-declaration.js +14 -5
  47. package/dist/host/release-probe.d.ts +4 -4
  48. package/dist/host/release-probe.js +39 -14
  49. package/dist/host/runner.d.ts +26 -0
  50. package/dist/host/runner.js +50 -0
  51. package/dist/host/runtime-links.d.ts +7 -0
  52. package/dist/host/runtime-links.js +25 -0
  53. package/dist/host/seam/denial.d.ts +4 -0
  54. package/dist/host/seam/denial.js +24 -0
  55. package/dist/host/seam/env.d.ts +15 -0
  56. package/dist/host/seam/env.js +17 -0
  57. package/dist/host/seam/exec.d.ts +84 -0
  58. package/dist/host/seam/exec.js +1 -0
  59. package/dist/host/seam/host-env.d.ts +2 -0
  60. package/dist/host/seam/host-env.js +18 -0
  61. package/dist/host/seam/intent.d.ts +66 -0
  62. package/dist/host/seam/intent.js +24 -0
  63. package/dist/host/seam/policy.d.ts +10 -0
  64. package/dist/host/seam/policy.js +85 -0
  65. package/dist/host/seam/process.d.ts +2 -0
  66. package/dist/host/seam/process.js +80 -0
  67. package/dist/host/seam/run.d.ts +44 -0
  68. package/dist/host/seam/run.js +421 -0
  69. package/dist/host/seam/service.d.ts +4 -0
  70. package/dist/host/seam/service.js +4 -0
  71. package/dist/host/seam/unit-seam.d.ts +14 -0
  72. package/dist/host/seam/unit-seam.js +43 -0
  73. package/dist/host/shell.d.ts +12 -0
  74. package/dist/host/shell.js +3 -1
  75. package/dist/host/time.d.ts +10 -0
  76. package/dist/host/time.js +14 -0
  77. package/dist/host/value-handoff.js +3 -2
  78. package/dist/host/workspace-store.js +2 -8
  79. package/dist/host.d.ts +11 -0
  80. package/dist/host.js +11 -0
  81. package/dist/i18n/en.js +3 -3
  82. package/dist/i18n/index.d.ts +4 -4
  83. package/dist/i18n/zh.d.ts +3 -3
  84. package/dist/i18n/zh.js +3 -3
  85. package/dist/lib/version.d.ts +4 -0
  86. package/dist/lib/version.js +21 -0
  87. package/dist/testing/fake-adapter-set.js +0 -1
  88. package/dist/testing/git.d.ts +3 -0
  89. package/dist/testing/git.js +36 -0
  90. package/dist/testing/host-fakes.d.ts +30 -0
  91. package/dist/testing/host-fakes.js +104 -0
  92. package/package.json +5 -2
  93. package/src/api/dsh.ts +8 -1
  94. package/src/config/__tests__/constants.test.ts +10 -0
  95. package/src/config/constants.ts +7 -1
  96. package/src/contract/unit-declaration.ts +20 -1
  97. package/src/contract/unit.ts +3 -0
  98. package/src/host/__tests__/env-policy.test.ts +114 -0
  99. package/src/host/__tests__/fs-write.test.ts +96 -0
  100. package/src/host/__tests__/preflight-route.test.ts +29 -0
  101. package/src/host/__tests__/seam.test.ts +296 -0
  102. package/src/host/__tests__/shell.test.ts +24 -0
  103. package/src/host/__tests__/time.test.ts +20 -0
  104. package/src/host/adapter-set.ts +0 -1
  105. package/src/host/changelog.ts +2 -1
  106. package/src/host/config-sync.ts +3 -90
  107. package/src/host/env-policy.ts +192 -0
  108. package/src/host/extension.ts +2 -1
  109. package/src/host/flow/run.ts +2 -1
  110. package/src/host/fs-write.ts +137 -0
  111. package/src/host/host-kit.ts +7 -2
  112. package/src/host/http.ts +11 -5
  113. package/src/host/installed-sources.ts +4 -5
  114. package/src/host/long-task.ts +3 -3
  115. package/src/host/package-content.ts +23 -13
  116. package/src/host/package-route.ts +10 -9
  117. package/src/host/panel-state.ts +2 -1
  118. package/src/host/patch-blocks.ts +67 -0
  119. package/src/host/patch.ts +5 -89
  120. package/src/host/port-types.ts +9 -9
  121. package/src/host/profile-registries.ts +2 -3
  122. package/src/host/registry-declaration.ts +17 -12
  123. package/src/host/release-probe.ts +47 -34
  124. package/src/host/seam/denial.ts +26 -0
  125. package/src/host/seam/env.ts +23 -0
  126. package/src/host/seam/exec.ts +94 -0
  127. package/src/host/seam/host-env.ts +20 -0
  128. package/src/host/seam/intent.ts +101 -0
  129. package/src/host/seam/policy.ts +89 -0
  130. package/src/host/seam/process.ts +90 -0
  131. package/src/host/seam/run.ts +484 -0
  132. package/src/host/seam/service.ts +8 -0
  133. package/src/host/seam/unit-seam.ts +62 -0
  134. package/src/host/shell.ts +17 -1
  135. package/src/host/time.ts +16 -0
  136. package/src/host/value-handoff.ts +3 -2
  137. package/src/host/workspace-store.ts +2 -8
  138. package/src/host.ts +11 -0
  139. package/src/i18n/en.ts +3 -3
  140. package/src/i18n/zh.ts +3 -3
  141. package/src/testing/fake-adapter-set.ts +0 -1
  142. package/src/testing/host-fakes.ts +126 -0
  143. package/dist/lib/unit-plugin.d.ts +0 -28
  144. package/dist/lib/unit-plugin.js +0 -23
package/src/host.ts CHANGED
@@ -47,7 +47,9 @@ export * from './host/profile-create.js';
47
47
  export * from './host/context-ref.js';
48
48
  export * from './host/diy-debug.js';
49
49
  export * from './host/diy-record.js';
50
+ export * from './host/env-policy.js';
50
51
  export * from './host/facts.js';
52
+ export * from './host/fs-write.js';
51
53
  export * from './host/git.js';
52
54
  export * from './host/http.js';
53
55
  export * from './host/lib-capabilities.js';
@@ -76,6 +78,15 @@ export * from './host/cli-error.js';
76
78
  export * from './host/data-root.js';
77
79
  export * from './host/shell-text.js';
78
80
  export * from './host/shell.js';
81
+ export * from './host/seam/intent.js';
82
+ export * from './host/seam/policy.js';
83
+ export * from './host/seam/env.js';
84
+ export * from './host/seam/denial.js';
85
+ export * from './host/seam/run.js';
86
+ export * from './host/seam/exec.js';
87
+ export * from './host/seam/process.js';
88
+ export * from './host/seam/unit-seam.js';
89
+ export * from './host/seam/service.js';
79
90
  export * from './host/data-error.js';
80
91
  export * from './host/install-failure.js';
81
92
  export * from './host/provision.js';
package/src/i18n/en.ts CHANGED
@@ -594,9 +594,8 @@ export const en: Record<keyof WorkbenchMessages, string> = {
594
594
  'env.title': 'Preparing the workbench',
595
595
  'env.checking': 'Getting the runtime ready…',
596
596
  'env.installing': 'Installing background tools — the first run takes a moment…',
597
- 'env.installingToolchain': 'Installing the workbench’s own npm / pnpm — the first run downloads them, so it can take a while.',
597
+ 'env.installingToolchain': 'Installing the workbench’s own pnpm — the first run downloads it, so it can take a while.',
598
598
  'env.failed': 'One step away',
599
- 'env.elapsed': 'Waiting {seconds}s',
600
599
  'env.stepFailed.install': 'install failed',
601
600
  'env.stepFailed.path': 'installed but not found',
602
601
  'env.stepFailed.shell': 'cannot reach the command line',
@@ -615,14 +614,15 @@ export const en: Record<keyof WorkbenchMessages, string> = {
615
614
  'env.fix.whyShell': 'The workbench cannot reach the command line on this machine, so it cannot fetch data \u2014 you cannot install this from here; someone needs to fix the background environment.',
616
615
  'env.fix.whyHost': 'The workbench runs a few checks on the command line and collects what they return; this time the command went out and nothing came back. The tools themselves are most likely fine \u2014 reinstalling Node / npm / pnpm will not help.',
617
616
  'env.fix.step': 'Run this in a terminal, then hit Retry:',
617
+ 'env.fix.stepRetry': 'Hit Retry to try again; if it still fails you can enter the workbench anyway and restart it once the install succeeds.',
618
618
  'env.fix.stepPath': 'Open a new terminal window (or make sure npm\u2019s global bin directory is on PATH), then hit Retry.',
619
619
  'env.fix.stepShell': 'Restart the workbench (or dsh); if it keeps happening, the workbench still cannot reach the command line.',
620
620
  'env.fix.stepHost': 'Quit the workbench completely (including the tray icon), clear the dsh-* leftovers in the system temp folder, then open it again. If it keeps happening, update dsh.',
621
621
  'env.fix.permission': 'Permission denied: rerun with sudo, or point npm\u2019s global directory at your home.',
622
622
  'env.fix.network': 'Network unreachable: check your network or proxy, then retry.',
623
623
  'env.fix.details': 'Details (for troubleshooting)',
624
- 'env.log': 'Detailed output',
625
624
  'env.retry': 'Retry',
625
+ 'env.failed.continue': 'Enter workbench anyway',
626
626
  'env.wake': 'Open browser',
627
627
  'env.wake.opening': 'Opening the browser…',
628
628
  'env.wake.browserOpen': 'The browser is already running but the extension is not connected — check that it is enabled.',
package/src/i18n/zh.ts CHANGED
@@ -590,9 +590,8 @@ export const zh = {
590
590
  'env.title': '准备工作台',
591
591
  'env.checking': '正在准备运行环境…',
592
592
  'env.installing': '正在安装后台工具,第一次会慢一点…',
593
- 'env.installingToolchain': '正在装工作台自己那份 npm / pnpm —— 第一次要下载,慢一点正常。',
593
+ 'env.installingToolchain': '正在装工作台自己那份 pnpm —— 第一次要下载,慢一点正常。',
594
594
  'env.failed': '还差一步就能用了',
595
- 'env.elapsed': '已等待 {seconds} 秒',
596
595
  'env.stepFailed.install': '装不上',
597
596
  'env.stepFailed.path': '装了但还找不到',
598
597
  'env.stepFailed.shell': '连不上命令行',
@@ -611,14 +610,15 @@ export const zh = {
611
610
  'env.fix.whyShell': '工作台拿不到这台机器的命令行,所以取不了数据 —— 这一步你装不了,需要有人处理后台环境。',
612
611
  'env.fix.whyHost': '工作台要靠命令行跑几条检查,再把结果收回来;这次命令发出去了,结果一直没回来。工具本身多半是好的 —— 重装 Node / npm / pnpm 不会有帮助。',
613
612
  'env.fix.step': '在终端里运行下面这条命令,装好之后点「重试」:',
613
+ 'env.fix.stepRetry': '点「重试」再装一次;还装不上也可以先进入工作台 —— 装好之后重启工作台就会用上。',
614
614
  'env.fix.stepPath': '新开一个终端窗口(或确认 npm 的全局 bin 目录在 PATH 里),然后点「重试」。',
615
615
  'env.fix.stepShell': '重启一次工作台(或 dsh);如果反复出现,说明工作台还是拿不到命令行。',
616
616
  'env.fix.stepHost': '完全退出工作台(托盘图标也要退),清掉系统临时目录里 dsh- 开头的残留,再重新打开;反复出现就升级 dsh。',
617
617
  'env.fix.permission': '权限不够:在命令前加 sudo 重跑,或先把 npm 的全局目录配到你的用户目录。',
618
618
  'env.fix.network': '网络不通:检查网络或代理设置后重试。',
619
619
  'env.fix.details': '详细输出(排障用)',
620
- 'env.log': '详细输出',
621
620
  'env.retry': '重试',
621
+ 'env.failed.continue': '先进入工作台',
622
622
  'env.wake': '打开浏览器',
623
623
  'env.wake.opening': '正在打开浏览器…',
624
624
  'env.wake.browserOpen': '浏览器已经开着,但扩展没连上 —— 检查扩展是否启用。',
@@ -115,7 +115,6 @@ const runtimePreset = (capabilities: RuntimePort['capabilities'] extends never ?
115
115
  runners: () => ({}),
116
116
  health: () => ({}),
117
117
  seed: () => undefined,
118
- warnUnwritableRoot: () => undefined,
119
118
  });
120
119
 
121
120
  const plugins: PluginSurface = {
@@ -1,5 +1,12 @@
1
1
  import { setTimeout as delay } from 'node:timers/promises';
2
2
  import type { DshShell } from '../api/dsh.js';
3
+ import type {
4
+ ProcessChild,
5
+ ProcessExitEvent,
6
+ ProcessHost,
7
+ ProcessSpawnOptions,
8
+ ProcessStream,
9
+ } from '../host/seam/exec.js';
3
10
 
4
11
  export interface ShellCall {
5
12
  command: string;
@@ -8,6 +15,7 @@ export interface ShellCall {
8
15
  onExpiry?: string;
9
16
  stdoutMaxBytes?: number;
10
17
  env?: Readonly<Record<string, string>>;
18
+ sandboxPolicy?: unknown;
11
19
  }
12
20
 
13
21
  export interface ShellReply {
@@ -18,6 +26,7 @@ export interface ShellReply {
18
26
  aborted?: boolean;
19
27
  truncated?: boolean;
20
28
  failWith?: Error;
29
+ sandbox?: { mode?: string; denied?: boolean; enforcement?: string; runnerFailed?: boolean } | undefined;
21
30
  }
22
31
 
23
32
  const tick = (): Promise<void> => delay(0);
@@ -53,6 +62,7 @@ export function createFakeShell(replies: ShellReply[] | ((call: ShellCall, index
53
62
  aborted: reply.aborted ?? false,
54
63
  stdout: { text: reply.stdout ?? '', truncated: reply.truncated === true },
55
64
  stderr: { text: reply.stderr ?? '', truncated: false },
65
+ ...(reply.sandbox === undefined ? {} : { sandbox: reply.sandbox }),
56
66
  };
57
67
  },
58
68
  };
@@ -80,3 +90,119 @@ export function createFakeLogger() {
80
90
  warnings,
81
91
  };
82
92
  }
93
+
94
+ export interface FakeProcessReply {
95
+ readonly stdout?: string;
96
+ readonly stderr?: string;
97
+ readonly exitCode?: number | null;
98
+ readonly signal?: string | null;
99
+ readonly error?: Error;
100
+ readonly hang?: boolean;
101
+ }
102
+
103
+ export interface FakeProcessChild extends ProcessChild {
104
+ readonly writes: readonly string[];
105
+ readonly killed: readonly string[];
106
+ readonly unrefed: boolean;
107
+ finish(code?: number | null, signal?: string | null): void;
108
+ emitStdout(chunk: string): void;
109
+ emitStderr(chunk: string): void;
110
+ fail(error: Error): void;
111
+ }
112
+
113
+ export function createFakeProcesses(
114
+ replies: FakeProcessReply[] | ((call: ProcessSpawnOptions, index: number) => FakeProcessReply) = [],
115
+ ) {
116
+ const calls: ProcessSpawnOptions[] = [];
117
+ const children: FakeProcessChild[] = [];
118
+ const host: ProcessHost = {
119
+ spawn(options) {
120
+ const index = calls.length;
121
+ calls.push(options);
122
+ const reply = typeof replies === 'function' ? replies(options, index) : (replies[index] ?? {});
123
+ const outListeners: Array<(chunk: string) => void> = [];
124
+ const errListeners: Array<(chunk: string) => void> = [];
125
+ const exitListeners: Array<(event: ProcessExitEvent) => void> = [];
126
+ const errorListeners: Array<(error: Error) => void> = [];
127
+ const writes: string[] = [];
128
+ const killed: string[] = [];
129
+ let unrefed = false;
130
+ let finished = false;
131
+ const emitStdout = (chunk: string): void => {
132
+ for (const listener of outListeners) listener(chunk);
133
+ };
134
+ const emitStderr = (chunk: string): void => {
135
+ for (const listener of errListeners) listener(chunk);
136
+ };
137
+ const finish = (code: number | null = 0, signal: string | null = null): void => {
138
+ if (finished) return;
139
+ finished = true;
140
+ for (const listener of exitListeners) listener({ code, signal });
141
+ };
142
+ const child: FakeProcessChild = {
143
+ pid: 4242 + index,
144
+ stdin: { write: (chunk: string) => writes.push(chunk) },
145
+ stdout: streamOf(outListeners),
146
+ stderr: streamOf(errListeners),
147
+ writes,
148
+ killed,
149
+ get unrefed() {
150
+ return unrefed;
151
+ },
152
+ finish,
153
+ emitStdout,
154
+ emitStderr,
155
+ fail(error) {
156
+ for (const listener of errorListeners) listener(error);
157
+ },
158
+ onExit(listener) {
159
+ exitListeners.push(listener);
160
+ return () => {
161
+ const at = exitListeners.indexOf(listener);
162
+ if (at >= 0) exitListeners.splice(at, 1);
163
+ };
164
+ },
165
+ onError(listener) {
166
+ errorListeners.push(listener);
167
+ return () => {
168
+ const at = errorListeners.indexOf(listener);
169
+ if (at >= 0) errorListeners.splice(at, 1);
170
+ };
171
+ },
172
+ unref() {
173
+ unrefed = true;
174
+ },
175
+ kill(signal) {
176
+ killed.push(signal ?? 'SIGTERM');
177
+ queueMicrotask(() => finish(null, signal ?? 'SIGTERM'));
178
+ },
179
+ };
180
+ children.push(child);
181
+ if (reply.hang !== true) {
182
+ queueMicrotask(() => {
183
+ if (reply.error !== undefined) {
184
+ child.fail(reply.error);
185
+ return;
186
+ }
187
+ if (reply.stdout !== undefined) emitStdout(reply.stdout);
188
+ if (reply.stderr !== undefined) emitStderr(reply.stderr);
189
+ finish(reply.exitCode ?? 0, reply.signal ?? null);
190
+ });
191
+ }
192
+ return child;
193
+ },
194
+ };
195
+ return { host, calls, children };
196
+ }
197
+
198
+ function streamOf(listeners: Array<(chunk: string) => void>): ProcessStream {
199
+ return {
200
+ onData(listener) {
201
+ listeners.push(listener);
202
+ return () => {
203
+ const at = listeners.indexOf(listener);
204
+ if (at >= 0) listeners.splice(at, 1);
205
+ };
206
+ },
207
+ };
208
+ }
@@ -1,28 +0,0 @@
1
- import type { UnitClientFace } from '../components/board-module.js';
2
- /**
3
- * 浏览器面注册需要的那点上下文:`get` / `effect`。
4
- */
5
- export interface UnitClientContextLike {
6
- get<T = unknown>(name: string): T | undefined;
7
- effect(effect: () => void | (() => void), label?: string): () => void;
8
- }
9
- /**
10
- * 一个浏览器插件导出的两件:`inject` / `apply`。
11
- */
12
- export interface UnitClientPlugin {
13
- readonly inject: readonly string[];
14
- apply(ctx: UnitClientContextLike): void;
15
- }
16
- /**
17
- * 把「浏览器面注册进外壳」这段在每个模块里都一样的接线收成一份。
18
- * 把它直接当插件导出用:`export const { inject, apply } = defineUnitClientPlugin({ … })`。
19
- * @param options.unit 单元 id。
20
- * @param options.face 这个单元的浏览器面。
21
- * @param options.label 清理标签里用的名字;默认用 `unit`。
22
- * @returns `{ inject, apply }`;`apply` 里取 `workbenchUnits`、缺了就 warn 一声。
23
- */
24
- export declare function defineUnitClientPlugin(options: {
25
- readonly unit: string;
26
- readonly face: UnitClientFace;
27
- readonly label?: string | undefined;
28
- }): UnitClientPlugin;
@@ -1,23 +0,0 @@
1
- /**
2
- * 把「浏览器面注册进外壳」这段在每个模块里都一样的接线收成一份。
3
- * 把它直接当插件导出用:`export const { inject, apply } = defineUnitClientPlugin({ … })`。
4
- * @param options.unit 单元 id。
5
- * @param options.face 这个单元的浏览器面。
6
- * @param options.label 清理标签里用的名字;默认用 `unit`。
7
- * @returns `{ inject, apply }`;`apply` 里取 `workbenchUnits`、缺了就 warn 一声。
8
- */
9
- export function defineUnitClientPlugin(options) {
10
- const { unit, face } = options;
11
- const label = options.label ?? unit;
12
- return {
13
- inject: ['workbenchUnits'],
14
- apply(ctx) {
15
- const units = ctx.get('workbenchUnits');
16
- if (units === undefined) {
17
- console.warn(`[${unit}] 外壳没有提供 workbenchUnits 服务:这张卡片装不进来`);
18
- return;
19
- }
20
- ctx.effect(() => units.registerUnit(face), `${label}: 注册 ${unit}`);
21
- },
22
- };
23
- }