refactor(packages): dissolve ui/ and rename sdk/ to scaffold/

git mv per the regrouping RFC: the five human-collaboration seams and
tui join packages/interaction/, app-boot becomes packages/boot/, and
jsonrpc joins the renamed scaffold/ (formerly sdk/) as its server half
beside client/protocol/create-sdk/helper/scripts/telemetry, whose
folders drop the legacy sdk- prefix. Three new group README triplets
replace the ui/ and sdk/ ones; tsconfig references/paths/globs,
knip keys, vitest globs, gate scripts, catalogs, docs, and the
lockfile follow. Adds the four settled FIXME rename markers
(dsh-sdk-server, dsh-sdk-telemetry, dsh-sdk-helper, dsh-sdk-scripts).

The scaffold folders diverge from their npm names until those renames
land, so tsconfig.base.json maps the three affected names explicitly
beside the group wildcard. Also repairs two pre-existing stale-path
classes the strengthened sweep surfaced: docs/web-styling.md's retired
web-ui host package and type-model spec fixture-literal joins.

app-boot's three Loader-composition specs time out at the default 5s
under full-suite parallel load on this filesystem (pre-existing;
pass isolated with --testTimeout=30000); interaction/scaffold/boot
suites otherwise green (687 passed).
This commit is contained in:
Tianyi Cui
2026-07-30 03:13:49 +08:00
parent 7e445c3a67
commit 3fc35c91ff
351 changed files with 368 additions and 311 deletions

View File

