mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`, `verify-translation-pairing --write` for the touched bilingual pairs, `gen-doc-graphs`, and one typert snapshot whose ids embed character offsets. `pnpm run rescope-vendor --check` verifies the result. Renames nine vendored packages (cordis, cosmokit, schemastery and the six @cordisjs plugins) and every reference that resolves them: manifest names and dependency keys, module specifiers including declare-module merges, cordis.yml plugin names, tsconfig paths, every Markdown fence, and `docs/` prose. Directory names, upstream versions, and dependency ranges are unchanged, so vendor/README.md still reads as an upstream snapshot; its manifest table gains an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed at each fork's origin. The tutorial tier follows the rename end to end: its yaml fences named plugins the Loader can no longer resolve, its `ts ignore-check` fences disagreed with the compiled fences beside them, and its prose quoted both. The contracts that told readers to keep upstream names — the root convention and the vendoring cookbook's tree comment and manifest invariant — now say to rescope instead. Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle purity gate now names the vendored libraries a browser bundle inlines, and the files where a bare `cordis` is an agent-preset id keep that product data.
This commit is contained in:
@@ -21,15 +21,15 @@ const workspaceGlobs = [
|
||||
{ dir: 'apps', depth: 1 },
|
||||
] as const
|
||||
const vendoredPackages = new Set([
|
||||
'cordis',
|
||||
'cosmokit',
|
||||
'schemastery',
|
||||
'@cordisjs/plugin-loader',
|
||||
'@cordisjs/plugin-include',
|
||||
'@cordisjs/plugin-group',
|
||||
'@cordisjs/plugin-timer',
|
||||
'@cordisjs/plugin-hmr',
|
||||
'@cordisjs/plugin-logger-console',
|
||||
'@deepseek-ai/cordis',
|
||||
'@deepseek-ai/cosmokit',
|
||||
'@deepseek-ai/schemastery',
|
||||
'@deepseek-ai/cordis-plugin-loader',
|
||||
'@deepseek-ai/cordis-plugin-include',
|
||||
'@deepseek-ai/cordis-plugin-group',
|
||||
'@deepseek-ai/cordis-plugin-timer',
|
||||
'@deepseek-ai/cordis-plugin-hmr',
|
||||
'@deepseek-ai/cordis-plugin-logger-console',
|
||||
])
|
||||
const publicLandlockPackages = new Set([
|
||||
'@deepseek-ai/node-addon-landlock-run',
|
||||
@@ -271,13 +271,13 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] {
|
||||
}
|
||||
|
||||
if (dir.startsWith('packages/') && manifest.name?.startsWith('@deepseek-ai/dsh-')) {
|
||||
const peer = manifest.peerDependencies?.cordis
|
||||
const dev = manifest.devDependencies?.cordis
|
||||
const peer = manifest.peerDependencies?.['@deepseek-ai/cordis']
|
||||
const dev = manifest.devDependencies?.['@deepseek-ai/cordis']
|
||||
|
||||
if (!peer) errors.push(`${label}: cordis must be a peerDependency`)
|
||||
if (!dev) errors.push(`${label}: cordis must also be a devDependency`)
|
||||
if (!peer) errors.push(`${label}: @deepseek-ai/cordis must be a peerDependency`)
|
||||
if (!dev) errors.push(`${label}: @deepseek-ai/cordis must also be a devDependency`)
|
||||
if (peer && dev && peer !== dev) {
|
||||
errors.push(`${label}: cordis peer (${peer}) and dev (${dev}) ranges must match`)
|
||||
errors.push(`${label}: @deepseek-ai/cordis peer (${peer}) and dev (${dev}) ranges must match`)
|
||||
}
|
||||
if (manifest.version !== repositoryVersion) {
|
||||
errors.push(`${label}: package.json version must match root version ${repositoryVersion ?? '(missing)'}`)
|
||||
|
||||
@@ -11,12 +11,12 @@ import ts from 'typescript'
|
||||
|
||||
/** Cheap textual prefilter for a cordis module merge, quote-style agnostic
|
||||
* (the AST match below reads `stmt.name.text` and never sees the quotes). */
|
||||
const MERGE_HEAD = /declare module ['"](?:cordis|\.\/context\.ts)['"]/
|
||||
const MERGE_HEAD = /declare module ['"](?:@deepseek-ai\/cordis|\.\/context\.ts)['"]/
|
||||
|
||||
/**
|
||||
* Parse every file matching `patterns` (repo-relative, sorted, `/`-normalized)
|
||||
* that textually contains a cordis module merge, yielding one entry per merge
|
||||
* BLOCK — a file may legally hold several `declare module 'cordis'` blocks
|
||||
* BLOCK — a file may legally hold several `declare module '@deepseek-ai/cordis'` blocks
|
||||
* (the Typert analyzer reads them all), so the exhaustiveness scan must too.
|
||||
* Files without a merge are skipped.
|
||||
* @param scanRoot - Repository root the patterns are resolved against.
|
||||
@@ -39,14 +39,14 @@ export function contextMergeFiles(
|
||||
return out
|
||||
}
|
||||
|
||||
/** Every cordis module-merge body in `sf`: `declare module 'cordis'` (harness
|
||||
/** Every cordis module-merge body in `sf`: `declare module '@deepseek-ai/cordis'` (harness
|
||||
* packages) or `declare module './context.ts'` (vendor core), in source order.
|
||||
* Module-local: consumers walk blocks through {@link contextMergeFiles}. */
|
||||
function cordisModuleBodies(sf: ts.SourceFile): ts.ModuleBlock[] {
|
||||
const bodies: ts.ModuleBlock[] = []
|
||||
for (const stmt of sf.statements) {
|
||||
if (!ts.isModuleDeclaration(stmt) || !ts.isStringLiteral(stmt.name)) continue
|
||||
if (stmt.name.text !== 'cordis' && stmt.name.text !== './context.ts') continue
|
||||
if (stmt.name.text !== '@deepseek-ai/cordis' && stmt.name.text !== './context.ts') continue
|
||||
if (stmt.body && ts.isModuleBlock(stmt.body)) bodies.push(stmt.body)
|
||||
}
|
||||
return bodies
|
||||
@@ -60,7 +60,7 @@ export function cordisModuleBody(sf: ts.SourceFile): ts.ModuleBlock | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* Every `key: Type` property a `declare module 'cordis'` Context merge
|
||||
* Every `key: Type` property a `declare module '@deepseek-ai/cordis'` Context merge
|
||||
* declares in one module body.
|
||||
* @param body - The cordis module augmentation block.
|
||||
* @param sf - Owning source file (for text extraction).
|
||||
@@ -79,7 +79,7 @@ export function contextKeyMap(body: ts.ModuleBlock, sf: ts.SourceFile): Map<stri
|
||||
}
|
||||
|
||||
/**
|
||||
* Every event name a `declare module 'cordis'` Events merge declares in one
|
||||
* Every event name a `declare module '@deepseek-ai/cordis'` Events merge declares in one
|
||||
* module body. Names are the literal member keys (`'agent/created'`), read
|
||||
* from method and property members alike so a declaration form the projector
|
||||
* would reject still enters the exhaustiveness scan.
|
||||
|
||||
@@ -128,7 +128,7 @@ describe('cordis-walk scan reach', () => {
|
||||
const dir = join(root, 'packages/client/ui-x/src/client')
|
||||
mkdirSync(dir, { recursive: true })
|
||||
writeFileSync(join(dir, 'index.ts'), [
|
||||
"declare module 'cordis' {",
|
||||
"declare module '@deepseek-ai/cordis' {",
|
||||
' interface Events {',
|
||||
" 'x/changed'(): void",
|
||||
' }',
|
||||
@@ -153,12 +153,12 @@ describe('cordis-walk scan reach', () => {
|
||||
// backstop must not stop at the first one, skip the double-quoted legal
|
||||
// form, or ignore .tsx sources.
|
||||
writeFileSync(join(dir, 'split.ts'), [
|
||||
"declare module 'cordis' {",
|
||||
"declare module '@deepseek-ai/cordis' {",
|
||||
' interface Context {',
|
||||
' first: FirstService',
|
||||
' }',
|
||||
'}',
|
||||
'declare module "cordis" {',
|
||||
'declare module "@deepseek-ai/cordis" {',
|
||||
' interface Events {',
|
||||
" 'second/changed'(): void",
|
||||
' }',
|
||||
@@ -167,7 +167,7 @@ describe('cordis-walk scan reach', () => {
|
||||
'',
|
||||
].join('\n'))
|
||||
writeFileSync(join(dir, 'view.tsx'), [
|
||||
"declare module 'cordis' {",
|
||||
"declare module '@deepseek-ai/cordis' {",
|
||||
' interface Context {',
|
||||
' fromTsx: TsxService',
|
||||
' }',
|
||||
@@ -189,7 +189,7 @@ describe('cordis-walk scan reach', () => {
|
||||
|
||||
it('reads string-literal and identifier member names from an Events merge', () => {
|
||||
const sf = ts.createSourceFile('x.ts', [
|
||||
"declare module 'cordis' {",
|
||||
"declare module '@deepseek-ai/cordis' {",
|
||||
' interface Events {',
|
||||
" 'scope/list'(items: string[]): void",
|
||||
' plain(): void',
|
||||
|
||||
@@ -99,7 +99,7 @@ export const SERVICE_PAGE: Record<string, string> = {
|
||||
/**
|
||||
* Context keys declared in `interface Context` merges that the rendering
|
||||
* projection cannot see, each with the reason and its documentation owner.
|
||||
* The scan that enforces this list reads EVERY `declare module 'cordis'`
|
||||
* The scan that enforces this list reads EVERY `declare module '@deepseek-ai/cordis'`
|
||||
* Context merge under `packages/x/x/src/**` — any depth, not only root
|
||||
* `index.ts` files with a same-named service class — so a new service can
|
||||
* never silently join this blind spot: it either enters {@link SERVICE_PAGE}
|
||||
@@ -168,7 +168,7 @@ export const EVENT_SCOPE_PAGE: Record<string, string> = {
|
||||
* Event names declared in `interface Events` merges that the rendering
|
||||
* projection cannot see, each with the reason and its documentation owner.
|
||||
* The mirror of {@link SERVICE_WALK_EXEMPTIONS} for events: an independent
|
||||
* scan reads EVERY `declare module 'cordis'` Events merge under
|
||||
* scan reads EVERY `declare module '@deepseek-ai/cordis'` Events merge under
|
||||
* `packages/x/x/src/**`, so a declared event either renders onto a subsystems
|
||||
* page (via {@link EVENT_SCOPE_PAGE}) or names itself here — never vanishes
|
||||
* silently. Keys are full event names, not scopes: client-face events share
|
||||
|
||||
@@ -309,14 +309,14 @@ class ScopedEventGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/** Return whether an Events interface is inside declare module 'cordis'. */
|
||||
/** Return whether an Events interface is inside declare module '@deepseek-ai/cordis'. */
|
||||
function isCordisModuleInterface(node: ts.InterfaceDeclaration): boolean {
|
||||
const block = node.parent
|
||||
const declaration = block.parent
|
||||
return ts.isModuleBlock(block)
|
||||
&& ts.isModuleDeclaration(declaration)
|
||||
&& ts.isStringLiteral(declaration.name)
|
||||
&& declaration.name.text === 'cordis'
|
||||
&& declaration.name.text === '@deepseek-ai/cordis'
|
||||
}
|
||||
|
||||
/** Return whether a parameter is the explicit TypeScript this receiver. */
|
||||
|
||||
@@ -134,13 +134,17 @@ describe('parseVendoredRows', () => {
|
||||
const rows = parseVendoredRows(readFileSync(resolve(root, 'vendor/README.md'), 'utf8'))
|
||||
|
||||
expect(rows.length).toBeGreaterThan(0)
|
||||
expect(rows).toContainEqual({ npmName: 'cordis', upstream: 'https://github.com/cordiverse/cordis' })
|
||||
expect(rows).toContainEqual({
|
||||
npmName: '@deepseek-ai/cordis',
|
||||
upstreamName: 'cordis',
|
||||
upstream: 'https://github.com/cordiverse/cordis',
|
||||
})
|
||||
// The upstream column carries a trailing package path for some rows; it is not part of the URL.
|
||||
expect(rows.every(row => /^https:\/\/\S+$/.test(row.upstream))).toBe(true)
|
||||
})
|
||||
|
||||
it('yields nothing when the table columns change, so the generator fails loud', () => {
|
||||
expect(parseVendoredRows('| `cordis/` | cordis | 4.0.0 | https://example.com | `abc123` |\n')).toEqual([])
|
||||
expect(parseVendoredRows('| `cordis/` | `@deepseek-ai/cordis` | cordis | 4.0.0 | https://example.com | `abc123` |\n')).toEqual([])
|
||||
})
|
||||
|
||||
it('covers every vendored directory, so no package can drop out of the notices', () => {
|
||||
|
||||
@@ -387,6 +387,8 @@ export function tierExternalDeps(manifests: Map<string, Manifest>, names: Set<st
|
||||
/** A vendored package row parsed out of the `vendor/README.md` manifest table. */
|
||||
export interface VendoredRow {
|
||||
npmName: string
|
||||
/** The name this package carries upstream; MIT attribution names the fork's origin, not our scope. */
|
||||
upstreamName: string
|
||||
upstream: string
|
||||
}
|
||||
|
||||
@@ -398,11 +400,12 @@ export interface VendoredRow {
|
||||
export function parseVendoredRows(text: string): VendoredRow[] {
|
||||
const rows: VendoredRow[] = []
|
||||
for (const line of text.split('\n')) {
|
||||
const match = /^\| \x60\S+\/\x60 \| \x60([^\x60]+)\x60 \| \S+ \| (https:\/\/\S+?)(?: \([^)]*\))? \| \x60[0-9a-f]+\x60 \|$/.exec(line)
|
||||
const match = new RegExp(String.raw`^\| \x60\S+\/\x60 \| \x60([^\x60]+)\x60 \| \x60([^\x60]+)\x60 \| \S+ \| `
|
||||
+ String.raw`(https:\/\/\S+?)(?: \([^)]*\))? \| \x60[0-9a-f]+\x60 \|$`).exec(line)
|
||||
if (match === null) continue
|
||||
const [, npmName, upstream] = match
|
||||
if (npmName === undefined || upstream === undefined) continue
|
||||
rows.push({ npmName, upstream })
|
||||
const [, npmName, upstreamName, upstream] = match
|
||||
if (npmName === undefined || upstreamName === undefined || upstream === undefined) continue
|
||||
rows.push({ npmName, upstreamName, upstream })
|
||||
}
|
||||
return rows
|
||||
}
|
||||
@@ -696,11 +699,11 @@ The complete npm transitive closure, including the Landlock launcher workspace,
|
||||
|
||||
## Vendored source (\`vendor/\`)
|
||||
|
||||
The Cordis framework and its foundation libraries are source-vendored into this repository rather than consumed from npm. All are MIT-licensed; each directory preserves its upstream \`LICENSE\` file. Exact upstream commits and local modifications are recorded in [\`vendor/README.md\`](vendor/README.md).
|
||||
The Cordis framework and its foundation libraries are source-vendored into this repository rather than consumed from npm, and republished under the \`@deepseek-ai\` scope. All are MIT-licensed; each directory preserves its upstream \`LICENSE\` file. Exact upstream commits and local modifications are recorded in [\`vendor/README.md\`](vendor/README.md).
|
||||
|
||||
| Package | Upstream | License |
|
||||
| --- | --- | --- |
|
||||
${vendored.map(row => `| \`${row.npmName}\` | [${row.upstream.replace('https://', '')}](${row.upstream}) | MIT |`).join('\n')}
|
||||
| Package | Upstream name | Upstream | License |
|
||||
| --- | --- | --- | --- |
|
||||
${vendored.map(row => `| \`${row.npmName}\` | \`${row.upstreamName}\` | [${row.upstream.replace('https://', '')}](${row.upstream}) | MIT |`).join('\n')}
|
||||
|
||||
## Runtime npm dependencies
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { basename, resolve } from 'node:path'
|
||||
import { Context } from 'cordis'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import type { ToolSchema } from '@deepseek-ai/dsh-llm'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
|
||||
@@ -258,7 +258,9 @@ class WorkspacePackageSet {
|
||||
const name = expectString(manifest, 'name', manifestPath)
|
||||
const version = expectString(manifest, 'version', manifestPath)
|
||||
const isVendored = manifestPath.startsWith('vendor/')
|
||||
if (!isVendored && !name.startsWith('@deepseek-ai/')) {
|
||||
// Vendored packages are rescoped too (vendor/README.md), so publication
|
||||
// never carries an upstream name that would squat it on the registry.
|
||||
if (!name.startsWith('@deepseek-ai/')) {
|
||||
throw new Error(`${manifestPath} must name an @deepseek-ai package`)
|
||||
}
|
||||
if (name === '@deepseek-ai/dsh-root') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context, FiberState, Service, ValidationError } from 'cordis'
|
||||
import Loader from '@cordisjs/plugin-loader'
|
||||
import z from 'schemastery'
|
||||
import { Context, FiberState, Service, ValidationError } from '@deepseek-ai/cordis'
|
||||
import Loader from '@deepseek-ai/cordis-plugin-loader'
|
||||
import z from '@deepseek-ai/schemastery'
|
||||
import InvariantService from '@deepseek-ai/dsh-invariants'
|
||||
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||
import { packageInvariantOwners } from './package-invariants.ts'
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
usesManualInvariantTree,
|
||||
} from './test-invariants.ts'
|
||||
|
||||
declare module 'cordis' {
|
||||
declare module '@deepseek-ai/cordis' {
|
||||
interface Context {
|
||||
testInvariantProbe: TestInvariantProbe
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
import { expect } from 'vitest'
|
||||
import { FiberState, Inject, RegistryService } from 'cordis'
|
||||
import type { Context, Plugin } from 'cordis'
|
||||
import { FiberState, Inject, RegistryService } from '@deepseek-ai/cordis'
|
||||
import type { Context, Plugin } from '@deepseek-ai/cordis'
|
||||
import { AttachmentStore } from '@deepseek-ai/dsh-attachment'
|
||||
import type {
|
||||
ImageAttachmentLimits,
|
||||
|
||||
@@ -165,7 +165,7 @@ function validateEntry(value: unknown, file: string, path: string): void {
|
||||
}
|
||||
recordPlugin(value, file)
|
||||
validateMetadata(value, file, path)
|
||||
if ((value.group === true || value.name === '@cordisjs/plugin-group') && isUnknownArray(value.config)) {
|
||||
if ((value.group === true || value.name === '@deepseek-ai/cordis-plugin-group') && isUnknownArray(value.config)) {
|
||||
for (let index = 0; index < value.config.length; index++) {
|
||||
validateEntry(value.config[index], file, `${path}.config[${index}]`)
|
||||
}
|
||||
@@ -175,7 +175,7 @@ function validateEntry(value: unknown, file: string, path: string): void {
|
||||
validateEntry(value.insert[index], file, `${path}.insert[${index}]`)
|
||||
}
|
||||
}
|
||||
if (value.name !== '@cordisjs/plugin-include') return
|
||||
if (value.name !== '@deepseek-ai/cordis-plugin-include') return
|
||||
const config = value.config
|
||||
if (!isRecord(config) || !isUnknownArray(config.patches)) return
|
||||
for (let index = 0; index < config.patches.length; index++) {
|
||||
|
||||
Reference in New Issue
Block a user