mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Adopt MIT for DSH packages
This commit is contained in:
@@ -234,9 +234,9 @@ def verify_wheel(
|
||||
raise RuntimeError(
|
||||
f"{wheel} has distribution name {metadata.get('Name')}, expected {expected_distribution}"
|
||||
)
|
||||
if metadata.get("License-Expression") != "BSD-3-Clause":
|
||||
if metadata.get("License-Expression") != "MIT":
|
||||
raise RuntimeError(
|
||||
f"{wheel} has license expression {metadata.get('License-Expression')}, expected BSD-3-Clause"
|
||||
f"{wheel} has license expression {metadata.get('License-Expression')}, expected MIT"
|
||||
)
|
||||
expected_license_files = ["LICENSE"] if package == "sdk" else ["LICENSE", "THIRD_PARTY_NOTICES.md"]
|
||||
license_files = [Path(name).name for name in metadata.get_all("License-File") or []]
|
||||
|
||||
@@ -691,7 +691,7 @@ export function render(): string {
|
||||
|
||||
# Third-Party Notices
|
||||
|
||||
DeepSeek Harness is licensed under [BSD 3-Clause](LICENSE). It depends on the third-party software listed below. Each project remains under its own license; nothing in this file changes those terms.
|
||||
DeepSeek Harness is licensed under [MIT](LICENSE). It depends on the third-party software listed below. Each project remains under its own license; nothing in this file changes those terms.
|
||||
|
||||
This file lists **direct** dependencies declared by the workspace and the explicitly disclosed official Claude platform payload closure. It is generated from the workspace manifests by \`scripts/gen-third-party-notices.ts\`: a pre-commit hook regenerates it whenever a staged file changes one of its inputs, and \`scripts/gen-third-party-notices.spec.ts\` asserts in the test lane that the committed bytes match. Deleting a manifest runs no hook, so that case is caught by the assertion instead. Run \`pnpm run verify-third-party-notices\` for the standalone check.
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ describe('gate graph validation', () => {
|
||||
expect(ids).toContain('public-repository-links')
|
||||
})
|
||||
|
||||
it.each(['ci-primary', 'ci-static', 'check-all'] as const)(
|
||||
'keeps the DSH package license policy in %s',
|
||||
(mode) => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode(mode).map(subject => subject.id))
|
||||
|
||||
expect(ids).toContain('dsh-package-licenses')
|
||||
},
|
||||
)
|
||||
|
||||
it('keeps native Windows coverage blocking while portability inventory remains observational', () => {
|
||||
const gates = withPnpmEntrypoint(() => gatesForMode('ci-windows-complete'))
|
||||
const byId = new Map(gates.map(subject => [subject.id, subject]))
|
||||
|
||||
@@ -246,6 +246,7 @@ function ciSharedStaticGates(): Gate[] {
|
||||
return [
|
||||
pnpmScript('runtime-closure', 'verify-runtime-closure', { label: 'runtime closure' }),
|
||||
pnpmScript('constraints', 'constraints'),
|
||||
pnpmScript('dsh-package-licenses', 'verify-dsh-package-licenses', { label: 'DSH package licenses' }),
|
||||
pnpmScript('package-invariants', 'verify-package-invariants', { label: 'package invariants' }),
|
||||
pnpmScript('cordis-config', 'verify-cordis-config', { label: 'Cordis config' }),
|
||||
pnpmScript('issue-management', 'test:issue-management', { label: 'Issue management policy' }),
|
||||
@@ -557,6 +558,7 @@ function hygieneLeafGates(options: { artifactNeeds?: string[] } = {}): Gate[] {
|
||||
pnpmScript('knip', 'knip'),
|
||||
pnpmScript('publint', 'publint', artifactOptions),
|
||||
pnpmScript('constraints', 'constraints'),
|
||||
pnpmScript('dsh-package-licenses', 'verify-dsh-package-licenses', { label: 'DSH package licenses' }),
|
||||
pnpmScript('package-invariants', 'verify-package-invariants', { label: 'package invariants' }),
|
||||
builtPackageInvariantsGate(options.artifactNeeds),
|
||||
pnpmScript('node-next-types', 'verify-node-next-types', {
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "# DeepSeek Harness\n\nEnglish | [中文](README.zh.md)\n\nDeepSeek Harness (`dsh`) is an open-source agent harness developed by [DeepSeek AI](https://deepseek.com).\n\nIt uses an architecture where **everything is a plugin**, and is powered by [Cordis](https://github.com/cordiverse/cordis).\n\n## Developer preview\n\nDeepSeek Harness is currently in _developer preview_ and is iterating rapidly. **THERE WILL BE COMPATIBILITY-BREAKING CHANGES.**\n\n## Run\n\n### Run from `npm`\n\nInstall `Node.js`, then run:\n\n```sh\nnpx @deepseek-ai/dsh web\n```\n\nThe command starts the Web UI, served at `http://127.0.0.1:3080` by default. See [Web UI guide](docs/user/guide/index.md).\n\n### Run from source\n\nTo run from a repository checkout:\n\n```sh\ngit clone https://github.com/deepseek-ai/deepseek-harness.git\ncd deepseek-harness\npnpm install\npnpm run build\npnpm dsh web\n```\n\n## Community and support\n\n- Feel free to submit feedback or bug reports through [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions).\n- Add the [`dsh-plugin`](https://github.com/topics/dsh-plugin) topic to your plugin repository for discoverability.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Development\n\nStart with the [development guide](docs/development.md) and [architecture documentation](docs/architecture.md).\n\nFor agents, follow [AGENTS.md](AGENTS.md).\n\n## License\n\n[BSD 3-Clause](LICENSE)\n\nThird-party dependencies and their licenses are disclosed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).\n"
|
||||
"content": "# DeepSeek Harness\n\nEnglish | [中文](README.zh.md)\n\nDeepSeek Harness (`dsh`) is an open-source agent harness developed by [DeepSeek AI](https://deepseek.com).\n\nIt uses an architecture where **everything is a plugin**, and is powered by [Cordis](https://github.com/cordiverse/cordis).\n\n## Developer preview\n\nDeepSeek Harness is currently in _developer preview_ and is iterating rapidly. **THERE WILL BE COMPATIBILITY-BREAKING CHANGES.**\n\n## Run\n\n### Run from `npm`\n\nInstall `Node.js`, then run:\n\n```sh\nnpx @deepseek-ai/dsh web\n```\n\nThe command starts the Web UI, served at `http://127.0.0.1:3080` by default. See [Web UI guide](docs/user/guide/index.md).\n\n### Run from source\n\nTo run from a repository checkout:\n\n```sh\ngit clone https://github.com/deepseek-ai/deepseek-harness.git\ncd deepseek-harness\npnpm install\npnpm run build\npnpm dsh web\n```\n\n## Community and support\n\n- Feel free to submit feedback or bug reports through [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions).\n- Add the [`dsh-plugin`](https://github.com/topics/dsh-plugin) topic to your plugin repository for discoverability.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Development\n\nStart with the [development guide](docs/development.md) and [architecture documentation](docs/architecture.md).\n\nFor agents, follow [AGENTS.md](AGENTS.md).\n\n## License\n\n[MIT](LICENSE)\n\nThird-party dependencies and their licenses are disclosed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).\n"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "# DeepSeek Harness\n\n[English](README.md) | 中文\n\nDeepSeek Harness(`dsh`)是由 [DeepSeek AI](https://deepseek.com) 开发的开源 agent harness(智能体框架)。\n\n它采用**一切皆插件**的架构,并由 [Cordis](https://github.com/cordiverse/cordis) 驱动。\n\n## 开发者预览\n\nDeepSeek Harness 目前处于 _开发者预览_ 阶段,正在快速迭代。**未来将出现破坏兼容性的变更。**\n\n## 运行\n\n### 通过 `npm` 运行\n\n安装 `Node.js`,然后运行:\n\n```sh\nnpx @deepseek-ai/dsh web\n```\n\n该命令会启动 Web UI,默认地址为 `http://127.0.0.1:3080`。详见 [Web UI 指南](docs/user/guide/index.md)。\n\n### 从源码运行\n\n如需从仓库源码运行:\n\n```sh\ngit clone https://github.com/deepseek-ai/deepseek-harness.git\ncd deepseek-harness\npnpm install\npnpm run build\npnpm dsh web\n```\n\n## 社区与支持\n\n- 欢迎通过 [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions) 提交反馈或 bug 报告。\n- 为你的插件仓库添加 [`dsh-plugin`](https://github.com/topics/dsh-plugin) 主题,便于被发现。\n\n## 参与贡献\n\n参见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## 开发\n\n请先阅读[开发指南](docs/development.md)与[架构文档](docs/architecture.md)。\n\n面向 agent:请遵循 [AGENTS.md](AGENTS.md)。\n\n## 许可证\n\n[BSD 3-Clause](LICENSE)\n\n第三方依赖及其许可证见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。\n"
|
||||
"content": "# DeepSeek Harness\n\n[English](README.md) | 中文\n\nDeepSeek Harness(`dsh`)是由 [DeepSeek AI](https://deepseek.com) 开发的开源 agent harness(智能体框架)。\n\n它采用**一切皆插件**的架构,并由 [Cordis](https://github.com/cordiverse/cordis) 驱动。\n\n## 开发者预览\n\nDeepSeek Harness 目前处于 _开发者预览_ 阶段,正在快速迭代。**未来将出现破坏兼容性的变更。**\n\n## 运行\n\n### 通过 `npm` 运行\n\n安装 `Node.js`,然后运行:\n\n```sh\nnpx @deepseek-ai/dsh web\n```\n\n该命令会启动 Web UI,默认地址为 `http://127.0.0.1:3080`。详见 [Web UI 指南](docs/user/guide/index.md)。\n\n### 从源码运行\n\n如需从仓库源码运行:\n\n```sh\ngit clone https://github.com/deepseek-ai/deepseek-harness.git\ncd deepseek-harness\npnpm install\npnpm run build\npnpm dsh web\n```\n\n## 社区与支持\n\n- 欢迎通过 [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions) 提交反馈或 bug 报告。\n- 为你的插件仓库添加 [`dsh-plugin`](https://github.com/topics/dsh-plugin) 主题,便于被发现。\n\n## 参与贡献\n\n参见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## 开发\n\n请先阅读[开发指南](docs/development.md)与[架构文档](docs/architecture.md)。\n\n面向 agent:请遵循 [AGENTS.md](AGENTS.md)。\n\n## 许可证\n\n[MIT](LICENSE)\n\n第三方依赖及其许可证见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。\n"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
|
||||
59
scripts/verify-dsh-package-licenses.spec.ts
Normal file
59
scripts/verify-dsh-package-licenses.spec.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { inspectDshPackageLicenses } from './verify-dsh-package-licenses.ts'
|
||||
|
||||
const roots: string[] = []
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
function writeManifest(root: string, file: string, manifest: Record<string, unknown>): void {
|
||||
const path = join(root, file)
|
||||
mkdirSync(dirname(path), { recursive: true })
|
||||
writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`)
|
||||
}
|
||||
|
||||
function createWorkspace(): string {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-package-licenses-'))
|
||||
roots.push(root)
|
||||
writeManifest(root, 'package.json', {
|
||||
name: '@deepseek-ai/dsh-root',
|
||||
license: 'MIT',
|
||||
workspaces: ['apps/*', 'packages/*/*', 'vendor/*'],
|
||||
})
|
||||
return root
|
||||
}
|
||||
|
||||
describe('DSH package license gate', () => {
|
||||
it('checks root, unhyphenated CLI, and dsh-prefixed package names while ignoring other families', () => {
|
||||
const root = createWorkspace()
|
||||
writeManifest(root, 'apps/cli/package.json', { name: '@deepseek-ai/dsh', license: 'MIT' })
|
||||
writeManifest(root, 'packages/core/agent/package.json', {
|
||||
name: '@deepseek-ai/dsh-agent',
|
||||
license: 'BSD-3-Clause',
|
||||
})
|
||||
writeManifest(root, 'vendor/cordis/package.json', {
|
||||
name: '@deepseek-ai/cordis',
|
||||
license: 'BSD-3-Clause',
|
||||
})
|
||||
|
||||
expect(inspectDshPackageLicenses(root)).toEqual({
|
||||
packageCount: 3,
|
||||
failures: [
|
||||
'packages/core/agent/package.json: @deepseek-ai/dsh-agent must declare "license": "MIT"; found "BSD-3-Clause".',
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects a missing license declaration', () => {
|
||||
const root = createWorkspace()
|
||||
writeManifest(root, 'packages/core/agent/package.json', { name: '@deepseek-ai/dsh-agent' })
|
||||
|
||||
expect(inspectDshPackageLicenses(root).failures).toEqual([
|
||||
'packages/core/agent/package.json: @deepseek-ai/dsh-agent must declare "license": "MIT"; found undefined.',
|
||||
])
|
||||
})
|
||||
})
|
||||
89
scripts/verify-dsh-package-licenses.ts
Normal file
89
scripts/verify-dsh-package-licenses.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Enforce the MIT license declaration for repository-owned DSH npm packages.
|
||||
* @module scripts/verify-dsh-package-licenses
|
||||
*/
|
||||
|
||||
import { globSync, readFileSync } from 'node:fs'
|
||||
import { resolve, sep } from 'node:path'
|
||||
|
||||
const ROOT = resolve(import.meta.dirname, '..')
|
||||
const DSH_PACKAGE_NAME = /^@deepseek-ai\/dsh(?:-|$)/
|
||||
|
||||
/** Result of checking every DSH package reachable through the root workspace list. */
|
||||
export interface DshPackageLicenseReport {
|
||||
/** Number of DSH package manifests checked. */
|
||||
packageCount: number
|
||||
/** Repository-relative diagnostics for non-MIT declarations. */
|
||||
failures: string[]
|
||||
}
|
||||
|
||||
function readManifest(root: string, file: string): Record<string, unknown> {
|
||||
const parsed: unknown = JSON.parse(readFileSync(resolve(root, file), 'utf8'))
|
||||
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
||||
throw new Error(`verify-dsh-package-licenses: ${file} must contain a JSON object.`)
|
||||
}
|
||||
return parsed as Record<string, unknown>
|
||||
}
|
||||
|
||||
function isStringArray(value: unknown): value is string[] {
|
||||
return Array.isArray(value) && value.every((entry: unknown) => typeof entry === 'string')
|
||||
}
|
||||
|
||||
function workspaceManifestPaths(root: string): string[] {
|
||||
const rootManifest = readManifest(root, 'package.json')
|
||||
const workspaces = rootManifest.workspaces
|
||||
if (!isStringArray(workspaces)) {
|
||||
throw new Error('verify-dsh-package-licenses: package.json workspaces must be a string array.')
|
||||
}
|
||||
|
||||
const files = new Set(['package.json'])
|
||||
for (const pattern of workspaces) {
|
||||
for (const file of globSync(`${pattern}/package.json`, { cwd: root })) {
|
||||
files.add(file)
|
||||
}
|
||||
}
|
||||
return [...files].sort()
|
||||
}
|
||||
|
||||
function printable(value: unknown): string {
|
||||
return value === undefined ? 'undefined' : JSON.stringify(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check every DSH npm package declared by the repository workspace.
|
||||
* @param root - absolute repository root containing the workspace package.json.
|
||||
* @returns the checked package count and every non-MIT declaration.
|
||||
*/
|
||||
export function inspectDshPackageLicenses(root: string): DshPackageLicenseReport {
|
||||
let packageCount = 0
|
||||
const failures: string[] = []
|
||||
|
||||
for (const file of workspaceManifestPaths(root)) {
|
||||
const manifest = readManifest(root, file)
|
||||
const name = manifest.name
|
||||
if (typeof name !== 'string' || !DSH_PACKAGE_NAME.test(name)) continue
|
||||
|
||||
packageCount++
|
||||
if (manifest.license !== 'MIT') {
|
||||
const normalizedFile = file.split(sep).join('/')
|
||||
failures.push(
|
||||
`${normalizedFile}: ${name} must declare "license": "MIT"; found ${printable(manifest.license)}.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { packageCount, failures }
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.filename === resolve(process.argv[1])) {
|
||||
const report = inspectDshPackageLicenses(ROOT)
|
||||
if (report.failures.length > 0) {
|
||||
process.stderr.write('verify-dsh-package-licenses: non-MIT DSH package declarations found:\n')
|
||||
for (const failure of report.failures) process.stderr.write(` ${failure}\n`)
|
||||
process.exitCode = 1
|
||||
} else {
|
||||
process.stdout.write(
|
||||
`verify-dsh-package-licenses: ${String(report.packageCount)} DSH package(s) checked; all declare MIT.\n`,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user