@dsh-workbench/shared 1.0.0-beta.0 → 1.0.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.
- package/dist/components/FormNodes.js +5 -1
- package/dist/components/FormRows.css +1 -0
- package/dist/components/FormRows.d.ts +4 -2
- package/dist/components/FormRows.js +5 -4
- package/dist/config/constants.d.ts +0 -2
- package/dist/config/constants.js +0 -5
- package/dist/contract/command.d.ts +22 -0
- package/dist/contract/command.js +1 -0
- package/dist/contract/data.d.ts +2 -1
- package/dist/contract/extension.d.ts +14 -0
- package/dist/contract/extension.js +1 -0
- package/dist/contract/git.d.ts +38 -0
- package/dist/contract/git.js +1 -0
- package/dist/contract/lib.d.ts +4 -0
- package/dist/contract/lib.js +1 -0
- package/dist/contract/protocol/config-sync.d.ts +1 -21
- package/dist/contract/protocol/market-index.d.ts +1 -0
- package/dist/contract/protocol/profile-create.d.ts +0 -3
- package/dist/host/adapter-set.js +1 -0
- package/dist/host/adapters.d.ts +6 -0
- package/dist/host/extension.d.ts +7 -0
- package/dist/host/extension.js +39 -0
- package/dist/host/git.d.ts +2 -52
- package/dist/host/git.js +1 -64
- package/dist/host/http.js +1 -1
- package/dist/host/market-index.js +3 -44
- package/dist/host/port-types.d.ts +1 -0
- package/dist/host/release-packages.generated.d.ts +1 -0
- package/dist/host/release-packages.generated.js +10 -0
- package/dist/host/tool-kit.d.ts +0 -6
- package/dist/host/tool-kit.js +0 -22
- package/dist/host/unit-face.d.ts +7 -0
- package/dist/host/version-range.js +7 -67
- package/dist/host/version.d.ts +3 -2
- package/dist/host/version.js +17 -19
- package/dist/host.d.ts +6 -0
- package/dist/host.js +6 -0
- package/dist/i18n/en.js +3 -1
- package/dist/i18n/index.d.ts +9 -21
- package/dist/i18n/settings.d.ts +5 -19
- package/dist/i18n/settings.js +7 -35
- package/dist/i18n/zh.d.ts +8 -20
- package/dist/i18n/zh.js +3 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/lib/version.d.ts +4 -0
- package/dist/lib/version.js +21 -0
- package/dist/testing/git.d.ts +3 -0
- package/dist/testing/git.js +36 -0
- package/package.json +6 -4
- package/src/components/Form.test.tsx +6 -0
- package/src/components/FormNodes.tsx +6 -1
- package/src/components/FormRows.css +1 -0
- package/src/components/FormRows.test.tsx +30 -0
- package/src/components/FormRows.tsx +9 -5
- package/src/config/constants.ts +0 -6
- package/src/contract/command.ts +25 -0
- package/src/contract/data.ts +2 -1
- package/src/contract/extension.ts +20 -0
- package/src/contract/git.ts +20 -0
- package/src/contract/lib.ts +5 -0
- package/src/contract/protocol/config-sync.ts +1 -24
- package/src/contract/protocol/market-index.ts +1 -0
- package/src/contract/protocol/profile-create.ts +0 -3
- package/src/host/adapter-set.ts +1 -0
- package/src/host/adapters.ts +6 -0
- package/src/host/extension.test.ts +55 -0
- package/src/host/extension.ts +57 -0
- package/src/host/git.ts +6 -92
- package/src/host/http.ts +1 -1
- package/src/host/market-index.ts +3 -33
- package/src/host/port-types.ts +1 -0
- package/src/host/release-packages.generated.ts +10 -0
- package/src/host/tool-kit.ts +0 -35
- package/src/host/unit-face.ts +7 -0
- package/src/host/version-range.ts +6 -64
- package/src/host/version.ts +18 -18
- package/src/host.ts +6 -0
- package/src/i18n/en.ts +3 -1
- package/src/i18n/settings.ts +7 -35
- package/src/i18n/zh.ts +3 -1
- package/src/index.ts +4 -0
package/dist/i18n/settings.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
/** 「工作台设置」这一组的词条:配置同步 / 新建工作台。 */
|
|
2
2
|
export const zhSettings = {
|
|
3
3
|
'profileCreate.nav': '新建工作台',
|
|
4
|
-
'profileCreate.lead': '以已有 profile
|
|
4
|
+
'profileCreate.lead': '以已有 profile 为模板,建一个独立的新工作台。会话 / 项目 / 附件跟 web 共用,这里只复制设置。建好后关掉当前实例,再启动新的。',
|
|
5
5
|
'profileCreate.name': '新工作台的名字',
|
|
6
6
|
'profileCreate.nameHint': '例如 wb2(只用字母、数字、点、下划线或短横线)',
|
|
7
7
|
'profileCreate.source': '来源 profile',
|
|
8
8
|
'profileCreate.current': '当前',
|
|
9
9
|
'profileCreate.copy': '从来源复制',
|
|
10
10
|
'profileCreate.settings': '设置(模型、主题等)',
|
|
11
|
-
'profileCreate.plugins': '本地插件文件',
|
|
12
|
-
'profileCreate.pluginsRequired': '设置里引用了,不能单独去掉',
|
|
13
|
-
'profileCreate.projects': '项目列表',
|
|
14
|
-
'profileCreate.sessions': '会话记录',
|
|
15
11
|
'profileCreate.create': '创建',
|
|
16
12
|
'profileCreate.creating': '正在创建…',
|
|
17
13
|
'profileCreate.created': '已建好 {profile}。',
|
|
@@ -22,25 +18,16 @@ export const zhSettings = {
|
|
|
22
18
|
'profileCreate.noProfiles': '这台机器上还没有可用的来源 profile。',
|
|
23
19
|
'profileCreate.failed': '创建没有成功,看看下面的输出。',
|
|
24
20
|
'configSync.nav': '配置同步',
|
|
25
|
-
'configSync.lead': '
|
|
21
|
+
'configSync.lead': '只同步「改已有插件的设置」的行;挂新插件的行不同步。会话 / 项目 / 附件本来就共用,不用同步。要整套新建工作台用「新建工作台」。',
|
|
26
22
|
'configSync.source': '来源',
|
|
27
23
|
'configSync.sourceBroken': '读不到它的配置',
|
|
28
|
-
'configSync.sourceRows': '{name} 这份里你有 {count}
|
|
24
|
+
'configSync.sourceRows': '{name} 这份里你有 {count} 行可同步',
|
|
29
25
|
'configSync.sourceDead': '读不到',
|
|
30
26
|
'configSync.refresh': '重新读一遍',
|
|
31
27
|
'configSync.loading': '正在读来源的配置…',
|
|
32
28
|
'configSync.readHint': '换个来源,或再读一遍。',
|
|
33
29
|
'configSync.tag.new': '新增',
|
|
34
30
|
'configSync.tag.differs': '差异',
|
|
35
|
-
'configSync.tag.asset': '缺文件',
|
|
36
|
-
'configSync.tag.fileDiffers': '文件不同',
|
|
37
|
-
'configSync.assetOnly': '设置内容一样,只差文件。',
|
|
38
|
-
'configSync.assetMissingOne': '还要 1 个文件:{path}',
|
|
39
|
-
'configSync.assetMissingMany': '还要 {count} 个文件:{path}',
|
|
40
|
-
'configSync.assetDiffers': '文件不一样:{path}',
|
|
41
|
-
'configSync.assetDiffersMany': '文件有差异:{path}({count} 个)',
|
|
42
|
-
'configSync.assetExternal': '这个文件搬不过来:{path}({reason})',
|
|
43
|
-
'configSync.assetOverwrite': '覆盖工作台里的同名文件',
|
|
44
31
|
'configSync.conflictNote': '应用后工作台这份会被来源覆盖',
|
|
45
32
|
'configSync.code.lang': 'yaml',
|
|
46
33
|
'configSync.code.copy': '复制',
|
|
@@ -51,35 +38,30 @@ export const zhSettings = {
|
|
|
51
38
|
'configSync.code.collapseAria': '收起这一行的配置',
|
|
52
39
|
'configSync.code.expandAria': '展开差异(还有 {count} 行)',
|
|
53
40
|
'configSync.code.expand': '展开剩余 {count} 行',
|
|
54
|
-
'configSync.missing': '{pkg}
|
|
41
|
+
'configSync.missing': '{pkg} 还没装:这一行同步过来也不会生效 —— 先在模块市场里装它',
|
|
55
42
|
'configSync.apply': '同步选中的 {count} 项',
|
|
56
43
|
'configSync.applyNone': '请选择同步内容',
|
|
57
44
|
'configSync.applying': '正在写入…',
|
|
58
45
|
'configSync.applied': '已写入并检查通过',
|
|
59
46
|
'configSync.appliedUnverified': '已写入;重启后检查是否生效',
|
|
60
|
-
'configSync.appliedFiles': '复制了 {count} 个文件',
|
|
61
47
|
'configSync.appliedIds': '这次写进去:{ids}',
|
|
62
48
|
'configSync.skippedIds': '这几行工作台自己已有,没动:{ids}',
|
|
63
49
|
'configSync.nothing': '没有需要同步的内容',
|
|
64
50
|
'configSync.unreadable': '读不到 {path}:{reason}',
|
|
65
51
|
'configSync.noSource': '这台机器上只有工作台这一个 profile,没有可同步的来源',
|
|
66
|
-
'configSync.emptyProviders': '工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile
|
|
52
|
+
'configSync.emptyProviders': '工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把模型供应商那几行同步过来,或自己去「模型」里配。',
|
|
67
53
|
'configSync.failed': '同步没成功,再试一次。',
|
|
68
54
|
};
|
|
69
55
|
/** 上面那组的中文对照。 */
|
|
70
56
|
export const enSettings = {
|
|
71
57
|
'profileCreate.nav': 'New workbench',
|
|
72
|
-
'profileCreate.lead': 'Create a separate workbench from an existing profile. Stop this instance, then start the new one.',
|
|
58
|
+
'profileCreate.lead': 'Create a separate workbench from an existing profile. Chats, projects and attachments are shared with web; only settings are copied. Stop this instance, then start the new one.',
|
|
73
59
|
'profileCreate.name': 'New workbench name',
|
|
74
60
|
'profileCreate.nameHint': 'e.g. wb2 (letters, digits, dot, underscore or dash)',
|
|
75
61
|
'profileCreate.source': 'Source profile',
|
|
76
62
|
'profileCreate.current': 'current',
|
|
77
63
|
'profileCreate.copy': 'Copy from the source',
|
|
78
64
|
'profileCreate.settings': 'Settings (models, theme, …)',
|
|
79
|
-
'profileCreate.plugins': 'Local plugin files',
|
|
80
|
-
'profileCreate.pluginsRequired': 'Referenced by settings; copied together',
|
|
81
|
-
'profileCreate.projects': 'Project list',
|
|
82
|
-
'profileCreate.sessions': 'Chat history',
|
|
83
65
|
'profileCreate.create': 'Create',
|
|
84
66
|
'profileCreate.creating': 'Creating…',
|
|
85
67
|
'profileCreate.created': 'Created {profile}.',
|
|
@@ -90,7 +72,7 @@ export const enSettings = {
|
|
|
90
72
|
'profileCreate.noProfiles': 'This machine has no source profile yet.',
|
|
91
73
|
'profileCreate.failed': 'The workbench was not created; see the output below.',
|
|
92
74
|
'configSync.nav': 'Config sync',
|
|
93
|
-
'configSync.lead': 'Only
|
|
75
|
+
'configSync.lead': 'Only rows that change settings of plugins the workbench already has are copied. Rows that mount a new plugin are not; chats, projects and attachments are shared already. Use “New workbench” to create a full profile.',
|
|
94
76
|
'configSync.source': 'Source',
|
|
95
77
|
'configSync.sourceBroken': 'its config is unreadable',
|
|
96
78
|
'configSync.sourceRows': '{name}: {count} rows are new or different for the workbench',
|
|
@@ -100,15 +82,6 @@ export const enSettings = {
|
|
|
100
82
|
'configSync.readHint': 'Pick another source, or read again.',
|
|
101
83
|
'configSync.tag.new': 'New',
|
|
102
84
|
'configSync.tag.differs': 'Differs',
|
|
103
|
-
'configSync.tag.asset': 'File missing',
|
|
104
|
-
'configSync.tag.fileDiffers': 'File differs',
|
|
105
|
-
'configSync.assetOnly': 'The setting is the same; only its file is missing.',
|
|
106
|
-
'configSync.assetMissingOne': '1 file is still needed: {path}',
|
|
107
|
-
'configSync.assetMissingMany': '{count} files are still needed: {path}',
|
|
108
|
-
'configSync.assetDiffers': 'The file differs: {path}',
|
|
109
|
-
'configSync.assetDiffersMany': 'The files differ: {path} ({count} files)',
|
|
110
|
-
'configSync.assetExternal': 'This file cannot be copied: {path} ({reason})',
|
|
111
|
-
'configSync.assetOverwrite': 'Overwrite the workbench copy',
|
|
112
85
|
'configSync.conflictNote': 'Applying replaces this workbench copy with the source',
|
|
113
86
|
'configSync.code.lang': 'yaml',
|
|
114
87
|
'configSync.code.copy': 'Copy',
|
|
@@ -125,7 +98,6 @@ export const enSettings = {
|
|
|
125
98
|
'configSync.applying': 'Writing…',
|
|
126
99
|
'configSync.applied': 'Written and checked',
|
|
127
100
|
'configSync.appliedUnverified': 'Written; restart to check whether it took effect',
|
|
128
|
-
'configSync.appliedFiles': 'Copied {count} files',
|
|
129
101
|
'configSync.appliedIds': 'Written this time: {ids}',
|
|
130
102
|
'configSync.skippedIds': 'Left alone (already here): {ids}',
|
|
131
103
|
'configSync.nothing': 'Nothing to sync',
|
package/dist/i18n/zh.d.ts
CHANGED
|
@@ -275,6 +275,7 @@ export declare const zh: {
|
|
|
275
275
|
readonly 'panels.discover.loading': "正在读取索引";
|
|
276
276
|
readonly 'panels.discover.lead': "从索引源浏览模块;装上就能用。";
|
|
277
277
|
readonly 'panels.discover.addSource': "添加";
|
|
278
|
+
readonly 'panels.discover.addingSource': "正在添加…";
|
|
278
279
|
readonly 'panels.discover.addFirstSource': "添加索引源";
|
|
279
280
|
readonly 'panels.discover.removeSource': "移除";
|
|
280
281
|
readonly 'panels.discover.removeSourceNamed': "移除 {url}";
|
|
@@ -375,7 +376,6 @@ export declare const zh: {
|
|
|
375
376
|
readonly 'panels.discover.tabOverview': "概览";
|
|
376
377
|
readonly 'panels.discover.tabReadme': "说明";
|
|
377
378
|
readonly 'panels.discover.tabChangelog': "更新日志";
|
|
378
|
-
readonly 'panels.discover.docTitle': "{version} 的{kind}";
|
|
379
379
|
readonly 'panels.discover.docReadme': "说明";
|
|
380
380
|
readonly 'panels.discover.docChangelog': "更新日志";
|
|
381
381
|
readonly 'panels.discover.docLoading': "正在读取…";
|
|
@@ -612,6 +612,8 @@ export declare const zh: {
|
|
|
612
612
|
readonly 'approval.publish.module': "模块";
|
|
613
613
|
readonly 'approval.publish.target': "目标";
|
|
614
614
|
readonly 'approval.publish.version': "版本";
|
|
615
|
+
readonly 'approval.publish.author': "作者";
|
|
616
|
+
readonly 'approval.publish.authorMissing': "未署名(提交用本机 git 身份)";
|
|
615
617
|
readonly 'approval.publish.registry': "源";
|
|
616
618
|
readonly 'approval.publish.repo': "仓库";
|
|
617
619
|
readonly 'approval.publish.branch': "分支";
|
|
@@ -634,17 +636,13 @@ export declare const zh: {
|
|
|
634
636
|
readonly 'markdown.copied': "已复制";
|
|
635
637
|
readonly 'markdown.footnotes': "脚注";
|
|
636
638
|
readonly 'profileCreate.nav': "新建工作台";
|
|
637
|
-
readonly 'profileCreate.lead': "以已有 profile
|
|
639
|
+
readonly 'profileCreate.lead': "以已有 profile 为模板,建一个独立的新工作台。会话 / 项目 / 附件跟 web 共用,这里只复制设置。建好后关掉当前实例,再启动新的。";
|
|
638
640
|
readonly 'profileCreate.name': "新工作台的名字";
|
|
639
641
|
readonly 'profileCreate.nameHint': "例如 wb2(只用字母、数字、点、下划线或短横线)";
|
|
640
642
|
readonly 'profileCreate.source': "来源 profile";
|
|
641
643
|
readonly 'profileCreate.current': "当前";
|
|
642
644
|
readonly 'profileCreate.copy': "从来源复制";
|
|
643
645
|
readonly 'profileCreate.settings': "设置(模型、主题等)";
|
|
644
|
-
readonly 'profileCreate.plugins': "本地插件文件";
|
|
645
|
-
readonly 'profileCreate.pluginsRequired': "设置里引用了,不能单独去掉";
|
|
646
|
-
readonly 'profileCreate.projects': "项目列表";
|
|
647
|
-
readonly 'profileCreate.sessions': "会话记录";
|
|
648
646
|
readonly 'profileCreate.create': "创建";
|
|
649
647
|
readonly 'profileCreate.creating': "正在创建…";
|
|
650
648
|
readonly 'profileCreate.created': "已建好 {profile}。";
|
|
@@ -655,25 +653,16 @@ export declare const zh: {
|
|
|
655
653
|
readonly 'profileCreate.noProfiles': "这台机器上还没有可用的来源 profile。";
|
|
656
654
|
readonly 'profileCreate.failed': "创建没有成功,看看下面的输出。";
|
|
657
655
|
readonly 'configSync.nav': "配置同步";
|
|
658
|
-
readonly 'configSync.lead': "
|
|
656
|
+
readonly 'configSync.lead': "只同步「改已有插件的设置」的行;挂新插件的行不同步。会话 / 项目 / 附件本来就共用,不用同步。要整套新建工作台用「新建工作台」。";
|
|
659
657
|
readonly 'configSync.source': "来源";
|
|
660
658
|
readonly 'configSync.sourceBroken': "读不到它的配置";
|
|
661
|
-
readonly 'configSync.sourceRows': "{name} 这份里你有 {count}
|
|
659
|
+
readonly 'configSync.sourceRows': "{name} 这份里你有 {count} 行可同步";
|
|
662
660
|
readonly 'configSync.sourceDead': "读不到";
|
|
663
661
|
readonly 'configSync.refresh': "重新读一遍";
|
|
664
662
|
readonly 'configSync.loading': "正在读来源的配置…";
|
|
665
663
|
readonly 'configSync.readHint': "换个来源,或再读一遍。";
|
|
666
664
|
readonly 'configSync.tag.new': "新增";
|
|
667
665
|
readonly 'configSync.tag.differs': "差异";
|
|
668
|
-
readonly 'configSync.tag.asset': "缺文件";
|
|
669
|
-
readonly 'configSync.tag.fileDiffers': "文件不同";
|
|
670
|
-
readonly 'configSync.assetOnly': "设置内容一样,只差文件。";
|
|
671
|
-
readonly 'configSync.assetMissingOne': "还要 1 个文件:{path}";
|
|
672
|
-
readonly 'configSync.assetMissingMany': "还要 {count} 个文件:{path}";
|
|
673
|
-
readonly 'configSync.assetDiffers': "文件不一样:{path}";
|
|
674
|
-
readonly 'configSync.assetDiffersMany': "文件有差异:{path}({count} 个)";
|
|
675
|
-
readonly 'configSync.assetExternal': "这个文件搬不过来:{path}({reason})";
|
|
676
|
-
readonly 'configSync.assetOverwrite': "覆盖工作台里的同名文件";
|
|
677
666
|
readonly 'configSync.conflictNote': "应用后工作台这份会被来源覆盖";
|
|
678
667
|
readonly 'configSync.code.lang': "yaml";
|
|
679
668
|
readonly 'configSync.code.copy': "复制";
|
|
@@ -684,19 +673,18 @@ export declare const zh: {
|
|
|
684
673
|
readonly 'configSync.code.collapseAria': "收起这一行的配置";
|
|
685
674
|
readonly 'configSync.code.expandAria': "展开差异(还有 {count} 行)";
|
|
686
675
|
readonly 'configSync.code.expand': "展开剩余 {count} 行";
|
|
687
|
-
readonly 'configSync.missing': "{pkg}
|
|
676
|
+
readonly 'configSync.missing': "{pkg} 还没装:这一行同步过来也不会生效 —— 先在模块市场里装它";
|
|
688
677
|
readonly 'configSync.apply': "同步选中的 {count} 项";
|
|
689
678
|
readonly 'configSync.applyNone': "请选择同步内容";
|
|
690
679
|
readonly 'configSync.applying': "正在写入…";
|
|
691
680
|
readonly 'configSync.applied': "已写入并检查通过";
|
|
692
681
|
readonly 'configSync.appliedUnverified': "已写入;重启后检查是否生效";
|
|
693
|
-
readonly 'configSync.appliedFiles': "复制了 {count} 个文件";
|
|
694
682
|
readonly 'configSync.appliedIds': "这次写进去:{ids}";
|
|
695
683
|
readonly 'configSync.skippedIds': "这几行工作台自己已有,没动:{ids}";
|
|
696
684
|
readonly 'configSync.nothing': "没有需要同步的内容";
|
|
697
685
|
readonly 'configSync.unreadable': "读不到 {path}:{reason}";
|
|
698
686
|
readonly 'configSync.noSource': "这台机器上只有工作台这一个 profile,没有可同步的来源";
|
|
699
|
-
readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile
|
|
687
|
+
readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把模型供应商那几行同步过来,或自己去「模型」里配。";
|
|
700
688
|
readonly 'configSync.failed': "同步没成功,再试一次。";
|
|
701
689
|
};
|
|
702
690
|
/** 中文词表的键类型:`en` 与模块词表都得覆盖同一批键。 */
|
package/dist/i18n/zh.js
CHANGED
|
@@ -267,6 +267,7 @@ export const zh = {
|
|
|
267
267
|
'panels.discover.loading': '正在读取索引',
|
|
268
268
|
'panels.discover.lead': '从索引源浏览模块;装上就能用。',
|
|
269
269
|
'panels.discover.addSource': '添加',
|
|
270
|
+
'panels.discover.addingSource': '正在添加…',
|
|
270
271
|
'panels.discover.addFirstSource': '添加索引源',
|
|
271
272
|
'panels.discover.removeSource': '移除',
|
|
272
273
|
'panels.discover.removeSourceNamed': '移除 {url}',
|
|
@@ -367,7 +368,6 @@ export const zh = {
|
|
|
367
368
|
'panels.discover.tabOverview': '概览',
|
|
368
369
|
'panels.discover.tabReadme': '说明',
|
|
369
370
|
'panels.discover.tabChangelog': '更新日志',
|
|
370
|
-
'panels.discover.docTitle': '{version} 的{kind}',
|
|
371
371
|
'panels.discover.docReadme': '说明',
|
|
372
372
|
'panels.discover.docChangelog': '更新日志',
|
|
373
373
|
'panels.discover.docLoading': '正在读取…',
|
|
@@ -604,6 +604,8 @@ export const zh = {
|
|
|
604
604
|
'approval.publish.module': '模块',
|
|
605
605
|
'approval.publish.target': '目标',
|
|
606
606
|
'approval.publish.version': '版本',
|
|
607
|
+
'approval.publish.author': '作者',
|
|
608
|
+
'approval.publish.authorMissing': '未署名(提交用本机 git 身份)',
|
|
607
609
|
'approval.publish.registry': '源',
|
|
608
610
|
'approval.publish.repo': '仓库',
|
|
609
611
|
'approval.publish.branch': '分支',
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export * from './config/constants.js';
|
|
|
37
37
|
export * from './config/storage.js';
|
|
38
38
|
export * from './contract/blocker.js';
|
|
39
39
|
export * from './contract/data.js';
|
|
40
|
+
export * from './contract/extension.js';
|
|
41
|
+
export * from './contract/lib.js';
|
|
42
|
+
export * from './contract/git.js';
|
|
43
|
+
export * from './contract/command.js';
|
|
40
44
|
export * from './contract/facts.js';
|
|
41
45
|
export * from './contract/long-task.js';
|
|
42
46
|
export * from './contract/protocol/bundle-install.js';
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,10 @@ export * from './config/constants.js';
|
|
|
37
37
|
export * from './config/storage.js';
|
|
38
38
|
export * from './contract/blocker.js';
|
|
39
39
|
export * from './contract/data.js';
|
|
40
|
+
export * from './contract/extension.js';
|
|
41
|
+
export * from './contract/lib.js';
|
|
42
|
+
export * from './contract/git.js';
|
|
43
|
+
export * from './contract/command.js';
|
|
40
44
|
export * from './contract/facts.js';
|
|
41
45
|
export * from './contract/long-task.js';
|
|
42
46
|
export * from './contract/protocol/bundle-install.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function isValidVersion(value: string): boolean;
|
|
2
|
+
export declare function isPrereleaseVersion(value: string): boolean;
|
|
3
|
+
export declare function compareVersions(left: string, right: string): number | undefined;
|
|
4
|
+
export declare function isNewerVersion(latest: string, installed: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
export function isValidVersion(value) {
|
|
3
|
+
return semver.valid(value.trim()) !== null;
|
|
4
|
+
}
|
|
5
|
+
export function isPrereleaseVersion(value) {
|
|
6
|
+
const parsed = semver.valid(value.trim());
|
|
7
|
+
return parsed !== null && semver.prerelease(parsed) !== null;
|
|
8
|
+
}
|
|
9
|
+
export function compareVersions(left, right) {
|
|
10
|
+
const a = semver.valid(left.trim());
|
|
11
|
+
const b = semver.valid(right.trim());
|
|
12
|
+
if (a === null || b === null)
|
|
13
|
+
return undefined;
|
|
14
|
+
return semver.compare(a, b);
|
|
15
|
+
}
|
|
16
|
+
export function isNewerVersion(latest, installed) {
|
|
17
|
+
if (latest === installed)
|
|
18
|
+
return false;
|
|
19
|
+
const compared = compareVersions(latest, installed);
|
|
20
|
+
return compared === undefined ? true : compared > 0;
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { quoteShellArg, tailLines } from '../host/shell-text.js';
|
|
2
|
+
import { runShell } from '../host/shell.js';
|
|
3
|
+
export function createFakeGit(shell) {
|
|
4
|
+
return {
|
|
5
|
+
async origin(path) {
|
|
6
|
+
const key = path.trim();
|
|
7
|
+
if (!key)
|
|
8
|
+
return { kind: 'unknown', reason: 'no-path' };
|
|
9
|
+
const result = await runShell(shell, `git -C ${quoteShellArg(key)} remote get-url origin`);
|
|
10
|
+
if (result.exitCode !== 0)
|
|
11
|
+
return { kind: 'no-origin', detail: tailLines(result.stderr, 3) };
|
|
12
|
+
return { kind: 'ok', remote: result.stdout.trim() };
|
|
13
|
+
},
|
|
14
|
+
async branch(path) {
|
|
15
|
+
const key = path.trim();
|
|
16
|
+
if (!key)
|
|
17
|
+
return { kind: 'unknown', reason: 'no-path' };
|
|
18
|
+
const result = await runShell(shell, `git -C ${quoteShellArg(key)} rev-parse --abbrev-ref HEAD`);
|
|
19
|
+
const name = result.stdout.trim();
|
|
20
|
+
if (result.exitCode !== 0)
|
|
21
|
+
return { kind: 'no-branch', detail: tailLines(result.stderr, 3) };
|
|
22
|
+
if (name === '' || name === 'HEAD')
|
|
23
|
+
return { kind: 'no-branch', detail: name };
|
|
24
|
+
return { kind: 'ok', branch: name };
|
|
25
|
+
},
|
|
26
|
+
async head(path) {
|
|
27
|
+
const key = path.trim();
|
|
28
|
+
if (!key)
|
|
29
|
+
return { kind: 'unknown', reason: 'no-path' };
|
|
30
|
+
const result = await runShell(shell, `git -C ${quoteShellArg(key)} rev-parse HEAD`);
|
|
31
|
+
if (result.exitCode !== 0)
|
|
32
|
+
return { kind: 'no-head', detail: tailLines(result.stderr, 3) };
|
|
33
|
+
return { kind: 'ok', commit: result.stdout.trim() };
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/shared",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,13 +37,15 @@
|
|
|
37
37
|
"@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.2",
|
|
38
38
|
"@types/node": "^24.19.0",
|
|
39
39
|
"@types/react": "^19.0.0",
|
|
40
|
+
"@types/semver": "^7.8.0",
|
|
40
41
|
"@vitest/coverage-v8": "^5.0.2",
|
|
41
42
|
"react": "^18.0.0",
|
|
42
43
|
"typescript": "5.9",
|
|
43
44
|
"vitest": "^5.0.2"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"dayjs": "^1.11.23"
|
|
47
|
+
"dayjs": "^1.11.23",
|
|
48
|
+
"semver": "^7.8.5"
|
|
47
49
|
},
|
|
48
50
|
"repository": {
|
|
49
51
|
"type": "git",
|
|
@@ -55,12 +57,12 @@
|
|
|
55
57
|
"url": "https://github.com/novaeth/dsh-workbench/issues"
|
|
56
58
|
},
|
|
57
59
|
"scripts": {
|
|
58
|
-
"build": "tsc -p tsconfig.build.json && node scripts/copy-css.mjs",
|
|
60
|
+
"build": "node scripts/gen-release-packages.mjs && tsc -p tsconfig.build.json && node scripts/copy-css.mjs",
|
|
59
61
|
"typecheck": "tsc --noEmit --incremental --tsBuildInfoFile node_modules/.cache/tsconfig.tsbuildinfo",
|
|
60
62
|
"test": "vitest run",
|
|
61
63
|
"coverage": "vitest run --coverage",
|
|
62
64
|
"barrels": "node scripts/barrels.mjs",
|
|
63
|
-
"selfcheck": "node scripts/check-state.mjs",
|
|
65
|
+
"selfcheck": "node scripts/check-state.mjs && node scripts/gen-release-packages.mjs --check",
|
|
64
66
|
"arch:report": "arch-guard --report-only",
|
|
65
67
|
"arch": "arch-guard"
|
|
66
68
|
}
|
|
@@ -403,6 +403,12 @@ describe('formRowsOf', () => {
|
|
|
403
403
|
expect(propsOf(rows[0])['children']).toBe('env:wb-form-env:true:false');
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
+
it('★ 标签挂到同一格的控件上(htmlFor 与绑定 id 同一个值)', () => {
|
|
407
|
+
const rows = formRowsOf({ fields: [field('env', 'prod')], problems, showProblem: true, busy: false });
|
|
408
|
+
|
|
409
|
+
expect(propsOf(rows[0])['htmlFor']).toBe('wb-form-env');
|
|
410
|
+
});
|
|
411
|
+
|
|
406
412
|
it('★ 这一格的 value / onChange 从字段配置原样进绑定(值只写一处)', () => {
|
|
407
413
|
const onChange = (): void => {};
|
|
408
414
|
const probe: FormField = {
|
|
@@ -193,6 +193,7 @@ export function formRowsOf<Values extends object>(args: {
|
|
|
193
193
|
h(FormRow, {
|
|
194
194
|
key: field.key,
|
|
195
195
|
label: field.label,
|
|
196
|
+
htmlFor: controlIdOf(field.key),
|
|
196
197
|
hint: field.hint,
|
|
197
198
|
problem: args.showProblem ? args.problems[field.key] : undefined,
|
|
198
199
|
layout: field.layout,
|
|
@@ -200,6 +201,10 @@ export function formRowsOf<Values extends object>(args: {
|
|
|
200
201
|
);
|
|
201
202
|
}
|
|
202
203
|
|
|
204
|
+
function controlIdOf(key: string): string {
|
|
205
|
+
return `wb-form-${key}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
203
208
|
function controlOf<K extends string, V, Vals extends object>(
|
|
204
209
|
field: FormField<K, V, Vals>,
|
|
205
210
|
problems: Readonly<Record<string, ReactNode | undefined>>,
|
|
@@ -207,7 +212,7 @@ function controlOf<K extends string, V, Vals extends object>(
|
|
|
207
212
|
busy: boolean,
|
|
208
213
|
): ReactNode {
|
|
209
214
|
return field.control({
|
|
210
|
-
id:
|
|
215
|
+
id: controlIdOf(field.key),
|
|
211
216
|
name: field.key,
|
|
212
217
|
invalid: showProblem && Boolean(problems[field.key]),
|
|
213
218
|
disabled: busy || field.disabled === true,
|
|
@@ -48,6 +48,35 @@ describe('FormRow', () => {
|
|
|
48
48
|
expect(childrenOf(node).filter((one) => one !== null)).toHaveLength(2);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
it('★ 行是 <div>,<label> 只包标签文字 —— 控件、提示与整行空白都不在标签里', () => {
|
|
52
|
+
const node = FormRow({
|
|
53
|
+
label: '项目',
|
|
54
|
+
htmlFor: 'wb-form-project',
|
|
55
|
+
hint: '选错了也能改',
|
|
56
|
+
children: '下拉',
|
|
57
|
+
}) as unknown as { type: unknown; props: { children: unknown[] } };
|
|
58
|
+
const [labelNode, controlNode, hintNode] = node.props.children as {
|
|
59
|
+
type: unknown;
|
|
60
|
+
props: Record<string, unknown>;
|
|
61
|
+
}[];
|
|
62
|
+
|
|
63
|
+
expect(node.type).toBe('div');
|
|
64
|
+
expect(labelNode?.type).toBe('label');
|
|
65
|
+
expect(labelNode?.props['htmlFor']).toBe('wb-form-project');
|
|
66
|
+
expect(texts(labelNode)).toEqual(['项目']);
|
|
67
|
+
expect(controlNode?.props['className']).toBe('wb-formControl');
|
|
68
|
+
expect(hintNode?.props['className']).toBe('wb-formHint');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('没给 htmlFor 就不挂 for(排布照旧,只是点标签不聚焦)', () => {
|
|
72
|
+
const node = FormRow({ label: '项目', children: '下拉' }) as unknown as {
|
|
73
|
+
props: { children: unknown[] };
|
|
74
|
+
};
|
|
75
|
+
const labelNode = node.props.children[0] as { props: Record<string, unknown> };
|
|
76
|
+
|
|
77
|
+
expect(labelNode.props['htmlFor']).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
51
80
|
it('有 problem 就顶掉 hint(同一格,二选一),错误行挂 data-wb-problem 给聚焦那件找', () => {
|
|
52
81
|
const node = FormRow({
|
|
53
82
|
label: '项目',
|
|
@@ -150,6 +179,7 @@ describe('标签列:同一个 FormRows 共用一列(ADR-0052 §11)', () =>
|
|
|
150
179
|
|
|
151
180
|
it('★ 标签不折行;stacked 还是单列、标签照常换行', () => {
|
|
152
181
|
expect(declarations('.wb-formLabel')).toContain('white-space: nowrap');
|
|
182
|
+
expect(declarations('.wb-formLabel')).toContain('justify-self: start');
|
|
153
183
|
expect(declarations(".wb-formRow[data-layout='stacked'] .wb-formLabel")).toContain(
|
|
154
184
|
'white-space: normal',
|
|
155
185
|
);
|
|
@@ -23,6 +23,7 @@ export function FormRows({ children }: FormRowsProps) {
|
|
|
23
23
|
*/
|
|
24
24
|
export interface FormRowProps {
|
|
25
25
|
readonly label: ReactNode;
|
|
26
|
+
readonly htmlFor?: string | undefined;
|
|
26
27
|
readonly hint?: ReactNode | undefined;
|
|
27
28
|
readonly problem?: ReactNode | undefined;
|
|
28
29
|
readonly layout?: 'inline' | 'stacked' | undefined;
|
|
@@ -32,20 +33,23 @@ export interface FormRowProps {
|
|
|
32
33
|
/**
|
|
33
34
|
* 表单一行:左边标签、右边控件,提示与错误占控件下面那一格。
|
|
34
35
|
* @param props.label - 这一行的标签;进了这一行,控件自己就别再给 `label`,否则会多一个标签。
|
|
36
|
+
* @param props.htmlFor - 标签挂到哪个控件(同一个 `id`);不给就只是排布,点标签不聚焦 —— `Form` 会自己接好。
|
|
35
37
|
* @param props.hint - 控件下的说明;给了 `problem` 就不画它 —— 同一格不叠两段话。
|
|
36
38
|
* @param props.problem - 校验失败那句话;给了就顶掉 `hint` 并给整行加上出错标记。
|
|
37
39
|
* @param props.layout - `stacked` 才是标签在上、控件在下(默认 `inline`:标签在左)。
|
|
38
40
|
* @param props.children - 控件本体。
|
|
39
|
-
* @returns 一个 `<label
|
|
41
|
+
* @returns 一个 `<div>`:里面的 `<label>` 只包标签文字,不包控件、提示与整行的空白。
|
|
40
42
|
*/
|
|
41
|
-
export function FormRow({ label, hint, problem, layout = 'inline', children }: FormRowProps) {
|
|
43
|
+
export function FormRow({ label, htmlFor, hint, problem, layout = 'inline', children }: FormRowProps) {
|
|
42
44
|
return (
|
|
43
|
-
<
|
|
45
|
+
<div
|
|
44
46
|
className="wb-formRow"
|
|
45
47
|
data-layout={layout}
|
|
46
48
|
data-wb-problem={problem === undefined ? undefined : ''}
|
|
47
49
|
>
|
|
48
|
-
<
|
|
50
|
+
<label className="wb-formLabel" htmlFor={htmlFor}>
|
|
51
|
+
{label}
|
|
52
|
+
</label>
|
|
49
53
|
<span className="wb-formControl">{children}</span>
|
|
50
54
|
{problem === undefined ? (
|
|
51
55
|
hint === undefined ? null : (
|
|
@@ -54,6 +58,6 @@ export function FormRow({ label, hint, problem, layout = 'inline', children }: F
|
|
|
54
58
|
) : (
|
|
55
59
|
<span className="wb-formProblem">{problem}</span>
|
|
56
60
|
)}
|
|
57
|
-
</
|
|
61
|
+
</div>
|
|
58
62
|
);
|
|
59
63
|
}
|
package/src/config/constants.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/** 外壳插件的包名:浏览器模块表与宿主按它注册、认领这枚插件。 */
|
|
2
2
|
export const PLUGIN_ID = "@dsh-workbench/core";
|
|
3
3
|
|
|
4
|
-
/** 与外壳同批发布的兄弟包名:`release.ts` 用它判一版三包是否都已在源上。 */
|
|
5
|
-
export const RELEASE_SIBLINGS = [
|
|
6
|
-
"@dsh-workbench/shared",
|
|
7
|
-
"@dsh-workbench/module-tools",
|
|
8
|
-
] as const;
|
|
9
|
-
|
|
10
4
|
/** 外壳宿主 HTTP API 的根前缀;prefs / actions / provision 等路由都挂在它下面。 */
|
|
11
5
|
export const API_PREFIX = "/workbench/api";
|
|
12
6
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CommandFile {
|
|
2
|
+
readonly content: string;
|
|
3
|
+
readonly suffix?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface CommandRequest {
|
|
7
|
+
readonly argv: readonly string[];
|
|
8
|
+
readonly timeoutMs?: number | undefined;
|
|
9
|
+
readonly cwd?: string | undefined;
|
|
10
|
+
readonly files?: readonly CommandFile[] | undefined;
|
|
11
|
+
readonly appendFileArgs?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CommandResult {
|
|
15
|
+
readonly stdout: string;
|
|
16
|
+
readonly stderr: string;
|
|
17
|
+
readonly exitCode: number;
|
|
18
|
+
readonly timedOut: boolean;
|
|
19
|
+
readonly filePaths: readonly string[];
|
|
20
|
+
readonly error?: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CommandReader {
|
|
24
|
+
run(request: CommandRequest): Promise<CommandResult>;
|
|
25
|
+
}
|
package/src/contract/data.ts
CHANGED
|
@@ -19,7 +19,8 @@ export interface BrowserDataRequest extends DataRequestBase {
|
|
|
19
19
|
|
|
20
20
|
export interface CommandDataRequest extends DataRequestBase {
|
|
21
21
|
readonly kind: 'command';
|
|
22
|
-
readonly
|
|
22
|
+
readonly adapter: string;
|
|
23
|
+
readonly argv: readonly string[];
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export type DataRequest = HttpDataRequest | BrowserDataRequest | CommandDataRequest;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ExtensionSession = 'persistent' | 'ephemeral' | 'none';
|
|
2
|
+
|
|
3
|
+
export interface ExtensionCallOptions {
|
|
4
|
+
readonly key?: string;
|
|
5
|
+
readonly workdir?: string;
|
|
6
|
+
readonly session?: ExtensionSession;
|
|
7
|
+
readonly timeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExtensionValue<T = unknown> {
|
|
11
|
+
readonly value: T;
|
|
12
|
+
readonly at: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ExtensionCaller {
|
|
16
|
+
json(
|
|
17
|
+
args: readonly string[],
|
|
18
|
+
options?: ExtensionCallOptions,
|
|
19
|
+
): Promise<ExtensionValue>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type OriginRead =
|
|
2
|
+
| { readonly kind: 'ok'; readonly remote: string }
|
|
3
|
+
| { readonly kind: 'no-origin'; readonly detail?: string }
|
|
4
|
+
| { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string };
|
|
5
|
+
|
|
6
|
+
export type BranchRead =
|
|
7
|
+
| { readonly kind: 'ok'; readonly branch: string }
|
|
8
|
+
| { readonly kind: 'no-branch'; readonly detail?: string | undefined }
|
|
9
|
+
| { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string | undefined };
|
|
10
|
+
|
|
11
|
+
export type HeadRead =
|
|
12
|
+
| { readonly kind: 'ok'; readonly commit: string }
|
|
13
|
+
| { readonly kind: 'no-head'; readonly detail?: string }
|
|
14
|
+
| { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string };
|
|
15
|
+
|
|
16
|
+
export interface GitReader {
|
|
17
|
+
origin(path: string): Promise<OriginRead>;
|
|
18
|
+
branch(path: string): Promise<BranchRead>;
|
|
19
|
+
head(path: string): Promise<HeadRead>;
|
|
20
|
+
}
|