dsh-edge 0.1.3 → 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.i18n.yaml +6 -6
  2. package/README.md +25 -10
  3. package/README.zh.md +25 -10
  4. package/THIRD_PARTY_NOTICES.md +10019 -187
  5. package/dist/index.html +1 -1
  6. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +7 -7
  7. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +61 -61
  8. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +14 -14
  9. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +287 -287
  10. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +10 -10
  11. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +11 -11
  12. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +15 -15
  13. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +8 -8
  14. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +27 -27
  15. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +8 -8
  16. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +31 -31
  17. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +23 -23
  18. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +19 -19
  19. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +29 -29
  20. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +7 -7
  21. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +64 -64
  22. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +183 -183
  23. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +44 -44
  24. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +24 -24
  25. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +79 -79
  26. package/dist/plugins/dsh-edge-client-ui/client.js +68 -53
  27. package/package.json +22 -22
  28. package/scripts/activation.d.mts +34 -0
  29. package/scripts/activation.mjs +133 -0
  30. package/scripts/cli.d.mts +9 -0
  31. package/scripts/cli.mjs +66 -3
  32. package/scripts/dev.mjs +38 -0
  33. package/scripts/install.d.mts +8 -0
  34. package/scripts/install.mjs +95 -4
  35. package/scripts/legal-files.d.mts +23 -0
  36. package/scripts/legal-files.mjs +222 -40
  37. package/scripts/pnpm-invocation.d.mts +14 -0
  38. package/scripts/pnpm-invocation.mjs +25 -0
  39. package/scripts/publish.d.mts +25 -0
  40. package/scripts/publish.mjs +145 -0
  41. package/scripts/smoke-installed.mjs +27 -22
  42. package/scripts/verify-packed.mjs +8 -0
  43. package/scripts/wrangler-config-core.mjs +107 -0
  44. package/scripts/wrangler-config.d.mts +2 -0
  45. package/scripts/wrangler-config.mjs +9 -78
  46. package/worker/direct/index.js +1136 -1139
  47. package/worker/isolated/index.js +872 -875
  48. package/scripts/assemble-web.mjs +0 -230
  49. package/scripts/bundle.mjs +0 -86
