Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ src/usage-remote.ts Host half of the usage Remote: `commandcodeUsage`
service + `typert` registry contribution (optional inject).
src/client/index.ts Browser client entry: registers the "Command Code"
settings page (settings.section, id `commandcode`) and
installs the friendly image-gate error wrapper.
mounts the current Remote-backed settings surface.
src/client/settings.ts Settings-page controller (scope + credentials + staged
form; React-free so node tests can drive it).
src/client/usage.ts Account-card controller (Remote fetch lifecycle +
formatting; React-free) + the TypertRemoteMap merge
declaration for `commandcode/report`.
src/client/section.tsx The settings page React component (settings form +
account-usage card).
src/client/sessions.ts selectModel friendly-error wrapper (React-free).
src/client/version.ts Plugin version for the settings-page footer (package.json import, inlined at build).
src/client/update.ts Update hint: throttled npm-registry `latest` check +
tolerant semver compare (React-free, storage/fetch/time
Expand All @@ -51,7 +50,6 @@ src/client/locales.ts zh/en copy + LocaleNamespaceMap augmentation.
tests/adapter.test.ts Core adapter unit tests (node:test + tsx).
tests/accounts.test.ts Account-pool rotation tests.
tests/commands.test.ts getUsage + command tests (stubbed fetch, no network).
tests/client.test.ts sessions-wrapper tests.
tests/settings.test.ts settings-page controller tests.
tests/update.test.ts update-hint tests (semver compare, payload parse,
throttle cache, failure semantics).
Expand All @@ -73,10 +71,10 @@ tsdown.config.ts Build config (tsdown -> lib/, ESM, .d.ts + client.js).
`react/jsx-runtime`, `@deepseek-ai/cordis`, `@deepseek-ai/dsh-client-ui-slots`,
`@deepseek-ai/dsh-client-web-react`, `@deepseek-ai/dsh-client-ui-primitives`,
`@deepseek-ai/dsh-client-schema-form`, `@deepseek-ai/dsh-client-ui-attachment`)
and host-shipped client bundles resolvable from the loader's module table
(e.g. `@deepseek-ai/dsh-client-runtime/client`). The settings page binds the
and host-shipped platform modules resolvable from the loader's module table
(e.g. `@deepseek-ai/dsh-client-store`). The settings page binds the
`llm-commandcode` namespace through `ctx.settingsScope` and writes the API
key through `connection.api.credentials` under the `COMMANDCODE_API_KEY`
key through `ctx.remote.credentials` under the `COMMANDCODE_API_KEY`
reference — never through the settings section, so the key literal cannot
leak into a settings document. `tests/settings.test.ts` pins this contract.
- **Wire protocol** (reverse-engineered, command-code@1.28.4; re-verified unchanged against 1.36.0):
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- **Adapted the provider to DeepSeek Harness 0.1.2-alpha.1.** Tool-call IDs now use the current branded chunk vocabulary, credential operations use Typert Remotes, the browser client consumes the new `dsh-client-store` platform module, and package metadata no longer references the removed `dsh-client-runtime` package.

## [0.8.4] - 2026-08-27

