Merge pull request #1864 from deepseek-harness/worktree/drop-create-by-name

refactor: drop the create-by-name workspace route
This commit is contained in:
CreatixChu
2026-08-10 16:01:17 +08:00
committed by GitHub
67 changed files with 201 additions and 396 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write apps/cli/reference/README.md
README.md: bb3e1d77f00e03f6a21f4da3c04994f208e84293
README.zh.md: 3802f940ef6663ec215cf09293a9edda5ea4c512
README.md: 40807da0b1a88708e2e5e9efa3569bd0d6f6a020
README.zh.md: b9c48c16dd4be186266d30a438329463c31aca70

View File

@@ -43,7 +43,7 @@ Git-hosted plugins that ship sources build during install through their `prepare
## Web alias
`dsh web` is a hardcoded alias for `--profile web` that additionally accepts the Web flag family. `--host`, `--port`, `--workspace-root`, and repeatable `--trusted-host` values become patches over the composed rows; their owning plugin schemas validate them at boot. `--dev` switches the web-runtime row to development mode and inserts the client-plugin HMR receiver; it expects a separate `pnpm run dev:web` watcher for no-refresh client bundle updates.
`dsh web` is a hardcoded alias for `--profile web` that additionally accepts the Web flag family. `--host`, `--port`, and repeatable `--trusted-host` values become patches over the composed rows; their owning plugin schemas validate them at boot. `--dev` switches the web-runtime row to development mode and inserts the client-plugin HMR receiver; it expects a separate `pnpm run dev:web` watcher for no-refresh client bundle updates.
```sh
dsh web

View File

