@dsh-workbench/shared 0.2.9 → 0.2.11

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 (89) hide show
  1. package/dist/api/dsh-client.d.ts +4 -1
  2. package/dist/components/Activity.css +1 -0
  3. package/dist/components/Card.css +4 -4
  4. package/dist/components/CardAnchor.d.ts +7 -0
  5. package/dist/components/CardAnchor.js +8 -0
  6. package/dist/components/CardAnchor.module.css +3 -0
  7. package/dist/components/CardHead.css +1 -5
  8. package/dist/components/ChoiceGroup.css +11 -2
  9. package/dist/components/Field.css +4 -0
  10. package/dist/components/MockStrip.css +6 -0
  11. package/dist/components/Note.css +4 -4
  12. package/dist/components/SelectField.css +156 -0
  13. package/dist/components/SelectField.d.ts +57 -0
  14. package/dist/components/SelectField.js +236 -0
  15. package/dist/components/SettingsSection.css +2 -2
  16. package/dist/components/StateDot.d.ts +5 -0
  17. package/dist/components/StateDot.js +10 -0
  18. package/dist/components/TextField.css +5 -0
  19. package/dist/components/icons.d.ts +1 -0
  20. package/dist/components/icons.js +13 -0
  21. package/dist/host/__tests__/fakes.d.ts +41 -0
  22. package/dist/host/__tests__/fakes.js +76 -0
  23. package/dist/host/__tests__/preflight-fixtures.d.ts +19 -0
  24. package/dist/host/__tests__/preflight-fixtures.js +47 -0
  25. package/dist/host/context-inject.d.ts +24 -0
  26. package/dist/host/context-inject.js +74 -0
  27. package/dist/host/events.d.ts +9 -0
  28. package/dist/host/events.js +70 -0
  29. package/dist/host/mount-units.d.ts +52 -0
  30. package/dist/host/mount-units.js +186 -0
  31. package/dist/host/preflight.d.ts +58 -0
  32. package/dist/host/preflight.js +233 -0
  33. package/dist/host/probe-cache.d.ts +6 -0
  34. package/dist/host/probe-cache.js +19 -0
  35. package/dist/host/probe-libs.d.ts +45 -0
  36. package/dist/host/probe-libs.js +61 -0
  37. package/dist/host/probe-units.d.ts +17 -0
  38. package/dist/host/probe-units.js +102 -0
  39. package/dist/host/probe-verdict.d.ts +7 -0
  40. package/dist/host/probe-verdict.js +143 -0
  41. package/dist/host/tool-approval.d.ts +3 -1
  42. package/dist/host/tool-approval.js +3 -3
  43. package/dist/host/tool-kit.js +2 -2
  44. package/dist/host/tool-scope.d.ts +32 -0
  45. package/dist/host/tool-scope.js +84 -0
  46. package/dist/host/unit-readiness.d.ts +7 -0
  47. package/dist/host/unit-readiness.js +5 -0
  48. package/dist/host/unit-registry.d.ts +9 -0
  49. package/dist/host/unit-registry.js +33 -0
  50. package/dist/host/version-range.d.ts +2 -0
  51. package/dist/host/version-range.js +73 -0
  52. package/dist/host.d.ts +1 -0
  53. package/dist/host.js +1 -0
  54. package/dist/i18n/en.js +1 -1
  55. package/dist/i18n/index.d.ts +1 -1
  56. package/dist/i18n/zh.d.ts +1 -1
  57. package/dist/i18n/zh.js +1 -1
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.js +2 -0
  60. package/dist/lib/react.d.ts +2 -0
  61. package/dist/lib/react.js +2 -0
  62. package/package.json +1 -1
  63. package/src/api/dsh-client.ts +5 -1
  64. package/src/components/Activity.css +1 -0
  65. package/src/components/Card.css +4 -4
  66. package/src/components/Card.test.tsx +46 -0
  67. package/src/components/CardAnchor.module.css +3 -0
  68. package/src/components/CardAnchor.test.tsx +36 -0
  69. package/src/components/CardAnchor.tsx +20 -0
  70. package/src/components/CardHead.css +1 -5
  71. package/src/components/ChoiceGroup.css +11 -2
  72. package/src/components/Field.css +4 -0
  73. package/src/components/MockStrip.css +6 -0
  74. package/src/components/Note.css +4 -4
  75. package/src/components/SelectField.css +156 -0
  76. package/src/components/SelectField.test.tsx +238 -0
  77. package/src/components/SelectField.tsx +486 -0
  78. package/src/components/SettingsSection.css +2 -2
  79. package/src/components/TextField.css +5 -0
  80. package/src/components/icons.tsx +19 -0
  81. package/src/host/tool-approval.ts +4 -3
  82. package/src/host/tool-kit.ts +2 -2
  83. package/src/host.ts +1 -0
  84. package/src/i18n/en.ts +1 -1
  85. package/src/i18n/zh.ts +1 -1
  86. package/src/index.ts +2 -0
  87. package/src/lib/react.ts +3 -0
  88. package/dist/lib/lint-probe.d.ts +0 -1
  89. package/dist/lib/lint-probe.js +0 -6
