Merge remote-tracking branch 'origin/master' into worktree/attachment-alignment-2

This commit is contained in:
creatixchu
2026-08-12 15:19:32 +08:00
133 changed files with 3306 additions and 552 deletions
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/host/README.md
README.md: 926cb0b6b87a8ee76cb2dab745a31f620f4e7f5c
README.zh.md: 7ef057ee56e56ddc2baa7092ccbe44fb161b7448
README.md: 1c3b6ab3192fe35a5532183414e45d1b02325e57
README.zh.md: a062d5fce055e3266953993d532a86bec1375377
+1
View File
@@ -13,6 +13,7 @@ The host side of the dsh web GUI: the API gateway every client shape shares, and
| [`directory-picker-native/`](directory-picker-native/README.md) | Native directory-picker backend and browser interaction | registers `ctx.directoryPicker` |
| [`directory-picker-browse/`](directory-picker-browse/README.md) | In-app directory-browser backend and interaction | registers `ctx.directoryPicker` |
| [`directory-picker-auto/`](directory-picker-auto/README.md) | Host-adaptive picker composition | mounts a backend |
| [`plugin-inventory/`](plugin-inventory/README.md) | Read-only projection of current Loader entries | Remote `pluginInventory/list` |
`apiproxy` remains transport-independent; [`client/connection`](../client/connection/README.md) supplies the browser/HTTP carrier. Picker implementations replace one another behind the shared seam.
+1
View File
@@ -13,6 +13,7 @@ dsh Web GUI 的宿主侧:所有客户端形态共享的 API 网关,以及承
| [`directory-picker-native/`](directory-picker-native/README.md) | 原生目录选择器后端和浏览器交互 | 注册 `ctx.directoryPicker` |
| [`directory-picker-browse/`](directory-picker-browse/README.md) | 应用内目录浏览器后端和交互 | 注册 `ctx.directoryPicker` |
| [`directory-picker-auto/`](directory-picker-auto/README.md) | 宿主自适应选择器组合 | 挂载一个后端 |
| [`plugin-inventory/`](plugin-inventory/README.md) | 当前 Loader 条目的只读投影 | Remote `pluginInventory/list` |
`apiproxy` 保持传输无关;[`client/connection`](../client/connection/README.md) 提供浏览器/HTTP 载体。选择器实现可在共享 seam 后互相替换。
@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/host/plugin-inventory/README.md
README.md: 23fbf07d7900ecc881f81b5da3f8cbe6a45669de
README.zh.md: 87058cde595b83e980b8f3cec4192e6099b8d9ea
+22
View File
@@ -0,0 +1,22 @@
# @deepseek-ai/dsh-host-plugin-inventory
English | [中文](README.zh.md)
Read-only Host projection of the current Cordis Loader tree. `PluginInventoryService` registers the `pluginInventory` service and publishes one generated direct Remote, `pluginInventory/list`. Every call reads `ctx.loader.entries()` directly, skips structural group rows, and returns the remaining entries in Loader order with only their Loader entry id, module specifier, effective enablement, and current root Fiber phase.
The phase is `pending`, `loading`, `active`, `failed`, or `unloading`; it is `null` when the entry has no live root Fiber. The snapshot is intentionally point-in-time: Loader remains the sole lifecycle authority, while this package owns no cache, history, provenance model, event stream, or mutation path. Its public payload types live under `./types`, and TypeRT generates the Host and Client Remote artifacts exposed by `./typert` and `./remote`.
The service is Remote-only and deliberately declares no same-process Cordis `Context` merge. Client packages consume it through the explicit [`api-remotes`](../../api/remotes/README.md) assembly rather than importing the Host implementation.
## Model Experience
None, as this Host-only inventory projection registers no prompt, tool, message, or provider request.
#### KV Cache effect
None; this package never assembles model input.
## Known Limitations and Deferred Work
- **Point-in-time state only** — the result contains no durable failure history or subscription; a missing root Fiber is reported as `null`, regardless of why no live root exists.
- **No provenance or mutation** — the service does not identify which bundle, profile, or override introduced an entry, and it cannot enable, disable, add, or remove plugins.
@@ -0,0 +1,22 @@
# @deepseek-ai/dsh-host-plugin-inventory
[English](README.md) | 中文
当前 Cordis Loader 树的只读 Host 投影。`PluginInventoryService` 注册 `pluginInventory` 服务,并发布一个由 TypeRT 生成的直接 Remote`pluginInventory/list`。每次调用都直接读取 `ctx.loader.entries()`,跳过结构性的 group 行,再按 Loader 顺序返回其余条目,并且只包含 Loader 条目 id、模块标识、有效启用状态与当前根 Fiber 阶段。
阶段为 `pending``loading``active``failed``unloading`;条目没有存活的根 Fiber 时则为 `null`。该快照刻意只表示调用当下:Loader 仍是唯一的生命周期权威,本包不拥有缓存、历史、来源模型、事件流或修改路径。公开 payload 类型位于 `./types`TypeRT 生成由 `./typert``./remote` 导出的 Host 和 Client Remote 产物。
该服务仅供 Remote 使用,刻意不声明同进程 Cordis `Context` merge。Client 包通过显式的 [`api-remotes`](../../api/remotes/README.md) 组合消费它,而不导入 Host 实现。
## 模型体验
无,因为这个仅限 Host 的清单投影不注册提示词、工具、消息或提供方请求。
#### KV Cache 影响
无;本包从不组装模型输入。
## 已知限制与暂缓事项
- **仅表示调用当下** —— 结果不包含持久的失败历史或订阅;只要不存在存活的根 Fiber,就会报告 `null`,而不区分其原因。
- **无来源与修改能力** —— 服务不识别条目由哪个 bundle、profile 或 override 引入,也不能启用、停用、添加或移除插件。
@@ -0,0 +1,68 @@
{
"name": "@deepseek-ai/dsh-host-plugin-inventory",
"description": "Read-only Remote projection of current Cordis Loader plugin state",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
"repository": {
"type": "git",
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
"directory": "packages/host/plugin-inventory"
},
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"exports": {
".": {
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./types": {
"types": "./lib/types/types.d.ts",
"default": "./lib/types/types.js"
},
"./typert": {
"types": "./lib/typert.host.d.ts",
"default": "./lib/typert.host.js"
},
"./remote": {
"types": "./lib/typert.remote-client.d.ts",
"default": "./lib/typert.remote-client.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.js",
"lib/types/**/*.d.ts",
"lib/typert.host.js",
"lib/typert.host.d.ts",
"lib/typert.remote-client.js",
"lib/typert.remote-client.d.ts"
],
"license": "BSD-3-Clause",
"dependencies": {
"zod": "^4.4.3"
},
"peerDependencies": {
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
"@deepseek-ai/dsh-brand": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-type-meta": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
},
"devDependencies": {
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
"@deepseek-ai/dsh-brand": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-type-meta": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
}
}
@@ -0,0 +1,72 @@
/** Read-only projection of the current Cordis Loader plugin entries. */
import type { Context, FiberState } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/cordis-plugin-loader'
import { GatewayService, Remote } from '@deepseek-ai/dsh-type-meta'
// TypeRT-generated ./typert and ./remote artifacts import Zod at runtime.
import type {} from 'zod'
import type {
PluginEntryId,
PluginFiberPhase,
PluginInventoryEntry,
PluginInventorySnapshot,
} from './types.ts'
export type * from './types.ts'
/** Brand an existing Loader-tree entry id at the owning boundary. */
function pluginEntryId(value: string): PluginEntryId {
return value as PluginEntryId
}
/** Runtime mirror: FiberState is a cross-package const enum. */
const FIBER_STATE = {
PENDING: 0 as FiberState.PENDING,
LOADING: 1 as FiberState.LOADING,
ACTIVE: 2 as FiberState.ACTIVE,
FAILED: 3 as FiberState.FAILED,
DISPOSED: 4 as FiberState.DISPOSED,
UNLOADING: 5 as FiberState.UNLOADING,
} as const
/** Complete public projection of Cordis Fiber states. */
const FIBER_PHASE = {
[FIBER_STATE.PENDING]: 'pending',
[FIBER_STATE.LOADING]: 'loading',
[FIBER_STATE.ACTIVE]: 'active',
[FIBER_STATE.FAILED]: 'failed',
[FIBER_STATE.DISPOSED]: null,
[FIBER_STATE.UNLOADING]: 'unloading',
} as const satisfies Record<FiberState, PluginFiberPhase>
/** Remote-only service exposing the Loader's current non-group entry state. */
export class PluginInventoryService extends GatewayService {
static inject = ['loader']
constructor(ctx: Context) {
super(ctx, 'pluginInventory')
}
/**
* Read the Loader directly on every call. Cordis's internal plugin/status
* events already maintain Entry.fiber and Fiber.state, so a second cache
* would only add another lifecycle truth to keep synchronized.
* @returns Current non-group Loader entries in Loader order.
*/
@Remote('list')
list(): PluginInventorySnapshot {
const entries: PluginInventoryEntry[] = []
for (const entry of this.ctx.loader.entries()) {
if (entry.options.group) continue
entries.push({
entryId: pluginEntryId(entry.id),
moduleName: entry.options.name,
enabled: !entry.disabled,
fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state],
})
}
return { entries }
}
}
export default PluginInventoryService
@@ -0,0 +1,20 @@
/** Package-owned invariant companion. @module @deepseek-ai/dsh-host-plugin-inventory/invariant */
/* jscpd:ignore-start */
import type { Context } from '@deepseek-ai/cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-host-plugin-inventory'
/** Cordis companion plugin name. */
export const name = 'host-plugin-inventory-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** No runtime invariant: every snapshot is projected directly from Loader-owned state. */
const install: InvariantInstaller = () => {}
/** Register this package's invariant companion. */
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */
@@ -0,0 +1,28 @@
import type { Branded } from '@deepseek-ai/dsh-brand'
/** Stable Loader-tree identity of one configured plugin entry. */
export type PluginEntryId = Branded<'PluginEntryId'>
/** Lifecycle state of an entry's root Fiber, or null when it has no live root Fiber. */
export type PluginFiberPhase =
| 'pending'
| 'loading'
| 'active'
| 'failed'
| 'unloading'
| null
/** One non-group Loader entry exposed to trusted clients. */
export interface PluginInventoryEntry {
readonly entryId: PluginEntryId
/** Exact module specifier imported by the Loader entry. */
readonly moduleName: string
/** Effective Loader enablement, including disabled ancestor groups. */
readonly enabled: boolean
readonly fiberPhase: PluginFiberPhase
}
/** Point-in-time inventory returned by the plugin inventory Remote. */
export interface PluginInventorySnapshot {
readonly entries: readonly PluginInventoryEntry[]
}
@@ -0,0 +1,16 @@
import { Context } from '@deepseek-ai/cordis'
import { describe, expect, it } from 'vitest'
import InvariantService from '@deepseek-ai/dsh-invariants'
import * as PluginInventoryInvariant from '../src/invariant.ts'
describe('plugin-inventory invariant companion', () => {
it('registers the package-owned empty installer', async () => {
const ctx = new Context()
await ctx.plugin(InvariantService, { enabled: true })
const fiber = ctx.plugin(PluginInventoryInvariant)
await expect(fiber.await()).resolves.toBeDefined()
await fiber.dispose()
await expect(ctx.plugin(PluginInventoryInvariant).await()).resolves.toBeDefined()
await ctx.fiber.dispose()
})
})
@@ -0,0 +1,89 @@
import { afterEach, describe, expect, it } from 'vitest'
import { Context, type Plugin } from '@deepseek-ai/cordis'
import Loader from '@deepseek-ai/cordis-plugin-loader'
import { remoteMethods } from '@deepseek-ai/dsh-type-meta'
import PluginInventoryService from '../src/index.ts'
const contexts: Context[] = []
afterEach(async () => {
await Promise.all(contexts.splice(0).map(ctx => ctx.fiber.dispose()))
})
const activePlugin: Plugin.Function = () => {}
const pendingPlugin: Plugin.Object = {
inject: ['neverReady'],
apply() {},
}
async function harness(): Promise<{
ctx: Context
inventory: PluginInventoryService
}> {
const ctx = new Context()
contexts.push(ctx)
await ctx.plugin(Loader)
ctx.loader.builtins.active = activePlugin
ctx.loader.builtins.pending = pendingPlugin
await ctx.plugin(PluginInventoryService)
const inventory = ctx.get('pluginInventory') as PluginInventoryService
return { ctx, inventory }
}
describe('PluginInventoryService', () => {
it('publishes one direct list method under the pluginInventory namespace', async () => {
const { inventory } = await harness()
expect(inventory.typertGateway).toMatchObject({
serviceKey: 'pluginInventory',
namespace: 'pluginInventory',
})
expect(remoteMethods(inventory)).toEqual([
{ method: 'list', invocation: { kind: 'direct' } },
])
})
it('projects current non-group Loader entries without a second cache', async () => {
const { ctx, inventory } = await harness()
const activeId = await ctx.loader.create({ name: 'cordis:active' })
const pendingId = await ctx.loader.create({ name: 'cordis:pending' })
const disabledId = await ctx.loader.create({
name: 'cordis:not-installed',
disabled: true,
})
await ctx.loader.create({ name: 'cordis:active', group: true })
expect(inventory.list()).toEqual({
entries: [
{
entryId: activeId,
moduleName: 'cordis:active',
enabled: true,
fiberPhase: 'active',
},
{
entryId: pendingId,
moduleName: 'cordis:pending',
enabled: true,
fiberPhase: 'pending',
},
{
entryId: disabledId,
moduleName: 'cordis:not-installed',
enabled: false,
fiberPhase: null,
},
],
})
await ctx.loader.update(activeId, { disabled: true })
expect(inventory.list().entries.find(entry => entry.entryId === activeId)).toEqual({
entryId: activeId,
moduleName: 'cordis:active',
enabled: false,
fiberPhase: null,
})
await ctx.loader.remove(pendingId)
expect(inventory.list().entries.some(entry => entry.entryId === pendingId)).toBe(false)
})
})
@@ -0,0 +1,27 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib/types"
},
"include": [
"src"
],
"references": [
{
"path": "../../../vendor/cordis"
},
{
"path": "../../../vendor/loader"
},
{
"path": "../../util/brand"
},
{
"path": "../../typert/type-meta"
},
{
"path": "../../support/invariants"
}
]
}