Files
deepseek-harness/scripts/experimental-package-policy.ts
T
ZiyaandZiyaZhang d6d51be4cb feat(experimental): 把个性化页面和插件推荐合并为实验性插件「个性化推荐」 (#7034)
* feat(experimental): ship the two card experiments as one Personalized recommendations bundle

@deepseek-ai/dsh-personalized-recommendations inserts the action card
service, its browser half, Personalized pages and Plugin recommendations
with their card bodies under the existing row ids. As the only layer that
declares those ids, the Plugins page addresses and switches each row,
including the two shared card rows that were read-only while two bundles
inserted them.

The two experiment packages stop being bundles; the new bundle takes their
place in the official lists and the dsh installation, with the personalized
pages icon, localized title and description, and a feature preview of both
cards. The two feature rows describe what they do on the bundle page.

* fix(experimental): drop the model reason line from plugin recommendation cards

The reason follows the language of the user's question while the catalog
description below it follows the interface language, so the two lines could
differ in language and largely repeat each other; the answer already gives
the reason. The card keeps the catalog title and description, both in the
interface language, as its details target.

* test(web): refresh the card fixtures for the Personalized recommendations bundle

Both card replays enable the new bundle, so each Session lists both card
skills, and each skill's catalog lists Personalized recommendations in place
of the two former bundles. The plugin card goldens lose the reason line.

---------

Co-authored-by: ZiyaZhang <[email protected]>
2026-10-23 07:55:49 +00:00

80 lines
4.5 KiB
TypeScript

/** Experimental package identities, publication policy, and retained npm names. */
/**
* Experimental packages whose npm names omit the experimental prefix, by directory: identities retained across
* experimental classification and package-role moves, and packages named without the prefix so that leaving
* experimental status keeps their names.
*/
export const EXPERIMENTAL_PACKAGE_NAME_EXCEPTIONS: Readonly<Record<string, string>> = {
'packages/experimental/cua': '@deepseek-ai/dsh-cua',
'packages/experimental/cua-bundle': '@deepseek-ai/dsh-cua-bundle',
'packages/experimental/tool-session-query': '@deepseek-ai/dsh-tool-session-query',
'packages/experimental/session-title-all-prompts-llm': '@deepseek-ai/dsh-session-title-all-prompts-llm',
'packages/experimental/tool-terminal': '@deepseek-ai/dsh-tool-terminal',
'packages/experimental/tool-ralph': '@deepseek-ai/dsh-tool-ralph',
'packages/experimental/skill-badge': '@deepseek-ai/dsh-skill-badge',
'packages/experimental/hook-protocol': '@deepseek-ai/dsh-hook-protocol',
'packages/experimental/hooks-claude-code': '@deepseek-ai/dsh-hooks-claude-code',
'packages/experimental/hooks-codex': '@deepseek-ai/dsh-hooks-codex',
'packages/experimental/webhook': '@deepseek-ai/dsh-webhook',
'packages/experimental/webhook-github': '@deepseek-ai/dsh-webhook-github',
'packages/experimental/action-cards': '@deepseek-ai/dsh-action-cards',
'packages/experimental/client-ui-action-cards': '@deepseek-ai/dsh-client-ui-action-cards',
'packages/experimental/creation-recommendations': '@deepseek-ai/dsh-creation-recommendations',
'packages/experimental/client-ui-creation-recommendations': '@deepseek-ai/dsh-client-ui-creation-recommendations',
'packages/experimental/plugin-recommendations': '@deepseek-ai/dsh-plugin-recommendations',
'packages/experimental/client-ui-plugin-recommendations': '@deepseek-ai/dsh-client-ui-plugin-recommendations',
'packages/experimental/personalized-recommendations': '@deepseek-ai/dsh-personalized-recommendations',
} satisfies Record<`packages/experimental/${string}`, `@deepseek-ai/dsh-${string}`>
/** npm namespace for experimental packages without retained-name exceptions. */
export const EXPERIMENTAL_PACKAGE_NAME_PREFIX = '@deepseek-ai/dsh-experimental-'
const retainedNames = new Set(Object.values(EXPERIMENTAL_PACKAGE_NAME_EXCEPTIONS))
/**
* Identify an experimental npm package independently of its installed directory.
* @param name - complete npm package name, without a version or subpath.
* @returns Whether the name uses the experimental prefix or a retained name.
*/
export function isExperimentalPackageName(name: string): boolean {
return name.startsWith(EXPERIMENTAL_PACKAGE_NAME_PREFIX) || retainedNames.has(name)
}
/**
* Find experimental identities in module ids, paths, subpaths, or npm alias specifications.
* @param reference - package reference or bundler/runtime module identifier.
* @returns Whether a delimited package name identifies an experimental capability.
*/
export function hasExperimentalPackageReference(reference: string): boolean {
const normalized = reference.replaceAll('\\', '/')
return [...normalized.matchAll(/(?:^|[/:\u0000])(@deepseek-ai\/[^/@?#:\s]+)(?=$|[/@?#:])/g)]
.some(([, name]) => name !== undefined && isExperimentalPackageName(name))
}
/**
* Derive the package-owned plugin record namespace without changing persisted names.
* @param name - complete experimental npm package name.
* @returns Capability suffix, or undefined for a non-experimental name.
*/
export function experimentalPackageRecordNamespace(name: string): string | undefined {
if (!isExperimentalPackageName(name)) return undefined
return name.slice(name.startsWith(EXPERIMENTAL_PACKAGE_NAME_PREFIX) ? EXPERIMENTAL_PACKAGE_NAME_PREFIX.length : '@deepseek-ai/dsh-'.length)
}
/** Experimental packages excluded from public releases and npm baselines. */
export const PRIVATE_EXPERIMENTAL_PACKAGE_DIRECTORIES: readonly string[] = []
/**
* Whether an experimental package publishes under the default-public policy.
* @param directory - repository-relative package directory.
* @param privateDirectories - experimental directories excluded from publication.
* @returns Whether the package publishes with the dsh family.
*/
export function isPublicExperimentalPackageDirectory(
directory: string,
privateDirectories: readonly string[] = PRIVATE_EXPERIMENTAL_PACKAGE_DIRECTORIES,
): boolean {
return /^packages\/experimental\/[^/]+$/.test(directory)
&& !privateDirectories.includes(directory)
}