@@ -0,0 +1,143 @@
1
+ import { resolvePluginSource } from "./plugin-source";
2
+ import { isNewerVersion } from "./release";
3
+ export function evaluateUnit(list, unit, failure, command = "opencli", releases = new Map(), libs = []) {
4
+ const isPlugin = (item) => typeof item === "object" && item !== null;
5
+ const needs = unit.plugins ?? [];
6
+ const required = needs.flatMap((need) => need.commands ?? []);
7
+ const primary = needs[0]?.name;
8
+ if (failure !== undefined || list === undefined) {
9
+ return {
10
+ unit: unit.unit,
11
+ ...(primary === undefined ? {} : { plugin: primary }),
12
+ status: "unchecked",
13
+ required,
14
+ missing: [],
15
+ detail: failure ?? "探不动",
16
+ ...(libs.length === 0 ? {} : { libs }),
17
+ };
18
+ }
19
+ const plugins = list.filter(isPlugin);
20
+ const installed = new Map(plugins.map((item) => [String(item.name), item]));
21
+ const states = needs.map((need) => {
22
+ const hit = installed.get(need.name);
23
+ if (hit === undefined) {
24
+ const source = resolvePluginSource(need.installSource, process.env, {
25
+ command,
26
+ plugin: need.name,
27
+ });
28
+ return {
29
+ name: need.name,
30
+ status: "missing",
31
+ missing: [],
32
+ install: source.ok ? "ready" : source.problem,
33
+ command: source.ok ? source.line : pluginInstallCommand(need.name),
34
+ };
35
+ }
36
+ const available = new Set((Array.isArray(hit.commands) ? hit.commands : []).map(String));
37
+ const missing = (need.commands ?? []).filter((name) => !available.has(name));
38
+ const release = releases.get(need.name);
39
+ const behind = release?.latest !== undefined &&
40
+ isNewerVersion(release.latest, release.installed);
41
+ const commandsBehind = missing.length > 0;
42
+ const upgrade = behind && release?.latest !== undefined
43
+ ? upgradeLine(need, command, release.latest)
44
+ : undefined;
45
+ return {
46
+ name: need.name,
47
+ status: commandsBehind || behind ? "outdated" : "ok",
48
+ missing,
49
+ ...(release === undefined ? {} : { release }),
50
+ ...(commandsBehind || behind
51
+ ? {
52
+ command: upgrade ??
53
+ pluginUpdateCommand(need.name) ??
54
+ pluginInstallCommand(need.name),
55
+ }
56
+ : {}),
57
+ };
58
+ });
59
+ const absent = states.filter((state) => state.status === "missing");
60
+ const outdated = states.filter((state) => state.status === "outdated");
61
+ const missing = states.flatMap((state) => state.missing);
62
+ const libMissing = libs.filter((state) => state.status === "missing");
63
+ const libMismatch = libs.filter((state) => state.status === "unsatisfied");
64
+ const libBehind = libs.filter((state) => state.status === "outdated");
65
+ const status = absent.length > 0 || libMissing.length > 0 || libMismatch.length > 0
66
+ ? "missing-plugin"
67
+ : missing.length > 0
68
+ ? "missing-commands"
69
+ : "ok";
70
+ const blocked = absent.find((state) => state.install !== "ready");
71
+ const install = absent.length === 0
72
+ ?
73
+ libMissing.length > 0 || libMismatch.length > 0
74
+ ? "ready"
75
+ : undefined
76
+ : blocked === undefined
77
+ ? "ready"
78
+ : blocked.install;
79
+ const fix = status === "missing-plugin"
80
+ ? install === "ready"
81
+ ? "install"
82
+ : undefined
83
+ : outdated.length > 0 || libBehind.length > 0
84
+ ? "update"
85
+ : undefined;
86
+ const first = absent[0] ?? outdated[0] ?? libMissing[0] ?? libMismatch[0] ?? libBehind[0];
87
+ const gaps = [...(missing.length === 0 ? [] : [`缺必需:${missing.join("、")}`])];
88
+ const newer = states.filter((state) => state.release?.latest !== undefined &&
89
+ isNewerVersion(state.release.latest, state.release.installed));
90
+ const versionText = newer.length === 0
91
+ ? ""
92
+ : `(源上有新版:${newer.map((state) => `${state.release?.installed ?? ""} → ${state.release?.latest ?? ""}`).join("、")})`;
93
+ const absentNames = [
94
+ ...absent.map((state) => state.name),
95
+ ...libMissing.map((state) => state.name),
96
+ ];
97
+ const mismatchText = libMismatch.map((state) => {
98
+ const declared = unit.libs?.find((need) => need.name === state.name)?.version?.trim();
99
+ return `${state.name}(装的是 ${state.installed ?? "未知"},声明要 ${declared === undefined || declared === "" ? "任意版本" : declared})`;
100
+ });
101
+ return {
102
+ unit: unit.unit,
103
+ ...(primary === undefined ? {} : { plugin: primary }),
104
+ status,
105
+ required,
106
+ missing,
107
+ detail: absentNames.length > 0 || mismatchText.length > 0
108
+ ? [
109
+ ...(absentNames.length === 0
110
+ ? []
111
+ : [`${plugins.length} 个已装插件里没有 ${absentNames.join("、")}`]),
112
+ ...mismatchText,
113
+ ].join(";")
114
+ : `${needs.length} 份安装都在${gapsText(gaps)}${versionText}${libs.length === 0
115
+ ? ""
116
+ : `;交叉依赖:${libs.map((state) => `${state.name}${state.installed === undefined ? " 未装" : ` ${state.installed}`}`).join("、")}${libBehind.length === 0 ? "" : "(源上有新版)"}`}`,
117
+ ...(fix === undefined && first === undefined
118
+ ? {}
119
+ : { command: fix === "install" ? (absent[0] ?? first)?.command : first?.command }),
120
+ ...(fix === undefined ? {} : { fix }),
121
+ ...(install === undefined ? {} : { install }),
122
+ plugins: states,
123
+ ...(libs.length === 0 ? {} : { libs }),
124
+ };
125
+ }
126
+ export function gapsText(gaps) {
127
+ return gaps.length === 0 ? "" : `(${gaps.join(";")})`;
128
+ }
129
+ export function pluginUpdateCommand(plugin) {
130
+ return plugin === undefined ? undefined : `opencli plugin update ${plugin}`;
131
+ }
132
+ export function pluginInstallCommand(plugin) {
133
+ return `opencli plugin install <${plugin ?? "插件"}源>`;
134
+ }
135
+ export function upgradeLine(need, command, latest) {
136
+ const source = resolvePluginSource(need.installSource, process.env, {
137
+ command,
138
+ plugin: need.name,
139
+ version: latest,
140
+ mode: "update",
141
+ });
142
+ return source.ok ? source.line : undefined;
143
+ }
@@ -17,7 +17,7 @@ export type ApprovalFacts = ApprovalDetail | {
17
17
  readonly blocked: string;
18
18
  };