@@ -1,230 +0,0 @@
1
- /** Assemble the upstream Web shell and client-plugin graph as Worker assets. */
2
-
3
- import { createHash } from 'node:crypto'
4
- import {
5
- cp,
6
- mkdir,
7
- readFile,
8
- readdir,
9
- rm,
10
- stat,
11
- writeFile,
12
- } from 'node:fs/promises'
13
- import { dirname, join, relative, resolve } from 'node:path'
14
- import { fileURLToPath } from 'node:url'
15
-
16
- const appRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
17
- const repoRoot = resolve(appRoot, '../..')
18
- const shellDist = join(repoRoot, 'apps/web/dist')
19
- const outputRoot = join(appRoot, 'dist')
20
- const deploymentPatches = [
21
- join(repoRoot, 'packages/bundle/base/cordis.patch.yml'),
22
- join(repoRoot, 'packages/bundle/web-app/cordis.patch.yml'),
23
- ]
24
- // Deployment-owned browser features use the same client-plugin contract but
25
- // intentionally stay out of upstream's generic Web composition.
26
- const edgeClientPackages = ['dsh-edge-client-ui']
27
-
28
- // HMR is useful only when the upstream Node host also runs its bundle watcher.
29
- // Edge deploys immutable, content-addressed static assets instead.
30
- const edgeExcludedPackages = new Set([
31
- // Requires the upstream Node-side bundle watcher.
32
- '@deepseek-ai/dsh-client-hmr',
33
- // These surfaces depend on generated Host remotes or writable Host settings
34
- // that the minimal Edge ApiProxy does not advertise yet. Keeping them out of
35
- // the graph is capability negotiation at assembly time; their upstream code
36
- // remains unchanged and can be restored with the matching server domain.
37
- '@deepseek-ai/dsh-cordis-client-runner',
38
- '@deepseek-ai/dsh-client-ui-cordis',
39
- '@deepseek-ai/dsh-client-ui-goal',
40
- '@deepseek-ai/dsh-client-ui-message-feedback',
41
- '@deepseek-ai/dsh-client-ui-plan',
42
- '@deepseek-ai/dsh-client-ui-settings-models',
43
- '@deepseek-ai/dsh-client-ui-settings-plugin-inventory',
44
- '@deepseek-ai/dsh-client-ui-settings-plugins',
45
- // Its header action calls the session.export endpoint, which Edge does not
46
- // implement. Keep the unavailable action out of the assembled browser.
47
- '@deepseek-ai/dsh-session-log-export',
48
- ])
49
- const shellStaticPackages = new Set(['@deepseek-ai/dsh-client-ui-primitives'])
50
- const assetSecurityHeaders = `/*
51
- Content-Security-Policy: frame-ancestors 'none'
52
- X-Frame-Options: DENY
53
- `
54
-
55
- function shortHash(input) {
56
- return createHash('sha1').update(input).digest('hex').slice(0, 12)
57
- }
58
-
59
- async function isDirectory(path) {
60
- try {
61
- return (await stat(path)).isDirectory()
62
- } catch {
63
- return false
64
- }
65
- }
66
-
67
- async function findPackageJsonFiles(root) {
68
- const found = []
69
- const visit = async (directory) => {
70
- for (const entry of await readdir(directory, { withFileTypes: true })) {
71
- if (entry.name === 'node_modules' || entry.name === 'lib') continue
72
- const path = join(directory, entry.name)
73
- if (entry.isDirectory()) {
74
- await visit(path)
75
- } else if (entry.name === 'package.json') {
76
- found.push(path)
77
- }
78
- }
79
- }
80
- await visit(root)
81
- return found
82
- }
83
-
84
- async function removeSourceMaps(root) {
85
- for (const entry of await readdir(root, { withFileTypes: true })) {
86
- const path = join(root, entry.name)
87
- if (entry.isDirectory()) {
88
- await removeSourceMaps(path)
89
- } else if (entry.name.endsWith('.map')) {
90
- await rm(path)
91
- }
92
- }
93
- }
94
-
95
- function deploymentPackageNames(patch) {
96
- const names = []
97
- for (const match of patch.matchAll(/^\s+name:\s+'([^']+)'\s*$/gm)) {
98
- if (!edgeExcludedPackages.has(match[1])) names.push(match[1])
99
- }
100
- return names
101
- }
102
-
103
- function clientBundleRelativePath(pkg) {
104
- const client = pkg.exports?.['./client']
105
- if (typeof client === 'string') return client
106
- if (client !== null && typeof client === 'object' && typeof client.default === 'string') {
107
- return client.default
108
- }
109
- throw new Error(`${pkg.name} is in the Web roster but exports no ./client bundle.`)
110
- }
111
-
112
- function injectBootManifest(html, graph) {
113
- const json = JSON.stringify(graph).replaceAll('<', '\\u003c')
114
- const script = `<script>window.__DSH_BOOT__ = ${json}</script>`
115
- const head = html.indexOf('<head>')
116
- return head === -1
117
- ? `${script}${html}`
118
- : `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
119
- }
120
-
121
- function injectOwnerSessionGuard(html) {
122
- const script = `<script>(() => {
123
- const originalFetch = window.fetch.bind(window)
124
- let redirecting = false
125
- window.fetch = async (...args) => {
126
- const input = args[0]
127
- const href = input instanceof Request ? input.url : String(input)
128
- const target = new URL(href, window.location.href)
129
- const response = await originalFetch(...args)
130
- if (!redirecting
131
- && response.status === 401
132
- && response.headers.get('www-authenticate') === 'DshEdgeOwner'
133
- && target.origin === window.location.origin
134
- && target.pathname.startsWith('/api/')) {
135
- redirecting = true
136
- window.location.replace('/login')
137
- }
138
- return response
139
- }
140
- })()</script>`
141
- const head = html.indexOf('<head>')
142
- return head === -1
143
- ? `${script}${html}`
144
- : `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
145
- }
146
-
147
- async function copyBundle(pkgPath, pkg, entries) {
148
- const declaration = pkg.dsh?.client
149
- if (declaration?.platform !== 'web') {
150
- throw new Error(`${pkg.name} is in the upstream Web roster but has no web dsh.client declaration.`)
151
- }
152
- const source = resolve(dirname(pkgPath), clientBundleRelativePath(pkg))
153
- const contents = await readFile(source)
154
- const rev = shortHash(contents)
155
- const destination = join(outputRoot, 'plugins', pkg.name, 'client.js')
156
- await mkdir(dirname(destination), { recursive: true })
157
- await writeFile(destination, contents)
158
-
159
- entries.push({
160
- id: pkg.name,
161
- url: `/plugins/${pkg.name}/client.js?rev=${rev}`,
162
- rev,
163
- ...(Array.isArray(declaration.inject) ? { inject: declaration.inject } : {}),
164
- ...(declaration.immediately === true ? { immediately: true } : {}),
165
- })
166
- }
167
-
168
- async function main() {
169
- if (!await isDirectory(shellDist)) {
170
- throw new Error('Upstream Web shell is not built. Run `pnpm --workspace-root run build:web` first.')
171
- }
172
-
173
- const packagesByName = new Map()
174
- for (const pkgPath of await findPackageJsonFiles(join(repoRoot, 'packages'))) {
175
- const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
176
- if (typeof pkg.name === 'string') packagesByName.set(pkg.name, { path: pkgPath, pkg })
177
- }
178
-
179
- const declared = []
180
- for (const patchPath of deploymentPatches) {
181
- declared.push(...deploymentPackageNames(await readFile(patchPath, 'utf8')))
182
- }
183
- declared.push(...edgeClientPackages)
184
- const roster = []
185
- const seen = new Set()
186
- for (const name of declared) {
187
- if (seen.has(name)) continue
188
- const record = packagesByName.get(name)
189
- // Vendor entries and package subpaths have no workspace package root; only
190
- // workspace packages can declare the client bundles assembled here.
191
- if (record === undefined) continue
192
- if (record.pkg.dsh?.client?.platform !== 'web') continue
193
- seen.add(name)
194
- roster.push(name)
195
- }
196
- await rm(outputRoot, { recursive: true, force: true })
197
- await cp(shellDist, outputRoot, { recursive: true })
198
- // Match the published upstream Web package: production assets do not ship
199
- // source maps, keeping the Worker upload compact without changing runtime JS.
200
- await removeSourceMaps(outputRoot)
201
-
202
- const entries = []
203
- for (const name of roster) {
204
- const record = packagesByName.get(name)
205
- if (record === undefined) throw new Error(`Cannot resolve upstream Web package ${name}.`)
206
- await copyBundle(record.path, record.pkg, entries)
207
- }
208
-
209
- const selected = new Set(entries.map(entry => entry.id))
210
- for (const entry of entries) {
211
- for (const dependency of entry.inject ?? []) {
212
- if (!selected.has(dependency) && !shellStaticPackages.has(dependency)) {
213
- throw new Error(`${entry.id} injects missing Edge Web package ${dependency}.`)
214
- }
215
- }
216
- }
217
-
218
- const graph = { rev: shortHash(JSON.stringify(entries)), entries }
219
- const indexPath = join(outputRoot, 'index.html')
220
- const index = await readFile(indexPath, 'utf8')
221
- await writeFile(indexPath, injectOwnerSessionGuard(injectBootManifest(index, graph)))
222
- // Cloudflare may serve index.html and SPA fallbacks without invoking the
223
- // Worker. Apply the framing boundary at the asset layer so every alias of
224
- // the executable shell receives the same policy while immutable assets can
225
- // still bypass Worker execution.
226
- await writeFile(join(outputRoot, '_headers'), assetSecurityHeaders)
227
- console.log(`Assembled ${entries.length} upstream client plugins in ${relative(repoRoot, outputRoot)} (rev ${graph.rev}).`)
228
- }
229
-
230
- await main()
@@ -1,86 +0,0 @@
1
- import { createRequire } from 'node:module'
2
- import { lstat, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
3
- import { tmpdir } from 'node:os'
4
- import { join } from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
- import { execa } from 'execa'
7
- import edgePackage from '../package.json' with { type: 'json' }
8
- import { requireGzipBudget } from './bundle-size.mjs'
9
- import {
10
- workerArtifactPath,
11
- writeSourceModeWranglerConfig,
12
- } from './wrangler-config.mjs'
13
-
14
- const DIRECT_GZIP_BUDGET_BYTES = 900 * 1024
15
- const appDirectory = fileURLToPath(new URL('..', import.meta.url))
16
- const require = createRequire(import.meta.url)
17
- const wranglerCli = require.resolve('wrangler')
18
- const mode = process.argv[2]
19
-
20
- if (mode !== 'direct' && mode !== 'isolated') {
21
- process.stderr.write('Usage: node scripts/bundle.mjs <direct|isolated>\n')
22
- process.exitCode = 2
23
- } else {
24
- const directory = await mkdtemp(join(tmpdir(), `dsh-edge-${mode}-bundle-`))
25
- try {
26
- const configFile = join(directory, 'wrangler.json')
27
- const outputDirectory = join(directory, 'worker')
28
- await writeSourceModeWranglerConfig(mode, configFile)
29
- const result = await execa(process.execPath, [
30
- wranglerCli,
31
- 'deploy',
32
- '--config', configFile,
33
- '--env', mode === 'direct' ? '' : 'isolated',
34
- '--define',
35
- `__DSH_EDGE_DEPLOYMENT_ID__:${JSON.stringify(`dsh-edge@${edgePackage.version}/${mode}`)}`,
36
- '--dry-run',
37
- '--outdir', outputDirectory,
38
- ], {
39
- cwd: appDirectory,
40
- reject: false,
41
- all: true,
42
- })
43
- const output = result.all ?? `${result.stdout}\n${result.stderr}`
44
- process.stdout.write(output.endsWith('\n') ? output : `${output}\n`)
45
- if (result.exitCode !== 0) {
46
- process.exitCode = result.exitCode
47
- } else {
48
- if (mode === 'direct') {
49
- const bytes = requireGzipBudget(output, DIRECT_GZIP_BUDGET_BYTES)
50
- process.stdout.write(
51
- `Direct Worker gzip budget: ${bytes}/${DIRECT_GZIP_BUDGET_BYTES} bytes.\n`,
52
- )
53
- }
54
- await publishArtifact(mode, join(outputDirectory, 'index.js'))
55
- }
56
- } catch (error) {
57
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
58
- process.exitCode = 1
59
- } finally {
60
- await rm(directory, { recursive: true, force: true })
61
- }
62
- }
63
-
64
- async function publishArtifact(runtimeMode, source) {
65
- const destination = workerArtifactPath(runtimeMode)
66
- const destinationDirectory = fileURLToPath(new URL(`../worker/${runtimeMode}`, import.meta.url))
67
- await removeGeneratedDirectory(destinationDirectory)
68
- await mkdir(destinationDirectory, { recursive: true, mode: 0o755 })
69
- const bundle = (await readFile(source, 'utf8'))
70
- .replace(/\n\/\/# sourceMappingURL=index\.js\.map\s*$/u, '\n')
71
- await writeFile(destination, bundle, { encoding: 'utf8', mode: 0o644, flag: 'wx' })
72
- process.stdout.write(`Wrote ${runtimeMode} Worker artifact to ${destination}.\n`)
73
- }
74
-
75
- async function removeGeneratedDirectory(directory) {
76
- try {
77
- const entry = await lstat(directory)
78
- if (!entry.isDirectory() || entry.isSymbolicLink()) {
79
- throw new Error(`Refusing to replace non-directory Worker artifact path: ${directory}`)
80
- }
81
- } catch (error) {
82
- if (error?.code === 'ENOENT') return
83
- throw error
84
- }
85
- await rm(directory, { recursive: true })
86
- }