relay-dsh-plugin-session-import 0.1.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 +11 -0
- package/README.zh.md +10 -0
- package/SPEC.md +52 -0
- package/cordis.patch.yml +3 -0
- package/docs/images/session-import-rail-menu.jpg +0 -0
- package/docs/images/session-import-wide-menu.jpg +0 -0
- package/docs/spec/acceptance.md +21 -0
- package/docs/spec/ui-acceptance.md +23 -0
- package/lib/client.js +126 -0
- package/lib/client.js.map +1 -0
- package/lib/contracts.d.ts +30 -0
- package/lib/contracts.js +1 -0
- package/lib/host-plugin.js +12 -0
- package/lib/host-plugin.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Boboyang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Relay DSH Session Import
|
|
2
|
+
|
|
3
|
+
Provider-neutral session import hub for DeepSeek Harness. It contributes one
|
|
4
|
+
sidebar action and a typed provider slot; import implementations stay in their
|
|
5
|
+
provider plugins.
|
|
6
|
+
|
|
7
|
+
See [SPEC.md](./SPEC.md) and [delivery acceptance](./docs/spec/acceptance.md).
|
|
8
|
+
|
|
9
|
+
Verified in official DSH `0.1.1-rc.2` with Codex and Claude providers:
|
|
10
|
+
[wide sidebar](./docs/images/session-import-wide-menu.jpg) and
|
|
11
|
+
[collapsed sidebar](./docs/images/session-import-rail-menu.jpg).
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Relay DSH 会话导入中心
|
|
2
|
+
|
|
3
|
+
面向 DeepSeek Harness 的中立会话导入入口。它只提供一个侧栏入口和类型化
|
|
4
|
+
Provider 插槽,Codex、Claude 等插件继续拥有各自的扫描与导入流程。
|
|
5
|
+
|
|
6
|
+
详见 [SPEC.md](./SPEC.md) 与[交付验收](./docs/spec/acceptance.md)。
|
|
7
|
+
|
|
8
|
+
已在官方 DSH `0.1.1-rc.2` 中同时安装 Codex、Claude Provider 验证:
|
|
9
|
+
[展开侧栏](./docs/images/session-import-wide-menu.jpg)与
|
|
10
|
+
[折叠侧栏](./docs/images/session-import-rail-menu.jpg)。
|
package/SPEC.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Session Import Hub Specification
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`relay-dsh-plugin-session-import` provides one provider-neutral session import
|
|
6
|
+
entry in the DSH sidebar. Provider plugins own discovery, selection, import,
|
|
7
|
+
progress, and result behavior; the hub owns only aggregation and navigation.
|
|
8
|
+
|
|
9
|
+
## Composition Contract
|
|
10
|
+
|
|
11
|
+
- The hub registers one `relay-session-import-hub` entry in the supported
|
|
12
|
+
`sidebar.footer.action` list slot.
|
|
13
|
+
- The hub declares the root-scoped list slot
|
|
14
|
+
`relay.session-import.provider`.
|
|
15
|
+
- The package exports the canonical slot-definition type. Each provider merges
|
|
16
|
+
that type into its local DSH `SlotMap`, keeping one contract while avoiding
|
|
17
|
+
package-manager-specific TypeScript module identities.
|
|
18
|
+
- A provider contribution is renderless while idle. It registers a localized
|
|
19
|
+
descriptor on mount and renders only its own import dialog when selected.
|
|
20
|
+
- Provider ids are stable and unique. Lower `order` values appear first.
|
|
21
|
+
- The hub is hidden while no provider is registered.
|
|
22
|
+
- Provider unload removes its row immediately. Removing the final provider
|
|
23
|
+
closes the menu and removes the trigger.
|
|
24
|
+
|
|
25
|
+
## User Interface
|
|
26
|
+
|
|
27
|
+
- Wide sidebar: one 42px row with the standard import/download glyph and the
|
|
28
|
+
label `Import sessions...` / `导入会话...`.
|
|
29
|
+
- Collapsed sidebar: one 36px circular icon button with a tooltip.
|
|
30
|
+
- The provider menu opens above the wide trigger and to the right of the rail
|
|
31
|
+
trigger.
|
|
32
|
+
- Each provider menu row contains its provider mark and an explicit localized
|
|
33
|
+
action label. The hub trigger never combines multiple provider marks.
|
|
34
|
+
- Selection closes the menu before opening the provider-owned dialog.
|
|
35
|
+
|
|
36
|
+
## Packaging
|
|
37
|
+
|
|
38
|
+
Provider packages depend on this package and add a uniquely identified Loader
|
|
39
|
+
row whose `name` is `relay-dsh-plugin-session-import`. Multiple rows are safe:
|
|
40
|
+
the host plugin is intentionally empty and DSH client modules are deduplicated
|
|
41
|
+
by package name. Provider client declarations inject this package so the hub
|
|
42
|
+
applies before provider contributions.
|
|
43
|
+
|
|
44
|
+
Local DSH development symlinks must preserve one consumer-root type identity
|
|
45
|
+
for official DSH peer packages. Provider typechecks pin `@deepseek-ai/*`
|
|
46
|
+
resolution to their own `node_modules` and enable `preserveSymlinks`.
|
|
47
|
+
|
|
48
|
+
## Non-goals
|
|
49
|
+
|
|
50
|
+
- Modifying official DSH source or Workspace menus.
|
|
51
|
+
- DOM injection or CSS selectors against DSH internals.
|
|
52
|
+
- Provider-specific scanning, persistence, or import policy.
|
package/cordis.patch.yml
ADDED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Delivery Acceptance
|
|
2
|
+
|
|
3
|
+
1. With no providers, the sidebar contains no session-import trigger.
|
|
4
|
+
2. With Codex only, one trigger opens one `Import from Codex` row.
|
|
5
|
+
3. With Claude only, one trigger opens one `Import from Claude` row.
|
|
6
|
+
4. With both providers, one trigger opens Codex then Claude rows.
|
|
7
|
+
5. Selecting a row closes the menu and opens only that provider's existing
|
|
8
|
+
Workspace selection dialog.
|
|
9
|
+
6. Unloading one provider removes only its row; unloading the last removes the
|
|
10
|
+
trigger.
|
|
11
|
+
7. The wide trigger is a full-width 42px text row and does not compete for
|
|
12
|
+
horizontal space with another import action.
|
|
13
|
+
8. The rail trigger is a 36px icon button with an accessible name and tooltip.
|
|
14
|
+
9. Keyboard Escape/outside-pointer behavior remains owned by the official DSH
|
|
15
|
+
`Menu` primitive.
|
|
16
|
+
10. Two provider Loader rows activate one browser hub module without duplicate
|
|
17
|
+
slot registration.
|
|
18
|
+
11. Typecheck, component tests, package tests, builds, and real DSH composition
|
|
19
|
+
all pass.
|
|
20
|
+
12. Desktop wide/rail screenshots show no overlap, clipping, or ambiguous
|
|
21
|
+
provider glyph composition.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# UI Acceptance Evidence
|
|
2
|
+
|
|
3
|
+
## Environment
|
|
4
|
+
|
|
5
|
+
- Official DeepSeek Harness `0.1.1-rc.2`, commit `b150a551`.
|
|
6
|
+
- Local production builds of `relay-dsh-plugin-session-import@0.1.0`,
|
|
7
|
+
`relay-dsh-plugin-codex`, and `relay-dsh-plugin-claude`.
|
|
8
|
+
- Isolated DSH `web` Profile at a 1415 by 900 browser viewport.
|
|
9
|
+
|
|
10
|
+
## Results
|
|
11
|
+
|
|
12
|
+
- The composed page contains exactly one `[data-session-import-hub]` trigger.
|
|
13
|
+
- The open menu contains exactly two ordered rows: `Import from Codex`, then
|
|
14
|
+
`Import from Claude`.
|
|
15
|
+
- Each row closes the menu and opens only its provider's existing import dialog.
|
|
16
|
+
- The wide trigger and upward menu do not overlap Settings or Workspace content.
|
|
17
|
+
- The 36px rail trigger exposes a tooltip; its right-side menu is not clipped.
|
|
18
|
+
|
|
19
|
+
## Screenshots
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+