19
19
  export declare const APPROVAL_NOTE_ARG = "approval_note";
20
- export declare const APPROVAL_NOTE_LIMIT = 160;
20
+ export declare const APPROVAL_NOTE_LIMIT = 40;
21
21
  export declare function withApprovalNote(parameters: Record<string, unknown>, options?: {
22
22
  readonly required?: boolean | undefined;
23
23
  }): Record<string, unknown>;
@@ -28,6 +28,8 @@ export interface ApprovalCall {
28
28
  }
29
29
  export type ApprovalVerdict = {
30
30
  readonly kind: 'read';
31
+ } | {
32
+ readonly kind: 'allow';
31
33
  } | {
32
34
  readonly kind: 'ask';
33
35
  readonly reason: string;
@@ -1,8 +1,8 @@
1
1
  export const APPROVAL_NOTE_ARG = 'approval_note';
2
- export const APPROVAL_NOTE_LIMIT = 160;
2
+ export const APPROVAL_NOTE_LIMIT = 40;
3
3
  const NOTE_SCHEMA = {
4
4
  type: 'string',
5
- description: '一句话说明你这次想拿它干什么(要点头的那几通会显示在审批屏上)。',
5
+ description: '一句话说明你这次想拿它干什么(要点头时显示在审批屏上;40 字以内)。',
6
6
  };
7
7
  export function withApprovalNote(parameters, options = {}) {
8
8
  const properties = parameters['properties'];
@@ -57,7 +57,7 @@ export async function approvalFor(call, context = {}) {
57
57
  reason: `问"要不要审批"的时候套件的策略抛了错,已经停下:${messageOf(error)}`,
58
58
  };
59
59
  }
60
- if (verdict?.kind === 'read')
60
+ if (verdict?.kind === 'read' || verdict?.kind === 'allow')
61
61
  return undefined;
62
62
  if (verdict?.kind !== 'ask') {
63
63
  return {
@@ -24,10 +24,10 @@ export function commandHintFor(names) {
24
24
  if (!(error instanceof WorkbenchDataError) || error.code !== UNCLASSIFIED)
25
25
  throw error;
26
26
  const advice = `这条命令(${command})在这份 ${names.plugin} 插件里可能不存在(插件版本旧就会缺):` +
27
- `用 workbench_modules(action=update, id=${names.suiteId})升级插件,或在面板的模块状态里点更新,再重试。`;
27
+ `用 workbench_modules_update(id=${names.suiteId})升级插件,或在面板的模块状态里点更新,再重试。`;
28
28
  throw new WorkbenchDataError(error.code, `${error.message}。${advice}`, {
29
29
  ...(error.detail === undefined ? {} : { detail: error.detail }),
30
- hint: `升级:workbench_modules(action=update, id=${names.suiteId})。` +
30
+ hint: `升级:workbench_modules_update(id=${names.suiteId})。` +
31
31
  `终端确认:opencli ${names.plugin} ${command} --help${error.hint === undefined ? '' : `\n${error.hint}`}`,
32
32
  ...(error.helpUrl === undefined ? {} : { helpUrl: error.helpUrl }),
33
33
  ...(error.project === undefined ? {} : { project: error.project }),
@@ -0,0 +1,32 @@
1
+ import type { DshPromptAssembly } from '@dsh-workbench/shared';
2
+ export interface ScopedToolRegistry {
3
+ restrict(filter: {
4
+ readonly allow?: readonly string[];
5
+ readonly deny?: readonly string[];
6
+ }): () => void;
7
+ }
8
+ export interface ToolScopeAgent {
9
+ readonly ctx?: {
10
+ readonly tools?: ScopedToolRegistry | undefined;
11
+ get?<T = unknown>(name: string): T | undefined;
12
+ } | undefined;
13
+ readonly session?: {
14
+ readonly header?: {
15
+ readonly cwd?: string;
16
+ } | undefined;
17
+ } | undefined;
18
+ }
19
+ export interface ToolScopeOptions {
20
+ deniedTools(workspace: string | null): readonly string[];
21
+ logger?: {
22
+ info?(message: string): void;
23
+ warn?(message: string): void;
24
+ } | undefined;
25
+ }
26
+ export interface ToolScope {
27
+ apply(agent: unknown): void;
28
+ narrow(assembly: DshPromptAssembly, agent: unknown): DshPromptAssembly;
29
+ reapply(): void;
30
+ disposeAll(): void;
31
+ }
32
+ export declare function createToolScope(options: ToolScopeOptions): ToolScope;
@@ -0,0 +1,84 @@
1
+ function agentOf(value) {
2
+ return typeof value === 'object' && value !== null ? value : undefined;
3
+ }
4
+ function workspaceOf(handle) {
5
+ const cwd = handle.session?.header?.cwd;
6
+ return typeof cwd === 'string' && cwd !== '' ? cwd : null;
7
+ }
8
+ export function createToolScope(options) {
9
+ const applied = new WeakMap();
10
+ const seen = new Set();
11
+ function toolsOf(handle) {
12
+ const byProperty = handle.ctx?.tools;
13
+ if (byProperty?.restrict !== undefined)
14
+ return byProperty;
15
+ const byGet = handle.ctx?.get?.('tools');
16
+ return byGet?.restrict === undefined ? undefined : byGet;
17
+ }
18
+ function sync(handle) {
19
+ const tools = toolsOf(handle);
20
+ if (tools === undefined) {
21
+ options.logger?.warn?.('[dsh-workbench] 拿不到 agent 作用域的工具面:这次不收窄(下次再试)');
22
+ return;
23
+ }
24
+ const workspace = workspaceOf(handle);
25
+ const deny = [...options.deniedTools(workspace)];
26
+ const signature = `${workspace ?? ''}\u0000${deny.join(',')}`;
27
+ const previous = applied.get(handle);
28
+ if (previous !== undefined && previous.signature === signature)
29
+ return;
30
+ if (previous === undefined)
31
+ seen.add(new WeakRef(handle));
32
+ previous?.dispose();
33
+ if (deny.length === 0) {
34
+ options.logger?.info?.('[dsh-workbench] 这个工作区启用了全部套件:不收窄工具面');
35
+ applied.delete(handle);
36
+ return;
37
+ }
38
+ try {
39
+ applied.set(handle, { signature, dispose: tools.restrict({ deny }) });
40
+ options.logger?.info?.(`[dsh-workbench] 按工作区收窄工具面:${workspace ?? '(未知工作区)'} 里收起 ${deny.length} 个工具(${deny.join(', ')})`);
41
+ }
42
+ catch (error) {
43
+ options.logger?.warn?.(`[dsh-workbench] 收窄工具面失败:${String(error)}`);
44
+ }
45
+ }
46
+ return {
47
+ apply(agent) {
48
+ const handle = agentOf(agent);
49
+ if (handle === undefined)
50
+ return;
51
+ sync(handle);
52
+ },
53
+ narrow(assembly, agent) {
54
+ const handle = agentOf(agent);
55
+ const tools = assembly?.tools;
56
+ if (handle === undefined || tools === undefined)
57
+ return assembly;
58
+ const deny = new Set(options.deniedTools(workspaceOf(handle)));
59
+ if (deny.size === 0)
60
+ return assembly;
61
+ const kept = tools.filter((tool) => !deny.has(tool.name));
62
+ return kept.length === tools.length ? assembly : { ...assembly, tools: kept };
63
+ },
64
+ reapply() {
65
+ for (const ref of [...seen]) {
66
+ const handle = ref.deref();
67
+ if (handle === undefined)
68
+ seen.delete(ref);
69
+ else
70
+ sync(handle);
71
+ }
72
+ },
73
+ disposeAll() {
74
+ for (const ref of [...seen]) {
75
+ const handle = ref.deref();
76
+ if (handle === undefined)
77
+ continue;
78
+ applied.get(handle)?.dispose();
79
+ applied.delete(handle);
80
+ }
81
+ seen.clear();
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,7 @@
1
+ import type { UnitManifest } from '@dsh-workbench/shared';
2
+ export interface UnitReadiness {
3
+ readonly canMount: boolean;
4
+ readonly missingHard: readonly string[];
5
+ readonly missingSoft: readonly string[];
6
+ }
7
+ export declare function unitReadiness(manifest: UnitManifest, lookup: (name: string) => unknown): UnitReadiness;
@@ -0,0 +1,5 @@
1
+ export function unitReadiness(manifest, lookup) {
2
+ const missingHard = manifest.host.inject.filter((name) => lookup(name) === undefined);
3
+ const missingSoft = (manifest.host.optional ?? []).filter((name) => lookup(name) === undefined);
4
+ return { canMount: missingHard.length === 0, missingHard, missingSoft };
5
+ }
@@ -0,0 +1,9 @@
1
+ import type { UnitManifest } from '@dsh-workbench/shared';
2
+ import type { UnitHostFace } from './unit-face';
3
+ export interface UnitRegistry {
4
+ register(face: UnitHostFace): () => void;
5
+ all(): readonly UnitHostFace[];
6
+ manifests(): readonly UnitManifest[];
7
+ subscribe(listener: () => void): () => void;
8
+ }
9
+ export declare function createUnitRegistry(): UnitRegistry;
@@ -0,0 +1,33 @@
1
+ export function createUnitRegistry() {
2
+ const faces = [];
3
+ const ids = new Set();
4
+ const listeners = new Set();
5
+ function notify() {
6
+ for (const listener of listeners)
7
+ listener();
8
+ }
9
+ return {
10
+ register(face) {
11
+ const id = face.manifest.id;
12
+ if (ids.has(id))
13
+ throw new Error(`套件 id 重复:${id}(id 会进持久化配置,不能撞)`);
14
+ ids.add(id);
15
+ faces.push(face);
16
+ notify();
17
+ return () => {
18
+ const index = faces.indexOf(face);
19
+ if (index < 0)
20
+ return;
21
+ faces.splice(index, 1);
22
+ ids.delete(id);
23
+ notify();
24
+ };
25
+ },
26
+ all: () => faces,
27
+ manifests: () => faces.map((face) => face.manifest),
28
+ subscribe(listener) {
29
+ listeners.add(listener);
30
+ return () => listeners.delete(listener);
31
+ },
32
+ };
33
+ }
@@ -0,0 +1,2 @@
1
+ export type VersionVerdict = 'satisfied' | 'unsatisfied' | 'malformed';
2
+ export declare function checkVersionRange(contract: string | undefined, version: string): VersionVerdict;
@@ -0,0 +1,73 @@
1
+ import { compareVersions } from './release';
2
+ function readable(version) {
3
+ return compareVersions(version, '0.0.0') !== undefined;
4
+ }
5
+ function segmentsOf(version) {
6
+ if (!readable(version))
7
+ return undefined;
8
+ return version.split('.').map((part) => Number.parseInt(part, 10));
9
+ }
10
+ function caretUpper(base) {
11
+ const [major = 0, minor = 0, patch = 0] = base;
12
+ if (major > 0)
13
+ return `${major + 1}.0.0`;
14
+ return minor > 0 ? `0.${minor + 1}.0` : `0.0.${patch + 1}`;
15
+ }
16
+ function tildeUpper(base) {
17
+ const [major = 0, minor = 0] = base;
18
+ return `${major}.${minor + 1}.0`;
19
+ }
20
+ function comparator(token, version) {
21
+ const match = /^(>=|<=|>|<|=|\^|~)?\s*(.+)$/.exec(token.trim());
22
+ if (match === null)
23
+ return undefined;
24
+ const [, operator = '', raw = ''] = match;
25
+ const base = segmentsOf(raw.trim());
26
+ if (base === undefined)
27
+ return undefined;
28
+ const at = (other) => compareVersions(version, other);
29
+ switch (operator) {
30
+ case '^':
31
+ return (at(raw) ?? -1) >= 0 && (at(caretUpper(base)) ?? 1) < 0;
32
+ case '~':
33
+ return (at(raw) ?? -1) >= 0 && (at(tildeUpper(base)) ?? 1) < 0;
34
+ default:
35
+ break;
36
+ }
37
+ const compared = at(raw.trim());
38
+ if (compared === undefined)
39
+ return undefined;
40
+ switch (operator) {
41
+ case '>=':
42
+ return compared >= 0;
43
+ case '<=':
44
+ return compared <= 0;
45
+ case '>':
46
+ return compared > 0;
47
+ case '<':
48
+ return compared < 0;
49
+ case '=':
50
+ case '':
51
+ return compared === 0;
52
+ default:
53
+ return undefined;
54
+ }
55
+ }
56
+ export function checkVersionRange(contract, version) {
57
+ const spec = contract?.trim() ?? '';
58
+ if (spec === '')
59
+ return 'satisfied';
60
+ if (!readable(version))
61
+ return 'malformed';
62
+ const tokens = spec.split(/\s+/).filter((token) => token !== '');
63
+ if (tokens.length === 0)
64
+ return 'satisfied';
65
+ for (const token of tokens) {
66
+ const verdict = comparator(token, version);
67
+ if (verdict === undefined)
68
+ return 'malformed';
69
+ if (!verdict)
70
+ return 'unsatisfied';
71
+ }
72
+ return 'satisfied';
73
+ }
package/dist/host.d.ts CHANGED
@@ -18,6 +18,7 @@ export * from './host/http.js';
18
18
  export * from './host/long-task.js';
19
19
  export * from './host/opencli-runtime.js';
20
20
  export * from './host/opencli.js';
21
+ export * from './host/opencli-window.js';
21
22
  export * from './host/plugin-ledger.js';
22
23
  export * from './host/plugin-source.js';
23
24
  export * from './host/provision.js';
package/dist/host.js CHANGED
@@ -18,6 +18,7 @@ export * from './host/http.js';
18
18
  export * from './host/long-task.js';
19
19
  export * from './host/opencli-runtime.js';
20
20
  export * from './host/opencli.js';
21
+ export * from './host/opencli-window.js';
21
22
  export * from './host/plugin-ledger.js';
22
23
  export * from './host/plugin-source.js';
23
24
  export * from './host/provision.js';
package/dist/i18n/en.js CHANGED
@@ -137,7 +137,7 @@ export const en = {
137
137
  'panels.market.pluginKeptUnsure': 'Files kept for now: some modules on this machine do not say what they use, so it is unclear who needs it.',
138
138
  'panels.market.pluginKeptHeld': 'Files kept: this one is yours, and a module letting go will not remove it.',
139
139
  'panels.market.pluginKeptUnnamed': 'Files kept for now: this one cannot be identified as a plugin, so it is unclear who needs it.',
140
- 'panels.market.pluginBroken': 'This install is broken: it cannot be identified as a plugin. Uninstall it, or tell the agent to reinstall it by package name with workbench_modules (the install-bundle action).',
140
+ 'panels.market.pluginBroken': 'This install is broken: it cannot be identified as a plugin. Uninstall it, or tell the agent to reinstall it by package name with workbench_modules_install_bundle.',
141
141
  'panels.market.restartNeeded': 'The new version is installed — restart once to pick it up.',
142
142
  'panels.market.foot': 'After installing, enable it in the panel page of that project.',
143
143
  'panels.market.recheck': 'Check for updates',
@@ -139,7 +139,7 @@ export declare const dictionaries: {
139
139
  readonly 'panels.market.pluginKeptUnsure': "文件先留着:这台机器上还有模块看不出用了什么,说不准谁在用它。";
140
140
  readonly 'panels.market.pluginKeptHeld': "文件留着:你自己装的那一份,模块放手不动它。";
141
141
  readonly 'panels.market.pluginKeptUnnamed': "文件先留着:看不出这是哪个插件,说不准谁在用它。";
142
- readonly 'panels.market.pluginBroken': "这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules 的 install-bundle 按包名再装一次。";
142
+ readonly 'panels.market.pluginBroken': "这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules_install_bundle 按包名再装一次。";
143
143
  readonly 'panels.market.restartNeeded': "新版装好了,重启一次才生效。";
144
144
  readonly 'panels.market.foot': "装好后到那个项目的面板页勾选它,模块才会出现。";
145
145
  readonly 'panels.market.recheck': "重新检查更新";
package/dist/i18n/zh.d.ts CHANGED
@@ -137,7 +137,7 @@ export declare const zh: {
137
137
  readonly 'panels.market.pluginKeptUnsure': "文件先留着:这台机器上还有模块看不出用了什么,说不准谁在用它。";
138
138
  readonly 'panels.market.pluginKeptHeld': "文件留着:你自己装的那一份,模块放手不动它。";
139
139
  readonly 'panels.market.pluginKeptUnnamed': "文件先留着:看不出这是哪个插件,说不准谁在用它。";
140
- readonly 'panels.market.pluginBroken': "这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules 的 install-bundle 按包名再装一次。";
140
+ readonly 'panels.market.pluginBroken': "这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules_install_bundle 按包名再装一次。";
141
141
  readonly 'panels.market.restartNeeded': "新版装好了,重启一次才生效。";
142
142
  readonly 'panels.market.foot': "装好后到那个项目的面板页勾选它,模块才会出现。";
143
143
  readonly 'panels.market.recheck': "重新检查更新";
package/dist/i18n/zh.js CHANGED
@@ -137,7 +137,7 @@ export const zh = {
137
137
  'panels.market.pluginKeptUnsure': '文件先留着:这台机器上还有模块看不出用了什么,说不准谁在用它。',
138
138
  'panels.market.pluginKeptHeld': '文件留着:你自己装的那一份,模块放手不动它。',
139
139
  'panels.market.pluginKeptUnnamed': '文件先留着:看不出这是哪个插件,说不准谁在用它。',
140
- 'panels.market.pluginBroken': '这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules 的 install-bundle 按包名再装一次。',
140
+ 'panels.market.pluginBroken': '这份装坏了:看不出它是个插件。可以卸载,或者直接跟 agent 说:用 workbench_modules_install_bundle 按包名再装一次。',
141
141
  'panels.market.restartNeeded': '新版装好了,重启一次才生效。',
142
142
  'panels.market.foot': '装好后到那个项目的面板页勾选它,模块才会出现。',
143
143
  'panels.market.recheck': '重新检查更新',
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export * from './components/Activity.js';
15
15
  export * from './components/ApprovalDetail.js';
16
16
  export * from './components/ApprovalPlan.js';
17
17
  export * from './components/Card.js';
18
+ export * from './components/CardAnchor.js';
18
19
  export * from './components/CardBoundary.js';
19
20
  export * from './components/CardHead.js';
20
21
  export * from './components/ChoiceGroup.js';
@@ -25,6 +26,7 @@ export * from './components/ResourceStates.js';
25
26
  export * from './components/Rows.js';
26
27
  export * from './components/SaveBar.js';
27
28
  export * from './components/SettingsSection.js';
29
+ export * from './components/SelectField.js';
28
30
  export * from './components/Stack.js';
29
31
  export * from './components/StateBlock.js';
30
32
  export * from './components/TextField.js';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ export * from './components/Activity.js';
15
15
  export * from './components/ApprovalDetail.js';
16
16
  export * from './components/ApprovalPlan.js';
17
17
  export * from './components/Card.js';
18
+ export * from './components/CardAnchor.js';
18
19
  export * from './components/CardBoundary.js';
19
20
  export * from './components/CardHead.js';
20
21
  export * from './components/ChoiceGroup.js';
@@ -25,6 +26,7 @@ export * from './components/ResourceStates.js';
25
26
  export * from './components/Rows.js';
26
27
  export * from './components/SaveBar.js';
27
28
  export * from './components/SettingsSection.js';
29
+ export * from './components/SelectField.js';
28
30
  export * from './components/Stack.js';
29
31
  export * from './components/StateBlock.js';
30
32
  export * from './components/TextField.js';
@@ -2,6 +2,8 @@ import type * as ReactTypes from 'react';
2
2
  export declare const h: typeof ReactTypes.createElement;
3
3
  export declare const Fragment: ReactTypes.ExoticComponent<ReactTypes.FragmentProps>;
4
4
  export declare const Component: typeof ReactTypes.Component;
5
+ export declare const createContext: typeof ReactTypes.createContext;
6
+ export declare const useContext: typeof ReactTypes.useContext;
5
7
  export declare const useState: typeof ReactTypes.useState;
6
8
  export declare const useEffect: typeof ReactTypes.useEffect;
7
9
  export declare const useLayoutEffect: typeof ReactTypes.useLayoutEffect;
package/dist/lib/react.js CHANGED
@@ -2,6 +2,8 @@ const react = require('react');
2
2
  export const h = react.createElement;
3
3
  export const Fragment = react.Fragment;
4
4
  export const Component = react.Component;
5
+ export const createContext = react.createContext;
6
+ export const useContext = react.useContext;
5
7
  export const useState = react.useState;
6
8
  export const useEffect = react.useEffect;
7
9
  export const useLayoutEffect = react.useLayoutEffect;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/shared",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -106,10 +106,14 @@ export interface DshShortcutCatalog {
106
106
  readonly catalog: unknown;
107
107
  }
108
108
 
109
+ export interface DshSessionStartOptions {
110
+ readonly agentPreset?: string;
111
+ }
112
+
109
113
  export interface DshUiWorkspace {
110
114
  openWorkspace(workspaceId: string): Promise<unknown>;
111
115
  openSession(sessionId: string): void;
112
- startSession(workspaceId: string): void;
116
+ startSession(workspaceId: string, options?: DshSessionStartOptions): void;
113
117
  pickDirectory(): Promise<string | null>;
114
118
  }
115
119
 
@@ -8,6 +8,7 @@
8
8
  }
9
9
 
10
10
  .wb-activityBlock:first-child {
11
+ padding-top: 0;
11
12
  border-top: none;
12
13
  }
13
14
 
@@ -12,9 +12,9 @@
12
12
  display: flex;
13
13
  flex-direction: column;
14
14
  gap: var(--wb-len-12);
15
- padding: var(--wb-len-12);
15
+ padding: var(--wb-len-12) var(--wb-card-gutter);
16
+ font-size: var(--dsw-font-xxs-12-font-size);
16
17
  }
17
- .wb-cardBody > :not([data-wb-bleed]) {
18
- padding-left: var(--wb-len-8);
19
- padding-right: var(--wb-len-8);
18
+ .wb-cardBleed {
19
+ margin-inline: calc(-1 * var(--wb-card-gutter));
20
20
  }