fix: rebase 2

This commit is contained in:
imccyu
2026-08-13 02:22:10 +08:00
parent 39f55a049f
commit 45dfff0cdd
31 changed files with 1073 additions and 2071 deletions

View File

@@ -156,7 +156,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'conversation.chat.node\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'client-ui-feedback FeedbackActions id \'feedback\'',
'client-ui-message-feedback MessageFeedbackActions id \'feedback\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.assistant-actions\', () => ctx.slots.register(\n { name: \'conversation.chat.assistant-actions\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -333,8 +333,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
declaredBy: 'an entry in \'conversation\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'client-ui-conversation ApprovalPanel',
'client-ui-question QuestionComposer',
'client-ui-subagent SubagentReadOnlyComposer',
'client-ui-user-questions QuestionComposer',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.composer\', () => ctx.slots.register(\n { name: \'conversation.composer\', select: owner => null },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -531,8 +531,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'conversation.hero.workspace\' (client-ui-workspace), so it exists while that entry is mounted',
occupants: [
'client-ui-directory-picker-browse BrowseDirectoryFlow',
'client-ui-directory-picker-native NativeDirectoryFlow',
'client-ui-directory-picker BrowseDirectoryFlow',
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.hero.workspace.directoryFlow\', () => ctx.slots.register(\n { name: \'conversation.hero.workspace.directoryFlow\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -669,7 +669,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'conversation.composer.bar\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'client-ui-model ModelSelect',
'client-ui-model-selection ModelSelect',
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.input.model\', () => ctx.slots.register(\n { name: \'conversation.input.model\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -679,8 +679,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
key: 'conversation.input.overlay',
kind: 'list',
scope: 'session',
summary: 'The InputBar floating overlay anchor: MenuView (this package) and the popupSelect shell (ui-command) contribute list entries; each reads its own store and renders null while closed.',
doc: 'The InputBar floating overlay anchor: MenuView (this package) and the\npopupSelect shell (ui-command) contribute list entries; each reads its\nown store and renders null while closed. Declared (children table) by\nui-conversation\'s composer entry; the anchor hides with the input\nunder a takeover.',
summary: 'The InputBar floating overlay anchor: MenuView (this package) and the popupSelect shell (ui-commands) contribute list entries; each reads its own store and renders null while closed.',
doc: 'The InputBar floating overlay anchor: MenuView (this package) and the\npopupSelect shell (ui-commands) contribute list entries; each reads its\nown store and renders null while closed. Declared (children table) by\nui-conversation\'s composer entry; the anchor hides with the input\nunder a takeover.',
registerOptions: [
{
name: 'id',
@@ -717,12 +717,12 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'conversation\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'client-ui-command PopupSelectView id \'command-popup\'',
'client-ui-slash MenuView id \'slash-menu\'',
'client-ui-commands PopupSelectView id \'command-popup\'',
'client-ui-input-trigger MenuView id \'slash-menu\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.input.overlay\', () => ctx.slots.register(\n { name: \'conversation.input.overlay\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
source: 'packages/client/ui-slash/src/client/slots.ts:24',
source: 'packages/client/ui-input-trigger/src/client/slots.ts:24',
},
{
key: 'conversation.input.plan',
@@ -909,8 +909,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
declaredBy: 'an entry in \'conversation.session.header\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'client-ui-agent-preset AgentPresetLabel id \'agent-preset\'',
'client-ui-jobs JobListAction id \'job-list\'',
'client-ui-subagent SubagentCatalogAction id \'subagent-catalog\'',
'client-ui-task TaskListAction id \'task-list\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.session.header.actions\', () => ctx.slots.register(\n { name: \'conversation.session.header.actions\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -960,7 +960,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'conversation.session.header\' (client-ui-conversation), so it exists while that entry is mounted',
occupants: [
'session-export SessionExportHeader id \'session-export\'',
'session-log-download SessionLogDownloadHeaderAction id \'session-log-download\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.session.header.utilities\', () => ctx.slots.register(\n { name: \'conversation.session.header.utilities\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -1187,7 +1187,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
'client-locale LanguageRow id \'language\'',
'client-ui-agent-preset AgentPresetRow id \'agent-preset\'',
'client-ui-conversation EnterBehaviorRow id \'composer-enter\'',
'client-ui-permission PermissionRow id \'permission\'',
'client-ui-permission-presets PermissionRow id \'permission\'',
'client-ui-theme AppearanceRow id \'appearance\'',
],
replaceRisk: 'none',
@@ -1259,8 +1259,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'sidebar.settings\' (client-ui-settings-general), so it exists while that entry is mounted',
occupants: [
'client-ui-models DeepSeekOnboardingDialog id \'deepseek-official\'',
'client-ui-settings-general WelcomeNotice id \'welcome-notice\'',
'client-ui-settings-models DeepSeekOnboardingDialog id \'deepseek-official\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'settings.onboarding\', () => ctx.slots.register(\n { name: \'settings.onboarding\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -1303,15 +1303,15 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
keyDomain: '',
hookContext: '',
slotInject: '',
declaredBy: 'an entry in \'settings.plugins.tab\' (client-ui-plugin-config), so it exists while that entry is mounted',
declaredBy: 'an entry in \'settings.plugins.tab\' (client-ui-settings-plugins), so it exists while that entry is mounted',
occupants: [
'client-ui-plugin-config BashCard id \'bash\'',
'client-ui-plugin-config AgentLoopCard id \'agent-loop\'',
'client-ui-plugin-config WebSearchCard id \'web-search\'',
'client-ui-settings-plugins BashCard id \'bash\'',
'client-ui-settings-plugins AgentLoopCard id \'agent-loop\'',
'client-ui-settings-plugins WebSearchCard id \'web-search\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'settings.plugin.item\', () => ctx.slots.register(\n { name: \'settings.plugin.item\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
source: 'packages/client/ui-plugin-config/src/client/slot-contract.ts:16',
source: 'packages/client/ui-settings-plugins/src/client/slot-contract.ts:16',
},
{
key: 'settings.plugins.tab',
@@ -1350,10 +1350,10 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
keyDomain: '',
hookContext: '',
slotInject: '',
declaredBy: 'an entry in \'settings.section\' (client-ui-plugin-config), so it exists while that entry is mounted',
declaredBy: 'an entry in \'settings.section\' (client-ui-settings-plugins), so it exists while that entry is mounted',
occupants: [
'client-ui-plugin-config ConfigurablePluginsTab id \'configurable\'',
'client-ui-plugins PluginSettingsSection id \'all\'',
'client-ui-settings-plugin-inventory PluginInventorySettingsTab id \'all\'',
'client-ui-settings-plugins ConfigurablePluginsTab id \'configurable\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'settings.plugins.tab\', () => ctx.slots.register(\n { name: \'settings.plugins.tab\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -1399,9 +1399,9 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
declaredBy: 'an entry in \'sidebar.settings\' (client-ui-settings-general), so it exists while that entry is mounted',
occupants: [
'client-ui-agent-preset AgentPresetSection id \'agent-presets\'',
'client-ui-models ModelsSection id \'models\'',
'client-ui-plugin-config PluginConfigSection id \'plugins\'',
'client-ui-settings-general GeneralSection id \'general\'',
'client-ui-settings-models ModelsSection id \'models\'',
'client-ui-settings-plugins PluginsSettingsSection id \'plugins\'',
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'settings.section\', () => ctx.slots.register(\n { name: \'settings.section\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
@@ -1617,8 +1617,8 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
slotInject: '',
declaredBy: 'an entry in \'sidebar.workspaces\' (client-ui-workspace), so it exists while that entry is mounted',
occupants: [
'client-ui-directory-picker-browse BrowseDirectoryFlow',
'client-ui-directory-picker-native NativeDirectoryFlow',
'client-ui-directory-picker BrowseDirectoryFlow',
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'sidebar.workspaces.directoryFlow\', () => ctx.slots.register(\n { name: \'sidebar.workspaces.directoryFlow\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',

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/extensions/tool-cordis/README.md
README.md: 839963b3b611f35389f8e4a424746ad0fcf5d02e
README.zh.md: a4dd0686702c18fb329bdea42478ca74ca3a1502
README.md: 396a844014328da8cfad57fa7728793b91a9aff7
README.zh.md: b38a4b518a28f9af76ab22325606b8faa772c1c1

File diff suppressed because it is too large Load Diff

View File

@@ -14,8 +14,6 @@ import type { Agent } from '@deepseek-ai/dsh-agent'
import type {} from '@deepseek-ai/dsh-cordis-host-runner'
import { EVENT_API, INHERITED_CTX_API, SERVICE_API, TYPE_API } from './api-catalog.ts'
import type { EventApiEntry, InheritedApiEntry, ServiceApiEntry, ServiceApiMethod, TypeApiEntry } from './api-catalog.ts'
import { CLIENT_NOTES, CLIENT_SLOT_API } from './client-catalog.ts'
import type { ClientSlotEntry } from './client-catalog.ts'
import { FiberState, STATE_LABELS } from './fiber-state.ts'
/** One live service joined with what the generated catalog knows about it. */
@@ -332,72 +330,3 @@ export function describeEvents(events: readonly EventApiEntry[] = EVENT_API, nam
lines.push('waterfall listeners receive a trailing next() and MUST call it to delegate — returning without next() short-circuits the chain.')
return lines
}
/** One slot's compact listing row: what it is, and whether registering costs shipped UI. */
function slotSummaryLines(entry: ClientSlotEntry): string[] {
const lines = [`- ${entry.key} [${entry.kind}, ${entry.scope}] — ${entry.summary}`]
lines.push(entry.replaceRisk === 'shadows-shipped-ui'
? ` OCCUPIED — registering here REPLACES: ${entry.occupants.join('; ')}`
: ` additive${entry.occupants.length === 0 ? ' (no shipped entries)' : ` (beside: ${entry.occupants.join('; ')})`}`)
return lines
}
/** One slot's full teaching block: how to register, what arrives, what it costs. */
function slotDetailLines(entry: ClientSlotEntry): string[] {
const lines = [`- ${entry.key} [${entry.kind}, ${entry.scope}]`]
for (const docLine of entry.doc.split('\n')) lines.push(` ${docLine}`)
lines.push(` exists: ${entry.declaredBy}`)
lines.push(entry.replaceRisk === 'shadows-shipped-ui'
? ` OCCUPIED — registering here REPLACES: ${entry.occupants.join('; ')}`
: ` additive${entry.occupants.length === 0 ? ' (no shipped entries)' : ` (beside: ${entry.occupants.join('; ')})`}`)
if (entry.keyDomain !== '') lines.push(` key domain: ${entry.keyDomain}`)
lines.push(` register options besides name:${entry.registerOptions.length === 0 ? ' none' : ''}`)
for (const option of entry.registerOptions) {
lines.push(` ${option.name} (${option.requirement}, ${option.type}) — ${option.doc}`)
}
lines.push(entry.ownerProps.length === 0
? ' owner props: none — the owner supplies only the render site'
: ' owner props (the shapes the owner passes down):')
for (const declaration of entry.ownerProps) {
for (const declLine of declaration.split('\n')) lines.push(` ${declLine}`)
}
if (entry.ownerPropsReferences.length > 0) {
lines.push(` shapes those fields reference, not expanded here: ${entry.ownerPropsReferences.join(', ')}`
+ ' — read the field as the contract above describes it rather than the whole shape')
}
lines.push(' framework props for this scope:')
for (const prop of entry.standardProps) lines.push(` ${prop}`)
if (entry.slotInject !== '') lines.push(` slot-level inject face every entry receives: ${entry.slotInject}`)
if (entry.hookContext !== '') lines.push(` per-render-site hook context: ${entry.hookContext}`)
lines.push(' minimal browser half:')
for (const codeLine of entry.example.split('\n')) lines.push(` ${codeLine}`)
return lines
}
/**
* The `client` section: the browser half's slot surface — every seat a dynamic
* package can contribute UI into, whether taking it costs shipped UI, and (with
* an exact `name`) the full register contract for one seat. Compile-time data
* from the shipped web bundle, so it needs no live runtime.
* @param slots - the generated slot catalog (injectable for tests).
* @param notes - the cross-cutting registrant rules (injectable for tests).
* @param name - exact slot key to expand; omitted for the compact catalog.
* @returns the section lines.
* @throws when `name` is not a catalogued slot key.
*/
export function describeClient(
slots: readonly ClientSlotEntry[] = CLIENT_SLOT_API,
notes: readonly string[] = CLIENT_NOTES,
name?: string,
): string[] {
if (name !== undefined) {
const entry = slots.find(candidate => candidate.key === name)
if (!entry) throw new Error(`no catalogued client slot named "${name}"`)
return slotDetailLines(entry)
}
const lines = slots.flatMap(entry => slotSummaryLines(entry))
lines.push('how to contribute:')
for (const note of notes) lines.push(`- ${note}`)
lines.push('pass name:"<slot key>" with what:"client" for one slot\'s register options, owner/framework props, and a minimal browser half.')
return lines
}

View File

@@ -31,7 +31,7 @@ export type { CordisKey } from './locales.ts'
/** Required services for the two Tool cards, panel, Remote lifecycle, and Slash source. */
export const inject = [
'slots', 'locale', 'slash', 'remote', 'remote.dynamicCordisRunner', 'dynamicCordisRunner',
'slots', 'locale', 'inputTriggers', 'remote', 'remote.dynamicCordisRunner', 'dynamicCordisRunner',
]
/** Mount every Cordis browser surface over the shared Host inventory. */
@@ -153,7 +153,7 @@ export function apply(ctx: ClientContext): void {
subscribeLexicon(_session, listener) { return inventory.subscribe(listener) },
onPick({ candidate }) { return { text: `@${candidate.name} ` } },
}
const slash = ctx.get('slash') as InputTriggerService
const slash = ctx.get('inputTriggers') as InputTriggerService
ctx.effect(() => slash.registerSource(source), 'ui-cordis: @pluginId source')
inventory.refresh()