|
package/lib/client.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "relay-dsh-plugin-session-import",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
//#region \0relay-css-module:./src/client/SessionImportHub.module.css.mjs
|
|
11
|
+
const css = ".GwK6rW_menuRoot{flex:auto;width:100%;min-width:0}.GwK6rW_menuRootRail{flex:none;width:36px}.GwK6rW_trigger{box-sizing:border-box;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;letter-spacing:0;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;margin:4px -2px;padding:0 10px 0 8px;font-size:14px;line-height:22px;display:flex;overflow:hidden}.GwK6rW_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.GwK6rW_trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.GwK6rW_triggerRail{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;margin:8px 0 2px;padding:0}.GwK6rW_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}";
|
|
12
|
+
const tagId = "relay-dsh-plugin-session-import/SessionImportHub.module.css";
|
|
13
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
14
|
+
const tag = document.createElement("style");
|
|
15
|
+
tag.dataset.plugin = "relay-dsh-plugin-session-import";
|
|
16
|
+
tag.dataset.pluginCss = tagId;
|
|
17
|
+
tag.textContent = css;
|
|
18
|
+
document.head.appendChild(tag);
|
|
19
|
+
}
|
|
20
|
+
var SessionImportHub_module_css_default = {
|
|
21
|
+
"label": "GwK6rW_label",
|
|
22
|
+
"menuRoot": "GwK6rW_menuRoot",
|
|
23
|
+
"menuRootRail": "GwK6rW_menuRootRail",
|
|
24
|
+
"trigger": "GwK6rW_trigger",
|
|
25
|
+
"triggerRail": "GwK6rW_triggerRail"
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/client/SessionImportHub.tsx
|
|
29
|
+
/** One provider-neutral footer action backed by provider-owned import flows. */
|
|
30
|
+
function SessionImportHub({ wide, renderSlot, t }) {
|
|
31
|
+
const records = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
32
|
+
const [providers, setProviders] = (0, react.useState)([]);
|
|
33
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
34
|
+
const publish = (0, react.useCallback)(() => {
|
|
35
|
+
setProviders([...records.current.values()].sort((left, right) => (left.order ?? 0) - (right.order ?? 0) || left.id.localeCompare(right.id)));
|
|
36
|
+
}, []);
|
|
37
|
+
const registerProvider = (0, react.useCallback)((provider) => {
|
|
38
|
+
if ([...records.current.values()].some((record) => record.id === provider.id)) throw new Error(`session import provider "${provider.id}" is already registered`);
|
|
39
|
+
const token = Symbol(provider.id);
|
|
40
|
+
records.current.set(token, {
|
|
41
|
+
...provider,
|
|
42
|
+
token
|
|
43
|
+
});
|
|
44
|
+
publish();
|
|
45
|
+
return () => {
|
|
46
|
+
if (!records.current.delete(token)) return;
|
|
47
|
+
publish();
|
|
48
|
+
};
|
|
49
|
+
}, [publish]);
|
|
50
|
+
(0, react.useEffect)(() => {
|
|
51
|
+
if (providers.length === 0) setOpen(false);
|
|
52
|
+
}, [providers.length]);
|
|
53
|
+
const items = providers.map((provider) => ({
|
|
54
|
+
id: provider.id,
|
|
55
|
+
label: provider.label,
|
|
56
|
+
icon: provider.icon
|
|
57
|
+
}));
|
|
58
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [renderSlot("relay.session-import.provider", { registerProvider }), providers.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
59
|
+
className: wide ? SessionImportHub_module_css_default.menuRoot : `${SessionImportHub_module_css_default.menuRoot} ${SessionImportHub_module_css_default.menuRootRail}`,
|
|
60
|
+
open,
|
|
61
|
+
onClose: () => {
|
|
62
|
+
setOpen(false);
|
|
63
|
+
},
|
|
64
|
+
items,
|
|
65
|
+
onSelect: (id) => {
|
|
66
|
+
const provider = providers.find((candidate) => candidate.id === id);
|
|
67
|
+
if (provider === void 0) return;
|
|
68
|
+
setOpen(false);
|
|
69
|
+
provider.open();
|
|
70
|
+
},
|
|
71
|
+
side: wide ? "top" : "right",
|
|
72
|
+
portal: true,
|
|
73
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
74
|
+
label: t("importSessions"),
|
|
75
|
+
side: "top",
|
|
76
|
+
delayMs: 500,
|
|
77
|
+
disabled: wide,
|
|
78
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
79
|
+
type: "button",
|
|
80
|
+
className: wide ? SessionImportHub_module_css_default.trigger : `${SessionImportHub_module_css_default.trigger} ${SessionImportHub_module_css_default.triggerRail}`,
|
|
81
|
+
"aria-label": t("importSessions"),
|
|
82
|
+
"aria-haspopup": "menu",
|
|
83
|
+
"aria-expanded": open,
|
|
84
|
+
"data-session-import-hub": "true",
|
|
85
|
+
onClick: () => {
|
|
86
|
+
setOpen((value) => !value);
|
|
87
|
+
},
|
|
88
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { size: wide ? 16 : 18 }), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
89
|
+
className: SessionImportHub_module_css_default.label,
|
|
90
|
+
children: t("importSessions")
|
|
91
|
+
})]
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
})] });
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/client/locales.ts
|
|
98
|
+
const en = { importSessions: "Import sessions..." };
|
|
99
|
+
const zh = { importSessions: "导入会话..." };
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/client/index.ts
|
|
102
|
+
const inject = ["slots", "locale"];
|
|
103
|
+
function apply(ctx) {
|
|
104
|
+
ctx.effect(() => ctx.locale.register("relay.session-import", {
|
|
105
|
+
zh,
|
|
106
|
+
en
|
|
107
|
+
}), "relay-session-import: dictionaries");
|
|
108
|
+
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
109
|
+
name: "sidebar.footer.action",
|
|
110
|
+
id: "relay-session-import-hub",
|
|
111
|
+
order: -10,
|
|
112
|
+
children: { "relay.session-import.provider": {
|
|
113
|
+
kind: "list",
|
|
114
|
+
scope: "root"
|
|
115
|
+
} },
|
|
116
|
+
locale: "relay.session-import"
|
|
117
|
+
}, SessionImportHub));
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
exports.apply = apply;
|
|
121
|
+
exports.inject = inject;
|
|
122
|
+
return module.exports;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["Menu","css","Tooltip","IconDownloadOutline16"],"sources":["../src/client/SessionImportHub.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport {\n IconDownloadOutline16,\n Menu,\n Tooltip,\n type MenuItem,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n PropsLocale,\n PropsRenderSlots,\n} from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SidebarFooterActionOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {\n SessionImportProviderDescriptor,\n SessionImportProviderOwnerProps,\n} from '../contracts.ts'\nimport type { SessionImportLocaleKey } from './locales.ts'\nimport css from './SessionImportHub.module.css'\n\ninterface RegisteredProvider extends SessionImportProviderDescriptor {\n token: symbol\n}\n\ntype Props = SidebarFooterActionOwnerProps\n & PropsRenderSlots<'relay.session-import.provider'>\n & PropsLocale<'relay.session-import'>\n\n/** One provider-neutral footer action backed by provider-owned import flows. */\nexport function SessionImportHub({ wide, renderSlot, t }: Props): ReactNode {\n const records = useRef(new Map<symbol, RegisteredProvider>())\n const [providers, setProviders] = useState<readonly RegisteredProvider[]>([])\n const [open, setOpen] = useState(false)\n\n const publish = useCallback(() => {\n setProviders([...records.current.values()].sort((left, right) =>\n (left.order ?? 0) - (right.order ?? 0) || left.id.localeCompare(right.id)))\n }, [])\n\n const registerProvider = useCallback<SessionImportProviderOwnerProps['registerProvider']>((provider) => {\n if ([...records.current.values()].some(record => record.id === provider.id)) {\n throw new Error(`session import provider \"${provider.id}\" is already registered`)\n }\n const token = Symbol(provider.id)\n records.current.set(token, { ...provider, token })\n publish()\n return () => {\n if (!records.current.delete(token)) return\n publish()\n }\n }, [publish])\n\n useEffect(() => {\n if (providers.length === 0) setOpen(false)\n }, [providers.length])\n\n const items: readonly MenuItem[] = providers.map(provider => ({\n id: provider.id,\n label: provider.label,\n icon: provider.icon,\n }))\n\n return (\n <>\n {renderSlot('relay.session-import.provider', { registerProvider })}\n {providers.length > 0 && (\n <Menu\n className={wide ? css.menuRoot : `${css.menuRoot} ${css.menuRootRail}`}\n open={open}\n onClose={() => { setOpen(false) }}\n items={items}\n onSelect={(id) => {\n const provider = providers.find(candidate => candidate.id === id)\n if (provider === undefined) return\n setOpen(false)\n provider.open()\n }}\n side={wide ? 'top' : 'right'}\n portal\n anchor={(\n <Tooltip label={t('importSessions')} side=\"top\" delayMs={500} disabled={wide}>\n <button\n type=\"button\"\n className={wide ? css.trigger : `${css.trigger} ${css.triggerRail}`}\n aria-label={t('importSessions')}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-session-import-hub=\"true\"\n onClick={() => { setOpen(value => !value) }}\n >\n <IconDownloadOutline16 size={wide ? 16 : 18} />\n {wide && <span className={css.label}>{t('importSessions')}</span>}\n </button>\n </Tooltip>\n )}\n />\n )}\n </>\n )\n}\n\nexport type { SessionImportLocaleKey }\n","export const en = {\n importSessions: 'Import sessions...',\n} as const\n\nexport const zh = {\n importSessions: '导入会话...',\n} satisfies Record<keyof typeof en, string>\n\nexport type SessionImportLocaleKey = keyof typeof en\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type { SidebarFooterActionOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type { SessionImportProviderSlotDefinition } from '../contracts.ts'\nimport { SessionImportHub } from './SessionImportHub.tsx'\nimport { en, zh, type SessionImportLocaleKey } from './locales.ts'\n\ntype SidebarFooterContractAnchor = SidebarFooterActionOwnerProps\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n 'relay.session-import.provider': SessionImportProviderSlotDefinition\n }\n interface LocaleNamespaceMap {\n 'relay.session-import': SessionImportLocaleKey\n }\n}\n\nexport const inject = ['slots', 'locale']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(\n () => ctx.locale.register('relay.session-import', { zh, en }),\n 'relay-session-import: dictionaries',\n )\n ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({\n name: 'sidebar.footer.action',\n id: 'relay-session-import-hub',\n order: -10,\n children: {\n 'relay.session-import.provider': { kind: 'list', scope: 'root' },\n },\n locale: 'relay.session-import',\n }, SessionImportHub))\n}\n\nexport type {\n SessionImportProviderDescriptor,\n SessionImportProviderOwnerProps,\n SessionImportProviderSlotDefinition,\n} from '../contracts.ts'\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/contracts.d.ts
|
|
4
|
+
/** One import implementation contributed by a provider plugin. */
|
|
5
|
+
interface SessionImportProviderDescriptor {
|
|
6
|
+
/** Stable provider identity, also used as the menu item id. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Localized menu label, for example "Import from Codex". */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Provider mark shown beside the explicit menu label. */
|
|
11
|
+
icon: ReactNode;
|
|
12
|
+
/** Deterministic menu ordering; lower values render first. */
|
|
13
|
+
order?: number;
|
|
14
|
+
/** Open the provider-owned import flow. */
|
|
15
|
+
open: () => void;
|
|
16
|
+
}
|
|
17
|
+
/** Owner share passed by the hub to each renderless provider contribution. */
|
|
18
|
+
interface SessionImportProviderOwnerProps {
|
|
19
|
+
/** Register while mounted and dispose the exact registration on unmount. */
|
|
20
|
+
registerProvider: (provider: SessionImportProviderDescriptor) => () => void;
|
|
21
|
+
}
|
|
22
|
+
/** Canonical slot definition consumers merge into their local DSH type graph. */
|
|
23
|
+
interface SessionImportProviderSlotDefinition {
|
|
24
|
+
kind: 'list';
|
|
25
|
+
scope: 'root';
|
|
26
|
+
owner: SessionImportProviderOwnerProps;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { SessionImportProviderDescriptor, SessionImportProviderOwnerProps, SessionImportProviderSlotDefinition };
|
|
30
|
+
//# sourceMappingURL=contracts.d.ts.map
|
package/lib/contracts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/host-plugin.ts
|
|
2
|
+
/** Package identity used by DSH Loader rows contributed by provider bundles. */
|
|
3
|
+
const name = "relay-dsh-plugin-session-import";
|
|
4
|
+
/**
|
|
5
|
+
* The host half is intentionally empty. Provider bundles may mount this row
|
|
6
|
+
* more than once; DSH deduplicates the browser client module by package name.
|
|
7
|
+
*/
|
|
8
|
+
function apply() {}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { apply, name };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=host-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-plugin.js","names":[],"sources":["../src/host-plugin.ts"],"sourcesContent":["/** Package identity used by DSH Loader rows contributed by provider bundles. */\nexport const name = 'relay-dsh-plugin-session-import'\n\n/**\n * The host half is intentionally empty. Provider bundles may mount this row\n * more than once; DSH deduplicates the browser client module by package name.\n */\nexport function apply(): void {}\n"],"mappings":";;AACA,MAAa,OAAO;;;;;AAMpB,SAAgB,QAAc,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "relay-dsh-plugin-session-import",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Provider-neutral session import hub for DeepSeek Harness plugins.",
|
|
5
|
+
"keywords": ["dsh-plugin", "deepseek-harness", "dsh", "session-import"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "lib/host-plugin.js",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/yangbobo2021/relay-dsh-plugin-session-import.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/yangbobo2021/relay-dsh-plugin-session-import#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/yangbobo2021/relay-dsh-plugin-session-import/issues"
|
|
16
|
+
},
|
|
17
|
+
"engines": { "node": ">=22.13" },
|
|
18
|
+
"publishConfig": { "access": "public" },
|
|
19
|
+
"scripts": {
|
|
20
|
+
"prepare:dsh": "bash scripts/link-dsh-development-peers.sh",
|
|
21
|
+
"prebuild": "npm run prepare:dsh && node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
|
|
22
|
+
"build": "tsdown --config tsdown.config.ts",
|
|
23
|
+
"postbuild": "node normalize-build.mjs",
|
|
24
|
+
"pretypecheck": "npm run prepare:dsh",
|
|
25
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
26
|
+
"test": "npm run prepare:dsh && vitest run test/*.spec.ts test/*.spec.tsx && node --test test/*.test.mjs",
|
|
27
|
+
"verify": "npm run typecheck && npm test && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./lib/host-plugin.js",
|
|
31
|
+
"./client": "./lib/client.js",
|
|
32
|
+
"./contracts": {
|
|
33
|
+
"types": "./lib/contracts.d.ts",
|
|
34
|
+
"default": "./lib/contracts.js"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"README.md",
|
|
40
|
+
"README.zh.md",
|
|
41
|
+
"SPEC.md",
|
|
42
|
+
"docs/spec",
|
|
43
|
+
"docs/images",
|
|
44
|
+
"cordis.patch.yml",
|
|
45
|
+
"lib/client.js",
|
|
46
|
+
"lib/client.js.map",
|
|
47
|
+
"lib/contracts.js",
|
|
48
|
+
"lib/contracts.js.map",
|
|
49
|
+
"lib/contracts.d.ts",
|
|
50
|
+
"lib/host-plugin.js",
|
|
51
|
+
"lib/host-plugin.js.map"
|
|
52
|
+
],
|
|
53
|
+
"dsh": {
|
|
54
|
+
"client": {
|
|
55
|
+
"inject": [
|
|
56
|
+
"@deepseek-ai/dsh-client-locale",
|
|
57
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-primitives",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
61
|
+
],
|
|
62
|
+
"platform": "web"
|
|
63
|
+
},
|
|
64
|
+
"bundle": { "patch": "./cordis.patch.yml" }
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"react": "^18.2.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"react": { "optional": true }
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@testing-library/react": "^16.3.2",
|
|
74
|
+
"@types/react": "~18.3.1",
|
|
75
|
+
"@types/react-dom": "^18.3.7",
|
|
76
|
+
"jsdom": "^29.1.1",
|
|
77
|
+
"lightningcss": "1.32.0",
|
|
78
|
+
"react": "^18.2.0",
|
|
79
|
+
"react-dom": "^18.3.1",
|
|
80
|
+
"tsdown": "0.22.2",
|
|
81
|
+
"typescript": "6.0.3",
|
|
82
|
+
"vitest": "^4.1.8"
|
|
83
|
+
}
|
|
84
|
+
}
|