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:
27
packages/scaffold/helper/src/templates/assets/README.md.tpl
Normal file
27
packages/scaffold/helper/src/templates/assets/README.md.tpl
Normal 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`.
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
lib/
|
||||
.env
|
||||
.sessions/
|
||||
*.tsbuildinfo
|
||||
20
packages/scaffold/helper/src/templates/assets/index.ts.tpl
Normal file
20
packages/scaffold/helper/src/templates/assets/index.ts.tpl
Normal 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
|
||||
}
|
||||
@@ -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,
|
||||
}))
|
||||
@@ -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(() => () => {})
|
||||
}
|
||||
@@ -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 }),
|
||||
}))
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2024",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"composite": true,
|
||||
"outDir": "lib",
|
||||
"rootDir": ".",
|
||||
"types": ["node"],
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}))
|
||||
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
110
packages/scaffold/helper/src/templates/project-template.ts
Normal file
110
packages/scaffold/helper/src/templates/project-template.ts
Normal 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',
|
||||
}
|
||||
}
|
||||
19
packages/scaffold/helper/src/templates/template-assets.ts
Normal file
19
packages/scaffold/helper/src/templates/template-assets.ts
Normal 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))
|
||||
}
|
||||
44
packages/scaffold/helper/src/templates/text-template.ts
Normal file
44
packages/scaffold/helper/src/templates/text-template.ts
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user