### Added
Expand Down
40 changes: 25 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 26 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
"client": {
"inject": [
"@deepseek-ai/dsh-client-connection",
"@deepseek-ai/dsh-client-runtime",
"@deepseek-ai/dsh-client-locale",
"@deepseek-ai/dsh-client-ui-renderer",
"@deepseek-ai/dsh-client-ui-settings",
"@deepseek-ai/dsh-api-remotes"
],
"external": [
"@deepseek-ai/dsh-client-runtime/client"
"@deepseek-ai/dsh-client-store"
],
"platform": "web"
}
Expand Down Expand Up @@ -78,31 +78,39 @@
"license": "MIT",
"peerDependencies": {
"@deepseek-ai/cordis": "^4.0.1",
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-timeout": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6 || ^0.1.1-rc.1",
"@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-attachment": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-store": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-commands": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-credentials": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-launch-environment": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-timeout": "^0.1.2-alpha.1",
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.1",
"@deepseek-ai/schemastery": "^3.18.1",
"react": "^18.2.0"
},
"peerDependenciesMeta": {
"@deepseek-ai/dsh-client-store": {
"optional": true
},
"@deepseek-ai/dsh-client-ui-renderer": {
"optional": true
}
},
"devDependencies": {
"@deepseek-ai/cordis": "^4.0.1",
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6",
"@deepseek-ai/dsh-attachment": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6",
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6",
Expand Down
10 changes: 7 additions & 3 deletions src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attac

import {
attributionHeaders,
CallId,
LlmAdapter,
LlmError,
ReasoningEffortId,
Expand All @@ -49,6 +48,11 @@ import {
} from '@deepseek-ai/dsh-llm'
import { RETRY_MAX_DELAY_MS } from './accounts.ts'

/** Brand a provider-issued tool-call id through the active harness chunk vocabulary. */
function toolCallId(id: string): Extract<StreamChunk, { type: 'tool-call-delta' }>['id'] {
return id as Extract<StreamChunk, { type: 'tool-call-delta' }>['id']
}

// ---------------------------------------------------------------------------
// Static capability snapshot (from the official command-code@1.36.0 bundled
// model catalog, dist/cli.mjs). The Provider API does not expose reasoning
Expand Down Expand Up @@ -1777,11 +1781,11 @@ export class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Command
sawContent = true
chunks.push(
{ type: 'block-start', index, blockType: 'tool-call' },
{ type: 'tool-call-delta', index, id: CallId(id), name, argumentsDelta: args },
{ type: 'tool-call-delta', index, id: toolCallId(id), name, argumentsDelta: args },
{
type: 'block-end',
index,
block: { type: 'tool-call', id: CallId(id), name, arguments: args },
block: { type: 'tool-call', id: toolCallId(id), name, arguments: args },
},
)
break
Expand Down
15 changes: 15 additions & 0 deletions src/client-store.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/** Compile-time face of the DSH 0.1.2 browser platform store module. */
declare module '@deepseek-ai/dsh-client-store' {
/** Mutable observable snapshot consumed by slot hooks. */
export interface SnapshotStore<T> {
getSnapshot(): T
subscribe(listener: () => void): () => void
set(value: T): void
}

/** Create one observable snapshot store. */
export function createSnapshotStore<T>(initial: T): SnapshotStore<T>
}

/** Type-only module marker for the 0.1.2 renderer service augmentation. */
declare module '@deepseek-ai/dsh-client-ui-renderer/client'
43 changes: 15 additions & 28 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,27 @@
*
* Two responsibilities:
*
* 1. A "Command Code" settings page (a `settings.section` entry at the same
* A "Command Code" settings page (a `settings.section` entry at the same
* nav level as General / Models / Plugins). The Models page renders an
* unknown-adapter-family card for the `commandcode` provider and disables
* its submit, so the API key cannot be configured there; this page is the
* dedicated surface. It writes the API key through the credentials domain
* (the `COMMANDCODE_API_KEY` reference the plugin resolves) and the
* connection facts through the `llm-commandcode` settings namespace, so a
* saved key or endpoint reaches the very next request.
*
* 2. The friendly-error wrapper for the harness's image-session gate — see
* `./sessions.ts`. The wrapper is deliberately narrow: only the
* `model-unavailable` code is rewritten, only when the message matches the
* image-session gate, and only the message text changes.
*
* The wire types are spelled structurally in `./sessions.ts` (not imported
* from `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag
* an extra peer dependency into the package; the shapes are stable and the
* client build inlines them anyway.
*/

import type { Context } from '@deepseek-ai/cordis'
import { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
import { createSnapshotStore } from '@deepseek-ai/dsh-client-store'
// Type-only imports that pull in the client-service augmentations
// (`slots`/`remote`/`locale` on Context) and the `settings.section` SlotMap
// entry (`settingsScope` arrives through dsh-client-ui-settings).
import type {} from '@deepseek-ai/dsh-api-remotes/client'
import type {} from '@deepseek-ai/dsh-client-locale/client'
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
import { installFriendlyImageError } from './sessions.ts'
import { CommandCodeSettingsController, COMMANDCODE_NS, type SettingsPageState } from './settings.ts'
import type { SettingsPageApi } from './settings.ts'
import { CommandCodeUsageController, type UsagePageState, type UsageRemote } from './usage.ts'
import { CommandCodeLoginController, type LoginPageState, type LoginRemote } from './login.ts'
import { USAGE_REMOTE_CONTRIBUTION } from '../usage-wire.ts'
Expand All @@ -41,9 +32,6 @@ import type { TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'
import { CommandCodeSettingsPage } from './section.tsx'
import { zh, en } from './locales.ts'

export { isImageSessionRejection, withFriendlyImageError } from './sessions.ts'
import type { ConnectionLike } from './sessions.ts'

/** CSS for the settings page, injected once (harness bundle convention). */
const PAGE_CSS = `
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}
Expand Down Expand Up @@ -154,31 +142,30 @@ function injectPageCss(): void {

/**
* Client plugin body. Gates on the services the settings page needs
* (`slots`, `locale`, `connection`, `remote`, `settingsScope`) plus the
* `connection` used by the friendly-error wrapper — the same inject list the
* harness's own settings-surface plugins declare.
* (`slots`, `locale`, `remote`, `remote.credentials`, `settingsScope`) — the
* same services the harness's own settings surfaces consume.
*/
export function apply(ctx: Context): void {
injectPageCss()

const connection = ctx.get('connection') as ConnectionLike | undefined
if (connection !== undefined) {
installFriendlyImageError(connection)
}

// The "Command Code" settings page: register the section once the
// `settings.section` declaration is on the ledger (ui-settings-general
// owns the shell; registration order relative to it is not constrained —
// `slots.inject` waits for the declaration).
ctx.effect(() => ctx.locale.register('settings.commandcode', { zh, en }), 'dsh-commandcode-provider: page copy')

const api = ctx.get('connection').api
const hostDescription = ctx.get('connection').hostDescription
const scope = ctx.settingsScope.bind<Record<string, unknown>>({ namespace: COMMANDCODE_NS })
const controller = new CommandCodeSettingsController(scope, { credentials: api.credentials }, hostDescription)
const credentialRemote = (ctx.remote as unknown as { credentials: SettingsPageApi['credentials'] }).credentials
const controller = new CommandCodeSettingsController(scope, { credentials: credentialRemote })
ctx.effect(() => () => controller.dispose(), 'dsh-commandcode-provider: settings controller')
const store = createSnapshotStore<SettingsPageState>(controller.state())
controller.subscribe(() => store.set(controller.state()))
ctx.effect(
() => (ctx.remote as unknown as {
$on(event: 'credentials/reference-updated', listener: (ref: string) => void): () => void
}).$on('credentials/reference-updated', () => { controller.refreshCredentials() }),
'dsh-commandcode-provider: credential invalidations',
)

// The account-usage card + login panel: mount the shared Remote contribution
// (one mount carries every endpoint this plugin serves — report and login —
Expand Down Expand Up @@ -309,7 +296,7 @@ export function apply(ctx: Context): void {
export const inject: readonly string[] = [
'slots',
'locale',
'connection',
'remote',
'remote.credentials',
'settingsScope',
]
Loading