@dsh-workbench/core 0.3.11 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -117
- package/bin/dsh-workbench +130 -29
- package/bin/dsh-workbench.cmd +5 -0
- package/bin/opencli-isolated +3 -2
- package/bin/opencli-isolated.mjs +44 -0
- package/bin/opencli-node-mode.cjs +1 -0
- package/bin/seed-workshop-windows.mjs +307 -0
- package/client.js +6572 -3959
- package/cordis.patch.yml +3 -3
- package/dist/client/client.body.js +6572 -3959
- package/dist/client/index.js +6417 -3804
- package/dist/host/index.js +5704 -5945
- package/dist/types/app/client.d.ts +1 -0
- package/dist/types/app/host.d.ts +2 -1
- package/dist/types/app/layouts/approval-detail.d.ts +3 -0
- package/dist/types/app/layouts/env-gate/boot-gate.d.ts +1 -12
- package/dist/types/app/layouts/env-gate/gate-text.d.ts +2 -1
- package/dist/types/app/layouts/market/DiscoverPanel.d.ts +8 -0
- package/dist/types/app/layouts/market/add-module-text.d.ts +1 -1
- package/dist/types/app/layouts/market/discover-categories.d.ts +8 -0
- package/dist/types/app/layouts/market/discover-confirm.d.ts +14 -0
- package/dist/types/app/layouts/market/discover-detail.d.ts +12 -0
- package/dist/types/app/layouts/market/discover-dialogs.d.ts +7 -0
- package/dist/types/app/layouts/market/discover-doc.d.ts +18 -0
- package/dist/types/app/layouts/market/discover-init-dialog.d.ts +10 -0
- package/dist/types/app/layouts/market/discover-rows.d.ts +24 -0
- package/dist/types/app/layouts/market/discover-sources-dialog.d.ts +16 -0
- package/dist/types/app/layouts/market/discover-states.d.ts +22 -0
- package/dist/types/app/layouts/market/discover-toolbar.d.ts +23 -0
- package/dist/types/app/layouts/market/discover-versions.d.ts +9 -0
- package/dist/types/app/layouts/market/discover-view.d.ts +38 -0
- package/dist/types/app/layouts/market/market-header.d.ts +13 -0
- package/dist/types/app/layouts/market/panel.d.ts +1 -1
- package/dist/types/app/layouts/market/use-add-module.d.ts +1 -1
- package/dist/types/app/layouts/market/use-discover.d.ts +72 -0
- package/dist/types/app/layouts/market/use-module-versions.d.ts +1 -8
- package/dist/types/app/layouts/rightbar/MarketView.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/Rightbar.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/board-shape.d.ts +1 -14
- package/dist/types/app/layouts/rightbar/market-busy.d.ts +0 -22
- package/dist/types/app/layouts/rightbar/market-change.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-hint.d.ts +1 -7
- package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +0 -7
- package/dist/types/app/layouts/rightbar/market-row-icon.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-row-types.d.ts +2 -2
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-section-icon.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-settle-hold.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-settle.d.ts +4 -7
- package/dist/types/app/layouts/rightbar/market-shared-rows.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-update-verdict.d.ts +1 -11
- package/dist/types/app/layouts/rightbar/market-view-text.d.ts +5 -1
- package/dist/types/app/layouts/rightbar/market-workbench-row.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/store.d.ts +0 -12
- package/dist/types/app/layouts/sidebar/LongTaskDot.d.ts +0 -6
- package/dist/types/app/layouts/sidebar/LongTaskHover.d.ts +0 -6
- package/dist/types/app/layouts/sidebar/edition-boot.d.ts +1 -19
- package/dist/types/app/layouts/sidebar/edition.d.ts +1 -18
- package/dist/types/app/layouts/sidebar/use-attention.d.ts +0 -4
- package/dist/types/app/layouts/sidebar/workshop-preset.d.ts +2 -0
- package/dist/types/app/layouts/workbench-settings/AdapterSetItem.d.ts +5 -0
- package/dist/types/app/layouts/workbench-settings/ConfigSyncRows.d.ts +11 -0
- package/dist/types/app/layouts/workbench-settings/NewWorkbenchItem.d.ts +5 -0
- package/dist/types/app/layouts/workbench-settings/SettingsItem.d.ts +0 -9
- package/dist/types/app/layouts/workbench-settings/SidebarEditionItem.d.ts +0 -6
- package/dist/types/app/layouts/workbench-settings/WorkbenchSettingsSection.d.ts +0 -6
- package/dist/types/app/units/manifests.d.ts +1 -1
- package/dist/types/{app/units → kernel/client}/registry.d.ts +1 -1
- package/dist/types/kernel/contract/bundle-install.d.ts +2 -0
- package/dist/types/kernel/contract/config-sync.d.ts +2 -0
- package/dist/types/kernel/contract/diy.d.ts +1 -0
- package/dist/types/kernel/contract/dsh-plugins.d.ts +2 -0
- package/dist/types/kernel/contract/index.d.ts +4 -0
- package/dist/types/kernel/contract/long-tasks.d.ts +2 -0
- package/dist/types/kernel/contract/market-index.d.ts +2 -0
- package/dist/types/kernel/contract/platform.d.ts +1 -0
- package/dist/types/kernel/contract/preflight-wake.d.ts +2 -0
- package/dist/types/kernel/contract/profile-create.d.ts +2 -0
- package/dist/types/kernel/contract/sidebar-edition.d.ts +2 -0
- package/dist/types/kernel/contract/unit-manifests.d.ts +2 -0
- package/dist/types/{shared/api → kernel}/host/mount-units.d.ts +2 -1
- package/dist/types/modules/panels/client.d.ts +1 -1
- package/dist/types/modules/panels/model/approval.d.ts +3 -15
- package/dist/types/modules/panels/model/diy-changelog.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-context.d.ts +1 -16
- package/dist/types/modules/panels/model/diy-page.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-open.d.ts +0 -15
- package/dist/types/modules/panels/model/diy-record-text.d.ts +0 -2
- package/dist/types/modules/panels/model/diy-record.d.ts +0 -30
- package/dist/types/modules/panels/model/diy-tools.d.ts +1 -0
- package/dist/types/modules/panels/model/long-task-tools.d.ts +0 -11
- package/dist/types/modules/panels/model/market-dependency-update.d.ts +1 -7
- package/dist/types/modules/panels/model/market-dependency.d.ts +15 -10
- package/dist/types/modules/panels/model/market-discover-routes.d.ts +3 -0
- package/dist/types/modules/panels/model/market-discover.d.ts +33 -0
- package/dist/types/modules/panels/model/market-dispatch.d.ts +3 -3
- package/dist/types/modules/panels/model/market-env.d.ts +2 -3
- package/dist/types/modules/panels/model/market-registry.d.ts +3 -3
- package/dist/types/modules/panels/model/market-restart.d.ts +1 -1
- package/dist/types/modules/panels/model/market-route.d.ts +5 -3
- package/dist/types/modules/panels/model/market-sources-act.d.ts +9 -0
- package/dist/types/modules/panels/model/market-types.d.ts +6 -13
- package/dist/types/modules/panels/model/market-update-bundle.d.ts +3 -9
- package/dist/types/modules/panels/model/market-verify.d.ts +3 -19
- package/dist/types/modules/panels/model/market-workbench-update.d.ts +3 -2
- package/dist/types/modules/panels/model/market.d.ts +6 -5
- package/dist/types/modules/panels/model/plugin-actions.d.ts +2 -1
- package/dist/types/modules/panels/model/plugin-section.d.ts +3 -1
- package/dist/types/modules/panels/model/publish-preview-routes.d.ts +2 -0
- package/dist/types/modules/panels/unit.d.ts +7 -3
- package/dist/types/modules/sessions/model/attention.d.ts +0 -11
- package/dist/types/modules/sessions/model/session-node.d.ts +0 -10
- package/dist/types/shared/api/diy.d.ts +6 -4
- package/dist/types/shared/api/host/approval-call.d.ts +0 -9
- package/dist/types/shared/api/host/approval-gate.d.ts +0 -13
- package/dist/types/shared/api/host/bundle-routes.d.ts +1 -1
- package/dist/types/shared/api/host/diy-artifacts.d.ts +0 -11
- package/dist/types/shared/api/host/diy-changelog.d.ts +13 -0
- package/dist/types/shared/api/host/diy-components.d.ts +2 -3
- package/dist/types/shared/api/host/diy-modules.d.ts +0 -16
- package/dist/types/shared/api/host/diy-publish-preview.d.ts +4 -0
- package/dist/types/shared/api/host/diy-recon-fs.d.ts +2 -2
- package/dist/types/shared/api/host/diy-tokens.d.ts +8 -0
- package/dist/types/shared/api/host/host-routes.d.ts +3 -6
- package/dist/types/shared/api/host/long-task-notice.d.ts +0 -20
- package/dist/types/shared/api/host/long-tasks.d.ts +1 -8
- package/dist/types/shared/api/host/market-doc.d.ts +21 -0
- package/dist/types/shared/api/host/market-index-fetch.d.ts +37 -0
- package/dist/types/shared/api/host/market-source-init.d.ts +22 -0
- package/dist/types/shared/api/host/market-sources-store.d.ts +15 -0
- package/dist/types/shared/api/host/permission-mode.d.ts +0 -5
- package/dist/types/shared/api/host/post-channels.d.ts +1 -1
- package/dist/types/shared/api/host/sidebar-edition.d.ts +1 -33
- package/dist/types/shared/api/host/unit-roster-facts.d.ts +1 -1
- package/dist/types/shared/api/host/workspace-root.d.ts +0 -7
- package/dist/types/shared/api/platform/client.d.ts +10 -0
- package/dist/types/shared/api/unit-board.d.ts +0 -16
- package/dist/types/shared/api/write-outcome.d.ts +0 -12
- package/dist/types/shared/components/IconModules.d.ts +0 -6
- package/dist/types/shared/components/PanelFoot.d.ts +0 -9
- package/dist/types/shared/components/blocker-action.d.ts +0 -13
- package/dist/types/shared/dev-surface/index.d.ts +5 -0
- package/dist/types/shared/dev-surface/types.d.ts +79 -0
- package/dist/types/shared/hooks/bundle-queries.d.ts +1 -13
- package/dist/types/shared/hooks/fact-transport.d.ts +4 -0
- package/dist/types/shared/hooks/fact-transports.d.ts +0 -4
- package/dist/types/shared/hooks/market-queries.d.ts +11 -0
- package/dist/types/shared/hooks/panel-state-report.d.ts +0 -12
- package/dist/types/shared/hooks/sidebar-edition.d.ts +1 -6
- package/dist/types/shared/hooks/use-blocker-actions.d.ts +0 -8
- package/dist/types/shared/hooks/use-capabilities.d.ts +0 -59
- package/dist/types/shared/hooks/use-diy-debug.d.ts +0 -13
- package/dist/types/shared/hooks/use-diy-record.d.ts +0 -13
- package/dist/types/shared/hooks/use-shell-long-tasks.d.ts +1 -7
- package/icon.svg +17 -28
- package/package.json +33 -13
- package/preset/diy.patch.yml +1 -1
- package/profile/isolation.patch.yml +8 -8
- package/profile/sandbox.patch.yml +2 -2
- package/scripts/clone-profile.mjs +268 -0
- package/scripts/create-workbench.mjs +166 -0
- package/scripts/seed-profile.sh +22 -10
- package/scripts/seed-workshop.sh +17 -19
- package/skills/workbench-module-diy/BUILD.md +4 -11
- package/skills/workbench-module-diy/COPY.md +1 -1
- package/skills/workbench-module-diy/DATASOURCE.md +107 -22
- package/skills/workbench-module-diy/DESIGN.md +2 -1
- package/skills/workbench-module-diy/FAMILY.md +48 -68
- package/skills/workbench-module-diy/KIT.md +2 -1
- package/skills/workbench-module-diy/LINKAGE.md +1 -1
- package/skills/workbench-module-diy/PANEL.md +5 -3
- package/skills/workbench-module-diy/REVIEW.md +7 -7
- package/skills/workbench-module-diy/SKILL.md +20 -11
- package/skills/workbench-module-diy/STEPS.md +1 -1
- package/skills/workbench-module-diy/TOOLS.md +33 -9
- package/skills/workbench-module-diy/WIRING.md +18 -6
- package/skills/workbench-module-diy/WRITES.md +30 -4
- package/dist/types/shared/api/bundle-install.d.ts +0 -136
- package/dist/types/shared/api/config-sync.d.ts +0 -35
- package/dist/types/shared/api/dsh-plugins.d.ts +0 -11
- package/dist/types/shared/api/host/bundle-manager.d.ts +0 -11
- package/dist/types/shared/api/host/config-sync.d.ts +0 -46
- package/dist/types/shared/api/host/diy-preset-health.d.ts +0 -35
- package/dist/types/shared/api/host/dsh-plugins.d.ts +0 -5
- package/dist/types/shared/api/host/installed-module.d.ts +0 -54
- package/dist/types/shared/api/host/installed-module.test.d.ts +0 -1
- package/dist/types/shared/api/host/opencli-command.d.ts +0 -10
- package/dist/types/shared/api/host/opencli-command.test.d.ts +0 -1
- package/dist/types/shared/api/host/opencli.test.d.ts +0 -1
- package/dist/types/shared/api/host/package-content.d.ts +0 -6
- package/dist/types/shared/api/host/package-content.test.d.ts +0 -1
- package/dist/types/shared/api/host/package-kind.d.ts +0 -21
- package/dist/types/shared/api/host/package-kind.test.d.ts +0 -1
- package/dist/types/shared/api/host/package-route.d.ts +0 -23
- package/dist/types/shared/api/host/package-route.test.d.ts +0 -1
- package/dist/types/shared/api/host/plugin-catalog.d.ts +0 -65
- package/dist/types/shared/api/host/plugin-login-hint.d.ts +0 -2
- package/dist/types/shared/api/host/plugin-tools.d.ts +0 -14
- package/dist/types/shared/api/host/plugin-units.d.ts +0 -48
- package/dist/types/shared/api/host/preflight-route.d.ts +0 -15
- package/dist/types/shared/api/host/preflight.d.ts +0 -75
- package/dist/types/shared/api/host/probe-cache.d.ts +0 -6
- package/dist/types/shared/api/host/probe-libs.d.ts +0 -11
- package/dist/types/shared/api/host/probe-units.d.ts +0 -17
- package/dist/types/shared/api/host/probe-verdict.d.ts +0 -7
- package/dist/types/shared/api/host/profile-registries.d.ts +0 -21
- package/dist/types/shared/api/host/registry-declaration.d.ts +0 -23
- package/dist/types/shared/api/host/release.d.ts +0 -24
- package/dist/types/shared/api/host/runtime-seed.d.ts +0 -40
- package/dist/types/shared/api/host/self-update.d.ts +0 -52
- package/dist/types/shared/api/host/version-range.d.ts +0 -2
- package/dist/types/shared/api/long-tasks.d.ts +0 -19
- package/dist/types/shared/api/sidebar-edition.d.ts +0 -14
- package/dist/types/shared/api/unit-manifests.d.ts +0 -6
- package/docs/HANDOFF.md +0 -333
- package/docs/OPERATIONS.md +0 -240
- package/skills/workbench-module-diy/TOOLING.md +0 -38
- /package/dist/types/{app/layouts/rightbar/registry.d.ts → kernel/client/board-registry.d.ts} +0 -0
- /package/dist/types/{app/layouts/rightbar/registry.test.d.ts → kernel/contract/contracts.test.d.ts} +0 -0
- /package/dist/types/{shared/api/host/bundle-manager.test.d.ts → kernel/contract/index.test.d.ts} +0 -0
- /package/dist/types/{shared/api → kernel}/host/unit-readiness.d.ts +0 -0
- /package/dist/types/{shared/api → kernel}/host/unit-registry.d.ts +0 -0
- /package/dist/types/shared/{api/host/dsh-plugins.test.d.ts → dev-surface/install.d.ts} +0 -0
package/icon.svg
CHANGED
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
width="64"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
rx="12"
|
|
19
|
-
fill="none"
|
|
20
|
-
stroke="#6b7280"
|
|
21
|
-
stroke-width="5"
|
|
22
|
-
/>
|
|
23
|
-
<path
|
|
24
|
-
d="M21 24h22M21 32h22M21 40h13"
|
|
25
|
-
stroke="#6b7280"
|
|
26
|
-
stroke-width="5"
|
|
27
|
-
stroke-linecap="round"
|
|
28
|
-
/>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="wb-logo-app" x1="32" y1="4" x2="32" y2="58" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#54ECE7"/>
|
|
5
|
+
<stop offset="1" stop-color="#658EFF"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="64" height="64" rx="15" fill="#0F1115"/>
|
|
9
|
+
<g transform="translate(3.84 3.84) scale(0.88)">
|
|
10
|
+
<path d="M10 6H54A5 5 0 0 1 59 11V43A5 5 0 0 1 54 48H10A5 5 0 0 1 5 43V11A5 5 0 0 1 10 6Z M12 10H52A3 3 0 0 1 55 13V41A3 3 0 0 1 52 44H12A3 3 0 0 1 9 41V13A3 3 0 0 1 12 10Z" fill="url(#wb-logo-app)" fill-rule="evenodd"/>
|
|
11
|
+
<rect x="27.5" y="48" width="9" height="4.75" fill="url(#wb-logo-app)"/>
|
|
12
|
+
<rect x="19" y="52.75" width="26" height="4.75" rx="2.375" fill="url(#wb-logo-app)"/>
|
|
13
|
+
<g transform="translate(14.6263 10.5853) scale(1.95)">
|
|
14
|
+
<path d="M8.844 13.742C8.967 12.328 8.45 10.4 8.45 9.65C8.45 8.94 8.88 8.43 9.6 8.43C11.285 8.43 12.106 8.281 12.685 8.104C13.71 7.791 14.585 6.768 15.055 5.945C15.137 5.803 14.99 5.641 14.829 5.671C13.829 5.86 12.828 5.376 11.827 4.978C10.659 4.514 9.491 4.707 8.935 4.876C8.805 4.915 8.658 4.819 8.636 4.686C8.468 3.643 7.405 2.615 5.498 2.238C4.54 2.048 3.748 1.574 3.347 1.202C3.252 1.113 3.088 1.125 3.03 1.242C2.628 2.059 2.168 3.82 5.248 6.115C5.82 6.494 6.31 6.785 6.574 7.637C6.72 8.104 6.157 9.168 6.061 9.368C5.157 11.27 5.089 12.19 4.926 13.742Z" fill="url(#wb-logo-app)"/>
|
|
15
|
+
<circle cx="6.885" cy="13.742" r="1.95" fill="url(#wb-logo-app)"/>
|
|
16
|
+
</g>
|
|
17
|
+
</g>
|
|
29
18
|
</svg>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "个人工作台:Agent
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"description": "个人工作台:Agent 工作台(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
7
7
|
"exports": {
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"default": "./client.js"
|
|
15
15
|
},
|
|
16
16
|
"./package.json": "./package.json",
|
|
17
|
+
"./contract": {
|
|
18
|
+
"types": "./dist/types/kernel/contract/index.d.ts"
|
|
19
|
+
},
|
|
17
20
|
"./client/esm": {
|
|
18
21
|
"types": "./dist/types/app/client.d.ts",
|
|
19
22
|
"default": "./dist/client/index.js"
|
|
@@ -22,7 +25,6 @@
|
|
|
22
25
|
"bin": {
|
|
23
26
|
"dsh-workbench": "./bin/dsh-workbench"
|
|
24
27
|
},
|
|
25
|
-
"//files": "npm 的兜底是 .gitignore —— 而 dist/ 在 .gitignore 里,不显式列出就会**漏掉宿主入口**(exports['.'] 指向它)。发出去之前用 npm pack --dry-run 数一遍 dist/ 有几条。skills/ 是 DIY 模式挂给 agent 的指引(经 skill-filesystem 的 customSkillDirs 挂载),漏了不报错、只是 DIY 的 agent 什么都不知道 —— selfcheck 有一条判据盯着它。scripts/ 下是**随包出货的脚本**:启动器与宿主自举都要跑它们(seed-profile.sh / seed-workshop.sh),漏一个的症状是「仓库里怎么都对、装出去那台静默什么也没做」。",
|
|
26
28
|
"files": [
|
|
27
29
|
"dist",
|
|
28
30
|
"client.js",
|
|
@@ -32,18 +34,16 @@
|
|
|
32
34
|
"profile",
|
|
33
35
|
"skills",
|
|
34
36
|
"preset",
|
|
37
|
+
"scripts/create-workbench.mjs",
|
|
38
|
+
"scripts/clone-profile.mjs",
|
|
35
39
|
"scripts/seed-profile.sh",
|
|
36
40
|
"scripts/seed-workshop.sh",
|
|
37
|
-
"README.md"
|
|
38
|
-
"docs/HANDOFF.md",
|
|
39
|
-
"docs/OPERATIONS.md"
|
|
41
|
+
"README.md"
|
|
40
42
|
],
|
|
41
43
|
"meta": {
|
|
42
44
|
"title": "Workbench",
|
|
43
45
|
"description": "个人工作台"
|
|
44
46
|
},
|
|
45
|
-
"//scripts": "包内不跑 check:docs —— 那份文档管理块住在仓库根的 docs/ARCHITECTURE.md,由根 `pnpm run check` 用 --config 指到本包的 arch.config.mjs 校验。check 与 prepublishOnly 都走 -w 跑根那一整套:包内自己串一份会漏掉 lint(react-hooks 那几条规则只在这里跑)、check:docs 与模块工具包的十三条判据 —— 2026-10-16 实测踩到(渲染期写 ref,包内全绿、根上一跑就红)。",
|
|
46
|
-
"//dsh.bundle.patch": "一份 preset 就是一个补丁层:它 insert 一行 @deepseek-ai/dsh-agent-preset,config.plugins 是整表插件清单。diy.patch.yml 是**生成的**(scripts/gen-diy-preset.mjs,从 dsh 出厂那份 standard.patch.yml 派生),selfcheck 有一条判据盯着它有没有过期。",
|
|
47
47
|
"dsh": {
|
|
48
48
|
"bundle": {
|
|
49
49
|
"patch": [
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
]
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
"//engines": "DIY 模式(preset/diy.patch.yml)是从 **dsh 出厂那份 standard.patch.yml** 派生的,所以这份外壳只跟着它派生的那一代 dsh 走:dsh 太旧时那个 preset 挂不起来,而 dsh 的模式选择器**只列挂得起来的** ⇒ 用户面前「工作台 DIY 模式」整个不见,一句错都不报(实测 0.2.0-rc.2:缺 dsh-tool-schedule)。这里声明下限,让 dsh 自己的兼容性预检在**装的时候**拒绝(自 0.2.1-alpha.4 起 engines.dsh 优先于 peer)。⚠️ **不写 peerDependencies['@deepseek-ai/dsh']**:pnpm 的 auto-install-peers(v11 连 optional 也装)会把整套 dsh 拖进 profile。旧到不认识 engines.dsh 的 dsh(0.2.0 及更早)由启动器那道硬门禁兜 —— 见 bin/dsh-workbench。判据:selfcheck 的「声明下限 = 验过的 dsh 版本」那条。",
|
|
66
65
|
"engines": {
|
|
67
66
|
"dsh": ">=0.2.1-rc.2"
|
|
68
67
|
},
|
|
@@ -75,10 +74,13 @@
|
|
|
75
74
|
}
|
|
76
75
|
},
|
|
77
76
|
"devDependencies": {
|
|
78
|
-
"@arch-guard/core": "^0.11.
|
|
77
|
+
"@arch-guard/core": "^0.11.1",
|
|
79
78
|
"@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.2",
|
|
80
79
|
"@types/node": "^24.19.0",
|
|
80
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
81
81
|
"@types/react": "^19.3.0",
|
|
82
|
+
"@types/which": "^3.0.4",
|
|
83
|
+
"@types/write-file-atomic": "^4.0.3",
|
|
82
84
|
"@vitest/coverage-v8": "^5.0.2",
|
|
83
85
|
"esbuild": "^0.28.2",
|
|
84
86
|
"react": "^19.3.0",
|
|
@@ -86,12 +88,28 @@
|
|
|
86
88
|
"vite": "^8.3.1",
|
|
87
89
|
"vitest": "^5.0.2"
|
|
88
90
|
},
|
|
89
|
-
"//publishConfig": "只影响**发布这个包**,不影响别人解析依赖。现在发**公网 npm**(scripts/release.mjs 走 registry.npmjs.org),所以这里只有 access;哪天真要改发内网源,地址写在这一段的 registry 里(release.mjs 会优先读它)。",
|
|
90
91
|
"publishConfig": {
|
|
91
92
|
"access": "public"
|
|
92
93
|
},
|
|
93
94
|
"dependencies": {
|
|
94
|
-
"
|
|
95
|
+
"dayjs": "^1.11.23",
|
|
96
|
+
"execa": "^10.2.0",
|
|
97
|
+
"prompts": "^2.4.2",
|
|
98
|
+
"proper-lockfile": "^4.1.2",
|
|
99
|
+
"which": "^7.0.0",
|
|
100
|
+
"write-file-atomic": "^8.0.0",
|
|
101
|
+
"@dsh-workbench/shared": "1.0.0-beta.0",
|
|
102
|
+
"@dsh-workbench/adapters-default": "1.0.0-beta.0"
|
|
103
|
+
},
|
|
104
|
+
"license": "MIT",
|
|
105
|
+
"repository": {
|
|
106
|
+
"type": "git",
|
|
107
|
+
"url": "git+https://github.com/novaeth/dsh-workbench.git",
|
|
108
|
+
"directory": "packages/core"
|
|
109
|
+
},
|
|
110
|
+
"homepage": "https://github.com/novaeth/dsh-workbench#readme",
|
|
111
|
+
"bugs": {
|
|
112
|
+
"url": "https://github.com/novaeth/dsh-workbench/issues"
|
|
95
113
|
},
|
|
96
114
|
"scripts": {
|
|
97
115
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
|
@@ -106,6 +124,8 @@
|
|
|
106
124
|
"test": "vitest run",
|
|
107
125
|
"coverage": "vitest run --coverage",
|
|
108
126
|
"dev": "node scripts/dev.mjs",
|
|
109
|
-
"
|
|
127
|
+
"dev:desktop": "node scripts/dev.mjs --desktop",
|
|
128
|
+
"build:types": "node scripts/build-types.mjs",
|
|
129
|
+
"check:adapter-defaults": "node scripts/check-adapter-defaults.mjs"
|
|
110
130
|
}
|
|
111
131
|
}
|
package/preset/diy.patch.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Agent preset workbench-diy:DIY 模式。**这个文件是生成的**,别手改 ——
|
|
2
|
-
# 改 packages/
|
|
2
|
+
# 改 packages/core/scripts/gen-diy-preset.mjs 再重跑它。
|
|
3
3
|
#
|
|
4
4
|
# 它从 dsh 出厂那份 standard.patch.yml 派生(整表 plugins 归 dsh 管,手抄会漂),
|
|
5
5
|
# 只叠加三处差分:DIY skill 目录、tool-cordis、plugin-manager 打开。
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
# 两个 profile 共用同一份会话历史。工作台要提供自己的定制工具,等于一个
|
|
9
9
|
# 独立的 agent 环境,共享会话没有意义 —— 这三行把数据分开。
|
|
10
10
|
#
|
|
11
|
-
#
|
|
12
|
-
# 会话
|
|
13
|
-
# 工作区
|
|
14
|
-
# 附件
|
|
11
|
+
# 隔离后(默认 profile;新 profile 由 DSH_WORKBENCH_HOME 指到自己的根):
|
|
12
|
+
# 会话 $DSH_HOME/workbench/sessions/
|
|
13
|
+
# 工作区 $DSH_HOME/workbench/storages/ (workspace 走 storage-domain)
|
|
14
|
+
# 附件 $DSH_HOME/workbench/attachments/v1/
|
|
15
15
|
# 有意不隔离:
|
|
16
16
|
# 凭据 ~/.dsh/.credentials.yaml (两边共用同一把 API key)
|
|
17
17
|
#
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
- id: session-persistence-jsonl
|
|
23
23
|
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
24
24
|
config:
|
|
25
|
-
root: !!js dshHomePath('workbench/sessions'
|
|
25
|
+
root: !!js (process.env.DSH_WORKBENCH_HOME ?? dshHomePath('workbench')) + '/sessions'
|
|
26
26
|
|
|
27
27
|
- id: storage-json
|
|
28
28
|
name: '@deepseek-ai/dsh-storage-json'
|
|
29
29
|
config:
|
|
30
|
-
root: !!js dshHomePath('workbench/storages'
|
|
30
|
+
root: !!js (process.env.DSH_WORKBENCH_HOME ?? dshHomePath('workbench')) + '/storages'
|
|
31
31
|
|
|
32
32
|
- id: attachment-local
|
|
33
33
|
name: '@deepseek-ai/dsh-attachment-local'
|
|
34
34
|
config:
|
|
35
|
-
dshHome: !!js dshHomePath('workbench')
|
|
35
|
+
dshHome: !!js process.env.DSH_WORKBENCH_HOME ?? dshHomePath('workbench')
|
|
36
36
|
|
|
37
37
|
# 可写根:**无会话**的插件命令(市场装模块、自举跑的那几条)回落到它。
|
|
38
38
|
#
|
|
@@ -43,4 +43,4 @@
|
|
|
43
43
|
- id: sandbox-policy
|
|
44
44
|
config:
|
|
45
45
|
mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'
|
|
46
|
-
workspaceRoot: !!js dshHomePath('workbench')
|
|
46
|
+
workspaceRoot: !!js process.env.DSH_WORKBENCH_HOME ?? dshHomePath('workbench')
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# 插件发起的调用**没有会话**,于是回落到部署策略;dsh-base 出厂那一条写的是
|
|
6
6
|
# `workspaceRoot: !!js process.cwd()` —— 而安装目标是 `$DSH_HOME/workbench/...`,
|
|
7
7
|
# 不在启动目录下面,沙箱拒写(实测 EPERM:mkdir ~/.npm/_cacache、mkdir
|
|
8
|
-
# $DSH_HOME/workbench/...,见
|
|
8
|
+
# $DSH_HOME/workbench/...,见 内部设计记录 第 10.3 节)。
|
|
9
9
|
# 症状:自动安装死在第一步,界面只能退化成"让用户去终端抄一条命令" ——
|
|
10
10
|
# 终端没有沙箱,抄过去反而能跑,于是这个缺口一直看不出来。
|
|
11
11
|
#
|
|
@@ -23,4 +23,4 @@
|
|
|
23
23
|
- id: sandbox-policy
|
|
24
24
|
config:
|
|
25
25
|
mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'
|
|
26
|
-
workspaceRoot: !!js dshHomePath('workbench')
|
|
26
|
+
workspaceRoot: !!js process.env.DSH_WORKBENCH_HOME ?? dshHomePath('workbench')
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const home = process.env.DSH_HOME?.trim() || join(homedir(), '.dsh');
|
|
8
|
+
const sourceName = process.env.WB_SOURCE_PROFILE?.trim() || 'web';
|
|
9
|
+
const targetName = process.env.WB_TARGET_PROFILE?.trim() || '';
|
|
10
|
+
const sourceDir = join(home, 'profiles', sourceName);
|
|
11
|
+
const targetDir = join(home, 'profiles', targetName);
|
|
12
|
+
const sourceCandidate = join(home, sourceName);
|
|
13
|
+
const sourcePatchForHome = join(sourceDir, 'cordis.patch.yml');
|
|
14
|
+
const sourcePatchText = existsSync(sourcePatchForHome) ? readText(sourcePatchForHome) : '';
|
|
15
|
+
const sourceHasIsolation = /id:\s*session-persistence-jsonl/.test(sourcePatchText);
|
|
16
|
+
const sourceHome =
|
|
17
|
+
process.env.WB_SOURCE_HOME?.trim() ||
|
|
18
|
+
(!sourceHasIsolation
|
|
19
|
+
? home
|
|
20
|
+
: sourcePatchText.includes('DSH_WORKBENCH_HOME') && sourceName !== 'workbench'
|
|
21
|
+
? sourceCandidate
|
|
22
|
+
: join(home, 'workbench'));
|
|
23
|
+
const targetHome = process.env.DSH_WORKBENCH_HOME?.trim() || join(home, targetName);
|
|
24
|
+
const copySettings = process.env.WB_COPY_SETTINGS === '1';
|
|
25
|
+
const copyPlugins = process.env.WB_COPY_PLUGINS === '1';
|
|
26
|
+
const copyProjects = process.env.WB_COPY_PROJECTS === '1';
|
|
27
|
+
const copySessions = process.env.WB_COPY_SESSIONS === '1';
|
|
28
|
+
|
|
29
|
+
const PROFILE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
30
|
+
const ISOLATION_IDS = new Set([
|
|
31
|
+
'session-persistence-jsonl',
|
|
32
|
+
'storage-json',
|
|
33
|
+
'attachment-local',
|
|
34
|
+
'sandbox-policy',
|
|
35
|
+
]);
|
|
36
|
+
const ASSET_MAX_BYTES = 8 * 1024 * 1024;
|
|
37
|
+
const ASSET_MAX_FILES = 500;
|
|
38
|
+
const ASSET_SKIP = new Set(['node_modules', '.git', '.DS_Store']);
|
|
39
|
+
|
|
40
|
+
function say(message) {
|
|
41
|
+
process.stdout.write(`→ ${message}\n`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fail(message) {
|
|
45
|
+
process.stderr.write(`clone-profile: ${message}\n`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!PROFILE_NAME.test(sourceName)) fail(`来源 profile 名不合法:${sourceName}`);
|
|
50
|
+
if (!PROFILE_NAME.test(targetName)) fail(`目标 profile 名不合法:${targetName}`);
|
|
51
|
+
if (sourceName === targetName) fail('来源和目标不能是同一个 profile');
|
|
52
|
+
if (!existsSync(join(sourceDir, 'package.json'))) fail(`没有来源 profile:${sourceDir}`);
|
|
53
|
+
if (!existsSync(targetDir)) fail(`目标 profile 还没建好:${targetDir}`);
|
|
54
|
+
|
|
55
|
+
function readText(file) {
|
|
56
|
+
return readFileSync(file, 'utf8');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (copySettings && !copyPlugins) {
|
|
60
|
+
const refs = localPluginRefs();
|
|
61
|
+
if (refs > 0) {
|
|
62
|
+
fail(`设置里有 ${refs} 个本地插件文件引用;不能只复制设置不复制插件(会指向不存在的文件)。要么一起复制插件,要么取消设置。`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseBlocks(text) {
|
|
67
|
+
const lines = text.split('\n');
|
|
68
|
+
const starts = [];
|
|
69
|
+
lines.forEach((line, index) => {
|
|
70
|
+
if (/^- /.test(line) || line === '-') starts.push(index);
|
|
71
|
+
});
|
|
72
|
+
const blocks = [];
|
|
73
|
+
for (let i = 0; i < starts.length; i += 1) {
|
|
74
|
+
const from = starts[i];
|
|
75
|
+
const to = i + 1 < starts.length ? starts[i + 1] : lines.length;
|
|
76
|
+
let end = to;
|
|
77
|
+
while (end > from && (lines[end - 1] ?? '').trim() === '') end -= 1;
|
|
78
|
+
const body = lines.slice(from, end).join('\n');
|
|
79
|
+
if (body.trim() === '') continue;
|
|
80
|
+
const first = body.split('\n')[0] ?? '';
|
|
81
|
+
const id = /^- id:[ \t]*"?([^"\s#]+)/.exec(first)?.[1];
|
|
82
|
+
const insert = id === undefined && /^- insert:[ \t]*$/.test(first);
|
|
83
|
+
const nested = body
|
|
84
|
+
.split('\n')
|
|
85
|
+
.map((line) => /^[ \t]+-[ \t]*id:[ \t]*"?([^"\s#]+)/.exec(line)?.[1])
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
const key = id !== undefined ? `id:${id}` : insert ? `insert:${nested.join(', ')}` : `block:${String(i)}`;
|
|
88
|
+
blocks.push({ key, id: id ?? nested.join(', ') ?? key, insert, body });
|
|
89
|
+
}
|
|
90
|
+
return blocks;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function namesOf(body) {
|
|
94
|
+
return body
|
|
95
|
+
.split('\n')
|
|
96
|
+
.map((line) => /^[ \t]*-?[ \t]*name:[ \t]*['"]?([^'"\s#]+)/.exec(line)?.[1])
|
|
97
|
+
.filter((name) => name !== undefined && (name.startsWith('./') || name.startsWith('../') || name.startsWith('file://') || isAbsolute(name)));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function insideProfile(dir, ref) {
|
|
101
|
+
if (ref.startsWith('file://')) return null;
|
|
102
|
+
if (!ref.startsWith('./') && !ref.startsWith('../') && !isAbsolute(ref)) return null;
|
|
103
|
+
const abs = resolve(dir, ref);
|
|
104
|
+
const rel = relative(dir, abs);
|
|
105
|
+
if (rel === '' || rel === '..' || rel.startsWith(`..${requireSep()}`) || isAbsolute(rel)) return null;
|
|
106
|
+
return { rel: rel.split(requireSep()).join('/'), abs };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function requireSep() {
|
|
110
|
+
return process.platform === 'win32' ? '\\' : '/';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function copyFileAsset(source, target, budget) {
|
|
114
|
+
const stat = statSync(source);
|
|
115
|
+
if (stat.isSymbolicLink() || !stat.isFile()) return false;
|
|
116
|
+
if (stat.size > ASSET_MAX_BYTES) return false;
|
|
117
|
+
budget.bytes += stat.size;
|
|
118
|
+
if (budget.bytes > 32 * 1024 * 1024 || budget.files >= ASSET_MAX_FILES) return false;
|
|
119
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
120
|
+
cpSync(source, target);
|
|
121
|
+
budget.files += 1;
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function copyDirAsset(source, target, budget) {
|
|
126
|
+
const walk = (dir) => {
|
|
127
|
+
for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
128
|
+
if (ASSET_SKIP.has(entry.name)) continue;
|
|
129
|
+
const abs = join(dir, entry.name);
|
|
130
|
+
if (entry.isSymbolicLink()) return false;
|
|
131
|
+
if (entry.isDirectory()) {
|
|
132
|
+
if (!walk(abs)) return false;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (!entry.isFile()) continue;
|
|
136
|
+
const rel = relative(source, abs);
|
|
137
|
+
if (!copyFileAsset(abs, join(target, rel), budget)) return false;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
};
|
|
141
|
+
return walk(source);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function localPluginRefs() {
|
|
145
|
+
const sourcePatch = join(sourceDir, 'cordis.patch.yml');
|
|
146
|
+
if (!existsSync(sourcePatch)) return 0;
|
|
147
|
+
const seen = new Set();
|
|
148
|
+
for (const block of parseBlocks(readText(sourcePatch))) {
|
|
149
|
+
if (!block.insert) continue;
|
|
150
|
+
for (const ref of namesOf(block.body)) {
|
|
151
|
+
const located = insideProfile(sourceDir, ref);
|
|
152
|
+
if (located !== null) seen.add(located.rel);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return seen.size;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function rewritePaths(body) {
|
|
159
|
+
return body.replace(/(dshHomePath\(\s*['"])workbench(?=[/'"])/g, `$1${targetName}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function copySettingRows() {
|
|
163
|
+
const sourcePatch = join(sourceDir, 'cordis.patch.yml');
|
|
164
|
+
const targetPatch = join(targetDir, 'cordis.patch.yml');
|
|
165
|
+
if (!existsSync(sourcePatch)) {
|
|
166
|
+
say('来源没有 cordis.patch.yml,跳过设置复制');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const sourceBlocks = parseBlocks(readText(sourcePatch));
|
|
170
|
+
const initial = existsSync(targetPatch) ? readText(targetPatch) : '';
|
|
171
|
+
let current = initial.replace(/^\s*\[\]\s*$/m, '');
|
|
172
|
+
const targetKeys = new Set(parseBlocks(current).map((block) => block.key));
|
|
173
|
+
const copied = [];
|
|
174
|
+
const skipped = [];
|
|
175
|
+
for (const block of sourceBlocks) {
|
|
176
|
+
if (ISOLATION_IDS.has(block.id) || targetKeys.has(block.key)) {
|
|
177
|
+
skipped.push(block.id);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const body = rewritePaths(block.body);
|
|
181
|
+
current = `${current.replace(/\s+$/, '')}\n\n${body}\n`;
|
|
182
|
+
writeFileSync(targetPatch, current, 'utf8');
|
|
183
|
+
targetKeys.add(block.key);
|
|
184
|
+
copied.push(block.id);
|
|
185
|
+
}
|
|
186
|
+
say(`设置行:复制 ${copied.length},跳过 ${skipped.length}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function copyPluginAssets() {
|
|
190
|
+
const sourcePatch = join(sourceDir, 'cordis.patch.yml');
|
|
191
|
+
if (!existsSync(sourcePatch)) return;
|
|
192
|
+
const budget = { bytes: 0, files: 0 };
|
|
193
|
+
const seen = new Set();
|
|
194
|
+
let copied = 0;
|
|
195
|
+
for (const block of parseBlocks(readText(sourcePatch))) {
|
|
196
|
+
if (!block.insert || ISOLATION_IDS.has(block.id)) continue;
|
|
197
|
+
for (const ref of namesOf(block.body)) {
|
|
198
|
+
const located = insideProfile(sourceDir, ref);
|
|
199
|
+
if (located === null || seen.has(located.rel)) continue;
|
|
200
|
+
seen.add(located.rel);
|
|
201
|
+
const source = join(sourceDir, located.rel);
|
|
202
|
+
const target = join(targetDir, located.rel);
|
|
203
|
+
if (!existsSync(source)) {
|
|
204
|
+
say(`缺文件,跳过:${located.rel}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const stat = statSync(source);
|
|
208
|
+
const ok = stat.isDirectory()
|
|
209
|
+
? copyDirAsset(source, target, budget)
|
|
210
|
+
: copyFileAsset(source, target, budget);
|
|
211
|
+
if (ok) copied += 1;
|
|
212
|
+
else say(`文件太大或含符号链接,跳过:${located.rel}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
say(`本地插件文件:复制 ${copied} 个`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function copyProjectList() {
|
|
219
|
+
const source = join(sourceHome, 'storages', 'workspace.json');
|
|
220
|
+
if (!existsSync(source)) {
|
|
221
|
+
say('来源没有项目列表,跳过');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const target = join(targetHome, 'storages', 'workspace.json');
|
|
225
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
226
|
+
cpSync(source, target);
|
|
227
|
+
say('项目列表:已复制');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function copySessionData() {
|
|
231
|
+
const source = join(sourceHome, 'sessions');
|
|
232
|
+
if (!existsSync(source)) {
|
|
233
|
+
say('来源没有会话记录,跳过');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const target = join(targetHome, 'sessions');
|
|
237
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
238
|
+
cpSync(source, target, { recursive: true });
|
|
239
|
+
say('会话记录:已复制');
|
|
240
|
+
const attachments = join(sourceHome, 'attachments');
|
|
241
|
+
if (existsSync(attachments)) cpSync(attachments, join(targetHome, 'attachments'), { recursive: true });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function mergeDependencies() {
|
|
245
|
+
const sourceManifest = JSON.parse(readText(join(sourceDir, 'package.json')));
|
|
246
|
+
const targetManifest = JSON.parse(readText(join(targetDir, 'package.json')));
|
|
247
|
+
const sourceDeps = sourceManifest.dependencies ?? {};
|
|
248
|
+
const targetDeps = targetManifest.dependencies ?? {};
|
|
249
|
+
const merged = { ...targetDeps };
|
|
250
|
+
for (const [name, spec] of Object.entries(sourceDeps)) {
|
|
251
|
+
if (name === '@dsh-workbench/core') continue;
|
|
252
|
+
if (!Object.hasOwn(merged, name)) merged[name] = spec;
|
|
253
|
+
}
|
|
254
|
+
targetManifest.dependencies = merged;
|
|
255
|
+
const tmp = `${join(targetDir, 'package.json')}.wb-clone`;
|
|
256
|
+
writeFileSync(tmp, `${JSON.stringify(targetManifest, null, 2)}\n`, 'utf8');
|
|
257
|
+
renameSync(tmp, join(targetDir, 'package.json'));
|
|
258
|
+
say(`依赖:并入 ${Object.keys(merged).length - Object.keys(targetDeps).length} 项`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
mkdirSync(targetDir, { recursive: true });
|
|
262
|
+
mkdirSync(targetHome, { recursive: true });
|
|
263
|
+
if (copySettings) copySettingRows();
|
|
264
|
+
if (copyPlugins) copyPluginAssets();
|
|
265
|
+
mergeDependencies();
|
|
266
|
+
if (copyProjects) copyProjectList();
|
|
267
|
+
if (copySessions) copySessionData();
|
|
268
|
+
say('完成');
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import prompts from 'prompts';
|
|
9
|
+
|
|
10
|
+
const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
11
|
+
const HOME = process.env.DSH_HOME?.trim() || join(homedir(), '.dsh');
|
|
12
|
+
const PROFILES_DIR = join(HOME, 'profiles');
|
|
13
|
+
const PROFILE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
14
|
+
|
|
15
|
+
function say(message) {
|
|
16
|
+
process.stdout.write(`${message}\n`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function fail(message) {
|
|
20
|
+
process.stderr.write(`create-workbench: ${message}\n`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function onCancel() {
|
|
25
|
+
process.stdout.write('\n已取消。\n');
|
|
26
|
+
process.exit(130);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function listProfiles() {
|
|
30
|
+
try {
|
|
31
|
+
return readdirSync(PROFILES_DIR, { withFileTypes: true })
|
|
32
|
+
.filter((entry) => entry.isDirectory() && existsSync(join(PROFILES_DIR, entry.name, 'package.json')))
|
|
33
|
+
.map((entry) => entry.name)
|
|
34
|
+
.sort((a, b) => a.localeCompare(b));
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function uniqueName(base) {
|
|
41
|
+
if (!existsSync(join(PROFILES_DIR, base))) return base;
|
|
42
|
+
for (let index = 2; index < 1000; index += 1) {
|
|
43
|
+
const candidate = `${base}${index}`;
|
|
44
|
+
if (!existsSync(join(PROFILES_DIR, candidate))) return candidate;
|
|
45
|
+
}
|
|
46
|
+
fail('找不到可用的新名字,请手动输入一个。');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function nameProblem(value, source, profiles) {
|
|
50
|
+
const name = value.trim();
|
|
51
|
+
if (name === '') return '名字不能为空';
|
|
52
|
+
if (!PROFILE_NAME.test(name)) return '只用字母、数字、点、下划线或短横线,且以字母或数字开头';
|
|
53
|
+
if (name === source) return '不能和来源 profile 同名';
|
|
54
|
+
if (profiles.includes(name) || existsSync(join(PROFILES_DIR, name))) return `已经有 profile:${name}`;
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function runSetup(args) {
|
|
59
|
+
const child = spawnSync('bash', [join(PKG_ROOT, 'bin', 'dsh-workbench'), ...args], { stdio: 'inherit' });
|
|
60
|
+
if (child.error !== undefined) fail(child.error.message);
|
|
61
|
+
process.exit(child.status ?? 1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
65
|
+
fail('这里需要交互终端。脚本或 CI 里请用:setup --from web --profile <名字>');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const profiles = listProfiles();
|
|
69
|
+
|
|
70
|
+
if (profiles.length === 0) {
|
|
71
|
+
say('这台机器还没有 profile;用 dsh 出厂的 web 模板建一个空工作台。');
|
|
72
|
+
const nameAnswer = await prompts(
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
name: 'name',
|
|
76
|
+
message: '新工作台叫什么?',
|
|
77
|
+
initial: uniqueName('workbench'),
|
|
78
|
+
validate: (value) => nameProblem(String(value), '', profiles) ?? true,
|
|
79
|
+
},
|
|
80
|
+
{ onCancel },
|
|
81
|
+
);
|
|
82
|
+
const name = String(nameAnswer.name).trim();
|
|
83
|
+
const confirmAnswer = await prompts(
|
|
84
|
+
{
|
|
85
|
+
type: 'confirm',
|
|
86
|
+
name: 'ok',
|
|
87
|
+
message: `创建 ${name}(dsh 出厂 web 模板,不复制设置)?`,
|
|
88
|
+
initial: true,
|
|
89
|
+
},
|
|
90
|
+
{ onCancel },
|
|
91
|
+
);
|
|
92
|
+
if (!confirmAnswer.ok) {
|
|
93
|
+
say('已取消。');
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
runSetup(['setup', '--profile', name]);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const defaultSource = profiles.includes('web') ? 'web' : profiles[0];
|
|
100
|
+
const sourceAnswer = await prompts(
|
|
101
|
+
{
|
|
102
|
+
type: 'select',
|
|
103
|
+
name: 'source',
|
|
104
|
+
message: '用哪个 profile 当模板?',
|
|
105
|
+
choices: profiles.map((name) => ({ title: name, value: name })),
|
|
106
|
+
initial: Math.max(0, profiles.indexOf(defaultSource)),
|
|
107
|
+
},
|
|
108
|
+
{ onCancel },
|
|
109
|
+
);
|
|
110
|
+
const source = sourceAnswer.source;
|
|
111
|
+
|
|
112
|
+
const defaultName = 'workbench';
|
|
113
|
+
const nameAnswer = await prompts(
|
|
114
|
+
{
|
|
115
|
+
type: 'text',
|
|
116
|
+
name: 'name',
|
|
117
|
+
message: '新工作台叫什么?',
|
|
118
|
+
initial: defaultName,
|
|
119
|
+
validate: (value) => nameProblem(String(value), source, profiles) ?? true,
|
|
120
|
+
},
|
|
121
|
+
{ onCancel },
|
|
122
|
+
);
|
|
123
|
+
const name = String(nameAnswer.name).trim();
|
|
124
|
+
|
|
125
|
+
const copyAnswer = await prompts(
|
|
126
|
+
{
|
|
127
|
+
type: 'multiselect',
|
|
128
|
+
name: 'copy',
|
|
129
|
+
message: `从 ${source} 复制哪些内容?`,
|
|
130
|
+
instructions: '空格选择 · 回车确认',
|
|
131
|
+
choices: [
|
|
132
|
+
{ title: '设置(模型、主题等)', value: 'settings', selected: true },
|
|
133
|
+
{ title: '本地插件文件', value: 'plugins', selected: true },
|
|
134
|
+
{ title: '项目列表', value: 'projects', selected: true },
|
|
135
|
+
{ title: '会话记录(可选,可能很多)', value: 'sessions', selected: false },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{ onCancel },
|
|
139
|
+
);
|
|
140
|
+
const copy = new Set(copyAnswer.copy ?? []);
|
|
141
|
+
if (copy.has('settings') && !copy.has('plugins')) {
|
|
142
|
+
copy.add('plugins');
|
|
143
|
+
say('设置行引用的本地插件会一起复制(否则配置会指向不存在的文件)。');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const confirmAnswer = await prompts(
|
|
147
|
+
{
|
|
148
|
+
type: 'confirm',
|
|
149
|
+
name: 'ok',
|
|
150
|
+
message: `创建 ${name}(来源 ${source},复制:${[...copy].join('、') || '无'})?`,
|
|
151
|
+
initial: true,
|
|
152
|
+
},
|
|
153
|
+
{ onCancel },
|
|
154
|
+
);
|
|
155
|
+
if (!confirmAnswer.ok) {
|
|
156
|
+
say('已取消。');
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const args = ['setup', '--from', source, '--profile', name];
|
|
161
|
+
if (copy.has('sessions')) args.push('--with-sessions');
|
|
162
|
+
if (!copy.has('settings')) args.push('--no-settings');
|
|
163
|
+
if (!copy.has('plugins')) args.push('--no-plugins');
|
|
164
|
+
if (!copy.has('projects')) args.push('--no-projects');
|
|
165
|
+
|
|
166
|
+
runSetup(args);
|