@@ -43,7 +43,7 @@ Git 托管、随附源码的插件在安装期间通过其 `prepare` 脚本构
## Web 别名
`dsh web``--profile web` 的硬编码别名,并额外接受 Web flag 系列。`--host``--port``--workspace-root` 和可重复的 `--trusted-host` 值会成为作用在组合行之上的 patch负责这些值的插件 schema 会在启动时验证它们。`--dev` 把 web-runtime 行切换到开发模式并插入客户端插件 HMR热模块替换接收器若要无刷新更新客户端 bundle还需单独运行 `pnpm run dev:web` watcher。
`dsh web``--profile web` 的硬编码别名,并额外接受 Web flag 系列。`--host``--port` 和可重复的 `--trusted-host` 值会成为作用在组合行之上的 patch负责这些值的插件 schema 会在启动时验证它们。`--dev` 把 web-runtime 行切换到开发模式并插入客户端插件 HMR热模块替换接收器若要无刷新更新客户端 bundle还需单独运行 `pnpm run dev:web` watcher。
```sh
dsh web

View File

@@ -48,7 +48,6 @@ interface WebInvocation {
host?: string
port?: number
dev: boolean
workspaceRoot?: string
/** Extra authorities for the /api browser-trust fence. */
trustedHosts?: string[]
}
@@ -70,7 +69,6 @@ interface WebOptions {
host?: string
port?: string
dev?: boolean
workspaceRoot?: string
trustedHost?: string[]
dumpConfig?: boolean
dumpDefaultConfig?: boolean
@@ -176,7 +174,6 @@ Examples:
.option('--host <host>', 'bind host; pass 0.0.0.0 to reach it from another machine')
.option('--port <port>', 'listen port; pass 0 to let the OS pick a free one')
.option('--dev', 'mount the client-plugin HMR receiver (run pnpm run dev:web separately to rebuild bundles)')
.option('--workspace-root <path>', 'parent directory for workspaces created from the browser UI')
.option('--trusted-host <authority...>', 'extra authority the /api browser-trust fence accepts (host or host:port; repeatable)')
.option('--dump-config', 'print the composed web-profile tree (with the user layer and any --patch) and exit')
.option('--dump-default-config', 'print the web profile\'s bundle layers (no user layer) and exit')
@@ -196,8 +193,8 @@ Examples:
// dropping them would print a tree that differs from the same
// invocation's boot.
if (options.host !== undefined || options.port !== undefined || options.dev === true
|| options.workspaceRoot !== undefined || options.trustedHost !== undefined) {
program.error('error: config dumps take no web flags (--host/--port/--dev/--workspace-root/--trusted-host)')
|| options.trustedHost !== undefined) {
program.error('error: config dumps take no web flags (--host/--port/--dev/--trusted-host)')
}
resolved = { mode: 'dump-config', profile: 'web', defaultOnly, patches }
return
@@ -211,7 +208,6 @@ Examples:
...options.host !== undefined && { host: options.host },
...options.port !== undefined && { port: Number(options.port) },
dev: options.dev === true,
...options.workspaceRoot !== undefined && { workspaceRoot: options.workspaceRoot },
...options.trustedHost !== undefined && { trustedHosts: options.trustedHost },
}
})

View File

@@ -1,7 +1,7 @@
/**
* `dsh web` — the browser-surface alias over the profile boot: `--profile web`
* plus the Web flag family (`--host/--port/--dev/--workspace-root/
* --trusted-host`), each flag becoming a patch over the composed profile
* plus the Web flag family (`--host/--port/--dev/--trusted-host`), each flag
* becoming a patch over the composed profile
* tree. All web runtime glue (dist serving, prompt section, URL line) lives
* in the `@deepseek-ai/dsh-web-app` bundle; this launcher only derives
* flag patches and the LAN-trust snapshot.
@@ -59,7 +59,6 @@ export interface WebFlags {
host?: string
port?: number
dev: boolean
workspaceRoot?: string
trustedHosts?: string[]
}
@@ -83,7 +82,6 @@ function deriveWebFlagPatches(
}
if (flags.host !== undefined) put('webserver', 'host', flags.host)
if (flags.port !== undefined) put('webserver', 'port', flags.port)
if (flags.workspaceRoot !== undefined) put('api-gateway', 'workspaceRoot', flags.workspaceRoot)
const composedHost = (rows.get('webserver')?.config as { host?: string } | undefined)?.host
const { lanAddresses, trustedHosts } = resolveLanTrust(flags.host ?? composedHost, flags.trustedHosts ?? [])
if (trustedHosts.length > 0) {
@@ -122,8 +120,8 @@ export function webSurfaceContextEnabled(rows: ProfileRows): boolean {
}
/**
* Serve the browser UI from the web profile. Host/port/workspace-root flags
* are passed through only when given (absent, the composed profile values
* Serve the browser UI from the web profile. Host/port flags are passed
* through only when given (absent, the composed profile values
* stand); `web-runtime.mode` and `lanAddresses` are launcher-derived on
* every boot. The URL line is printed by the web-app bundle's runtime row
* after Loader settlement.

View File

@@ -33,8 +33,8 @@ describe('parseDshArgs', () => {
.toEqual({ mode: 'run', profile: 'headless', patches: [], task: '--profile is task text' })
expect(parse(['web'])).toEqual({ mode: 'web', dev: false, patches: [] })
expect(parse(['web', '--patch', 'web.yml'])).toEqual({ mode: 'web', dev: false, patches: ['web.yml'] })
expect(parse(['web', '--host', '0.0.0.0', '--port', '8080', '--dev', '--workspace-root', '/w']))
.toEqual({ mode: 'web', host: '0.0.0.0', port: 8080, dev: true, workspaceRoot: '/w', patches: [] })
expect(parse(['web', '--host', '0.0.0.0', '--port', '8080', '--dev']))
.toEqual({ mode: 'web', host: '0.0.0.0', port: 8080, dev: true, patches: [] })
expect(parse(['web', '--trusted-host', 'harness.internal:3080', 'lab.internal', '--trusted-host', '10.0.0.9']))
.toEqual({ mode: 'web', dev: false, patches: [], trustedHosts: ['harness.internal:3080', 'lab.internal', '10.0.0.9'] })
})

View File

@@ -78,8 +78,8 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
beforeAll(async () => {
scaffold = await launchWebScaffold({})
// The workspace-aware flow runs sessions in <workspaceCwd>/workspace;
// the read targets must live in that session cwd (pre-creation is safe:
// create-by-name adopts an existing directory).
// the read targets must live in that session cwd (pre-creation is safe
// because the picker adopts an existing directory by path).
const sessionCwd = join(scaffold.workspaceCwd, 'workspace')
await mkdir(sessionCwd, { recursive: true })
await writeFile(join(sessionCwd, 'nav-a.md'), '# alpha nav\n')

View File

@@ -187,8 +187,8 @@ describe('web e2e: seeded history renders through cold resume', () => {
scaffold = await launchWebScaffold({})
// The workspace-aware flow runs sessions in <workspaceCwd>/workspace
// (the composer's default draft name); the read-tool targets must live in
// that session cwd. Pre-creating the directory is safe: create-by-name
// adopts an existing directory.
// that session cwd. Pre-creating the directory is safe because the picker
// adopts an existing directory by path.
const sessionCwd = join(scaffold.workspaceCwd, 'workspace')
await mkdir(sessionCwd, { recursive: true })
await writeFile(join(sessionCwd, 'a.txt'), 'alpha\n')