@@ -0,0 +1,27 @@
# {{name}}
{{description}}
Built with the DeepSeek Harness SDK using the {{model}} model.
{{#if isAcp}}
## Run as an ACP automation server
Run `{{packageManager}} start` and configure a programmatic ACP client to launch this project. Standard output is reserved for ACP JSON-RPC.
{{else}}
## Embed the harness
Import and call the exported `main()` from `index.ts` in your host application.
{{/if}}
## Development
Install NPM dependencies with `{{packageManager}} {{installArgs}}`, then use:
- `dev`: `{{packageManager}} run dev`
- `build`: `{{packageManager}} {{buildArgs}}`
- `typecheck`: `{{packageManager}} run typecheck`
- `start`: `{{packageManager}} start`
- `config`: `{{packageManager}} run config`
Edit `cordis.yml` to change the runtime plugin tree. Add or remove builtin features with `{{packageManager}} exec dsh-sdk config`.

View File

@@ -0,0 +1,5 @@
node_modules/
lib/
.env
.sessions/
*.tsbuildinfo

View File

@@ -0,0 +1,20 @@
{{#if isAcp}}
import { startSDK, type SdkBootContext } from '@deepseek-ai/dsh-scripts'
{{else}}
import { randomUUID } from 'node:crypto'
import { SessionId } from '@deepseek-ai/dsh-session'
import { startSDK, type SdkBootContext } from '@deepseek-ai/dsh-scripts'
{{/if}}
/** Boot this project's cordis.yml when invoked by dsh-scripts. */
export async function main(boot: SdkBootContext) {
const ctx = await startSDK(new URL('./cordis.yml', import.meta.url))
{{#if isEmbed}}
await ctx.agents.create({
sessionId: SessionId(`main-session-${randomUUID()}`),
meta: { cwd: boot.cwd },
agentOptions: { model: {{modelLiteral}} },
})
{{/if}}
return ctx
}

View File

@@ -0,0 +1,13 @@
import { defineConfig } from 'tsdown'
import { PluginBuild } from '@deepseek-ai/dsh-scripts/dev/tsdown-config'
export default defineConfig(PluginBuild({
entry: ['src/index.ts'],
outDir: 'lib',
format: ['esm'],
platform: 'node',
target: 'es2024',
fixedExtension: false,
dts: true,
clean: false,
}))

View File

@@ -0,0 +1,9 @@
/** Local Cordis plugin. */
import type { Context } from 'cordis'
export const name = '{{pluginName}}'
/** Register this plugin's project-local behavior. */
export function apply(ctx: Context): void {
ctx.effect(() => () => {})
}

View File

@@ -0,0 +1,17 @@
/** Project-local model-facing tool. */
import type { Context } from 'cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = '{{pluginName}}'
export const inject = ['tools']
/** Register the {{toolName}} tool. */
export function apply(ctx: Context): void {
ctx.tools.register(defineTool({
name: '{{toolName}}',
description: 'Project-local {{toolTitle}} tool.',
parameters: {},
execute: async () => [{ type: 'text', text: '{{toolName}} completed.' }],
presentCall: args => ({ card: 'generic', title: '{{toolTitle}}', kind: 'other', rawInput: args }),
}))
}

View File

@@ -0,0 +1,14 @@
{
"name": {{name}},
"version": "0.0.0",
"private": true,
"description": {{description}},
"type": "module",
"scripts": {
"build": "dsh-sdk build",
"typecheck": "tsc -b",
"config": "dsh-sdk config"
},
"dependencies": {{dependencies}},
"devDependencies": {{devDependencies}}
}

View File

@@ -0,0 +1,3 @@
You are a coding assistant powered by the \{{model}} model. Your working directory is \{{cwd}}.
Verify your work by running the code or tests. Keep answers brief and factual.

View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2024",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"declaration": true,
"composite": true,
"outDir": "lib",
"rootDir": ".",
"types": ["node"],
"skipLibCheck": true
}
}

View File

@@ -0,0 +1,13 @@
import { defineConfig } from 'tsdown'
import { ProjectBuild } from '@deepseek-ai/dsh-scripts/dev/tsdown-config'
export default defineConfig(ProjectBuild({
entry: ['index.ts'],
outDir: '.',
format: ['esm'],
platform: 'node',
target: 'es2024',
fixedExtension: false,
dts: false,
clean: false,
}))

View File

@@ -0,0 +1 @@
nodeLinker: node-modules

View File

@@ -0,0 +1,110 @@
/**
* Strict Handlebars wrapper and complete-file SDK project artifacts.
*
* @module @deepseek-ai/dsh-helper/templates/project-template
*/
import { PackageJsonFile } from '../documents/package-json-file.ts'
import { TextProjectFile } from '../documents/project-file.ts'
import type { PackageManagerName } from '../package-managers/package-manager.ts'
import { baselineNpmDependencies } from '../project/npm-dependency-policy.ts'
import type { ProjectProfile, RunInterface } from '../project/types.ts'
import { loadHelperTemplate } from './template-assets.ts'
import type { TextTemplate } from './text-template.ts'
/** Stable typed view consumed by all generated text artifacts. */
export interface ProjectTemplateContext {
name: string
description: string
releaseVersion: string
model: string
modelLiteral: string
isAcp: boolean
isEmbed: boolean
packageManager: PackageManagerName
installArgs: string
buildArgs: string
}
/** Complete project-file template artifact. */
export class TemplateArtifact<TModel extends object> extends TextProjectFile {
/** Render and own one complete project file. */
constructor(relativePath: string, template: TextTemplate<TModel>, model: TModel) {
super(relativePath, template.render(model))
}
}
const README_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('README.md.tpl')
const PACKAGE_JSON_TEMPLATE = loadHelperTemplate<{
name: string
description: string
dependencies: string
devDependencies: string
}>('package.json.tpl')
const INDEX_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('index.ts.tpl')
const TSDOWN_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('tsdown.config.ts.tpl')
const TSCONFIG_BASE_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('tsconfig.base.json.tpl')
const GITIGNORE_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('gitignore.tpl')
const YARNRC_TEMPLATE = loadHelperTemplate<ProjectTemplateContext>('yarnrc.yml.tpl')
/** Build the template model for one project and selected run interface. */
export function createProjectTemplateContext(
profile: ProjectProfile,
runInterface: RunInterface = profile.runInterface,
): ProjectTemplateContext {
return {
name: profile.name,
description: profile.description,
releaseVersion: profile.releaseVersion,
model: profile.runtime.model,
modelLiteral: JSON.stringify(profile.runtime.model),
isAcp: runInterface === 'acp',
isEmbed: runInterface === 'embed',
packageManager: profile.packageManager.name,
installArgs: profile.packageManager.installCommand().join(' '),
buildArgs: profile.packageManager.buildCommand().join(' '),
}
}
/** Render the complete root package defaults before structured contributions merge. */
export function createPackageJsonDoc(context: ProjectTemplateContext): PackageJsonFile {
const npmDependencies = baselineNpmDependencies(context.releaseVersion)
return PackageJsonFile.create(PACKAGE_JSON_TEMPLATE.render({
name: JSON.stringify(context.name),
description: JSON.stringify(context.description),
dependencies: JSON.stringify(npmDependencies.dependencies),
devDependencies: JSON.stringify(npmDependencies.devDependencies),
}))
}
/** Build interface-independent one-shot project artifacts. */
export function createBaselineProjectArtifacts(
context: ProjectTemplateContext,
): TemplateArtifact<ProjectTemplateContext>[] {
return [
new TemplateArtifact('tsdown.config.ts', TSDOWN_TEMPLATE, context),
new TemplateArtifact('tsconfig.base.json', TSCONFIG_BASE_TEMPLATE, context),
new TemplateArtifact('.gitignore', GITIGNORE_TEMPLATE, context),
...context.packageManager === 'yarn'
? [new TemplateArtifact('.yarnrc.yml', YARNRC_TEMPLATE, context)]
: [],
]
}
/** Build files owned by the selected app feature option. */
export function createAppProjectArtifacts(
context: ProjectTemplateContext,
): TemplateArtifact<ProjectTemplateContext>[] {
return [
new TemplateArtifact('README.md', README_TEMPLATE, context),
new TemplateArtifact('index.ts', INDEX_TEMPLATE, context),
]
}
/** Build package scripts owned by the selected app feature option. */
export function createAppPackageScripts(): Readonly<Record<'dev' | 'start', string>> {
return {
dev: 'dsh-sdk dev index.ts',
start: 'dsh-sdk start index.js',
}
}

View File

@@ -0,0 +1,19 @@
/**
* Asset loader for templates owned by dsh-helper.
*
* @module @deepseek-ai/dsh-helper/templates/template-assets
*/
import { TextTemplate } from './text-template.ts'
/**
* Load one helper-owned template in source and bundled layouts.
* @param filename - basename under the helper template asset directory.
* @returns compiled typed template.
*/
export function loadHelperTemplate<TModel extends object>(filename: string): TextTemplate<TModel> {
if (filename.includes('/') || filename.includes('\\')) {
throw new Error(`helper template filename must not contain a directory: ${filename}`)
}
return TextTemplate.fromFile<TModel>(new URL(`./assets/${filename}`, import.meta.url))
}

View File

@@ -0,0 +1,44 @@
/**
* Strict typed rendering for package-owned text templates.
*
* @module @deepseek-ai/dsh-helper/templates/text-template
*/
import { readFileSync } from 'node:fs'
import Handlebars from 'handlebars'
/** Strict Handlebars template with no HTML escaping or custom extensions. */
export class TextTemplate<TModel extends object> {
private readonly renderer: Handlebars.TemplateDelegate<TModel>
/**
* Compile one template under the SDK's fixed rendering policy.
* @param source - complete template source.
*/
constructor(source: string) {
const handlebars = Handlebars.create()
this.renderer = handlebars.compile<TModel>(source, {
strict: true,
noEscape: true,
preventIndent: true,
})
}
/**
* Load a template asset owned by the calling package.
* @param url - source or bundled asset URL.
* @returns compiled template.
*/
static fromFile<T extends object>(url: URL): TextTemplate<T> {
return new TextTemplate<T>(readFileSync(url, 'utf8'))
}
/**
* Render text from one complete typed model.
* @param model - values referenced by the template.
* @returns rendered text.
*/
render(model: TModel): string {
return this.renderer(model)
}
}