CCTor Marketplace · DeepSeek Harness Bundle
cctor-dsh-marketplace is an installable DeepSeek Harness (DSH) bundle. It uses https://api.cctor.com as its dynamic catalog and ships both a native marketplace UI and model-facing Agent tools. The UI and tools share one Host service, one persistent cache, one installed-state reader, and one installation coordinator.
The current version is 0.1.0. v1 covers discovery, details, installed-state display, and installation that always requires an explicit user confirmation. It does not update, disable, or remove plugins, and it does not install into another profile.
What it provides
- Master-detail workspace: a searchable result list on the left and the selected plugin's details on the right. On narrow screens the detail becomes a separate second screen with a Back control.
- Search and filters: 300 ms search debounce with cancellation of superseded requests. Non-empty queries shorter than three characters are not sent (the API intentionally returns an empty page for them). Category, sort, refresh, pagination, and cache reset are supported.
- Installed state: entries installed in the current profile show their local version and do not expose the normal Install action.
- Bilingual UI: Chinese or English, following the active DSH locale. Dates, counts, empty states, errors, and install progress are localized. Plugin names, descriptions, README content, tags, and repository metadata are preserved as supplied by the API.
- Three Agent tools over the same Host normalization and cache:
| Tool | Purpose | Key constraints |
|---|---|---|
cctor_search_plugins |
Search the catalog and return plugin summaries, pagination, and cache freshness | Default 10 results, at most 20 per call; returns an opaque next_cursor; never returns README or install_command; never installs |
cctor_get_plugin_details |
Read public details, verification state, and current-profile installed state by stable ID or exact slug | Slug resolution must be unique; no match returns not_found, multiple matches return ambiguous_plugin; a stable ID goes directly to the detail endpoint |
cctor_request_plugin_install |
Prepare a single-use installation confirmation for the current profile | Returns only awaiting_confirmation, confirmation ID, expiry, target profile, route, and safe spec; the tool cannot approve or execute its own request |
Tool outputs have per-field caps and a 64 KiB total budget. Cache internals, stacks, paths, and request headers never enter model context.
Architecture
Agent tools ─┐
├─ CctorMarketplaceService ── CCTor API (list / meta / detail)
Web Client ──┘ │
(via same-origin API) ├─ Storage Domain (plugin-owned persistent cache)
└─ Plugin Manager (installs only into the current profile)
- The Host owns HTTP requests and response validation, caching, catalog normalization, profile inspection, confirmation state, and installation.
- The Web Client is presentation only. It never calls CCTor directly and cannot execute an installation. It calls the Host through the same-origin
/api/cctor-marketplace/rpcroute registered withconnection; Agent tools and the retained Typert Remote share the same Host service. - The bundle declares the official
storageDomain,pluginManager,profileContext,typert, andtoolsservices as required injections. If the runtime module cannot be imported or Host composition fails, the guarded entry logs one bounded compatibility diagnostic and stays inert rather than breaking the whole plugin tree.
Installation
Requirements: Node.js >= 22; DSH >= 0.2.1-rc.5 < 0.3.0 (see engines in package.json; peer dependencies are supplied by the DSH runtime).
Install from npm
dsh plugin --profile <name> add cctor-dsh-marketplace
Replace <name> with the target profile, then restart DSH when prompted.
Verify the installation
dsh plugin --profile <name> list cctor-dsh-marketplace --depth 0
The output should list cctor-dsh-marketplace and its installed version.
Upgrade
dsh plugin --profile <name> update cctor-dsh-marketplace --latest
Restart DSH after the upgrade.
Uninstall
dsh plugin --profile <name> remove cctor-dsh-marketplace
Restart DSH after removal.
These management commands operate on the marketplace bundle itself; the UI's v1 limitation applies to plugins discovered inside the marketplace.
Install from a local checkout
pnpm install
pnpm build
dsh plugin --profile <name> add /absolute/path/to/cctor-dsh-marketplace
The Plugin Manager validates the bundle metadata and compatibility and records the path as a link: dependency. Use an absolute path. Version 0.1.0 is published to the public npm registry. Post-publication validation installed the exact registry version, installed it into an owned cctor-release-validation profile through the DeepSeek Harness 0.2.2-rc.1 bundled CLI, composed its configuration, and moved that profile to Trash. Three existing profiles' direct manifest fingerprints stayed unchanged; this does not establish whole-profile filesystem equality.
Configuration
The bundle's config is defined with Schemastery and passed through DSH's plugin configuration. The fields are equivalent to:
{
"apiBaseUrl": "https://api.cctor.com",
"requestTimeoutMs": 15000
}
| Field | Default | Meaning |
|---|---|---|
apiBaseUrl |
https://api.cctor.com |
Must be a root origin. Production requires HTTPS; HTTP is allowed only for the literal hosts localhost and 127.0.0.1, for local development. URL userinfo, paths, query strings, and fragments are rejected. |
requestTimeoutMs |
15000 |
Per-request catalog timeout, as a positive integer number of milliseconds. |
The toolbar's "Reset cache" control clears only this plugin's private cache domain. It does not touch other Storage Domains or installed state.
Cache and offline behavior
- Cache first: when the marketplace opens and a matching persistent record exists, the Host returns it immediately and refreshes the list or metadata in the background. A successful, validated response atomically replaces the matching record; a failed or invalid response never overwrites the last successful one. Details are cache-first as well.
- Freshness: lists and metadata for 5 minutes, details for 30 minutes. Records past their TTL are marked
stalebut still rendered immediately while a background refresh runs. - Seven-day fallback: the last successful record remains available as a fallback when refresh fails. After seven days it is marked
possiblyOutdated, is never presented as live, and is eventually evicted by the LRU. - Bounded cache: up to 50 list scopes, 50 metadata records, and 200 details, evicted by LRU. Every record carries a cache schema version. Cache keys include the normalized API base URL, query, category, sort, and cursor.
- Offline: with a cached record, the UI renders it with a localized "stale" or "possibly outdated" banner and a Retry action; a failed refresh is exposed as a bounded error code and never corrupts the cached response. Without a cache, a network failure shows a localized
offline/timeouterror with Retry. - Install confirmation bypasses the cache: preparing a confirmation always re-reads the plugin from the detail endpoint, so the confirmation binds the current network identity and safe spec.
Installation confirmation and safety boundary
- Every installation needs a fresh, explicit confirmation. A confirmation is single-use, expires after five minutes, and binds the stable plugin ID, normalized install spec, target profile, verification state, and source-content digest. The source is rechecked before execution; if the spec or relevant source fields changed, the confirmation becomes invalid and the user must review the new values.
- Unverified warning: unverified entries can be browsed and installed, but they are not silently trusted. The confirmation dialog explains that Host code may access conversations, files, and the network. Its primary button reads
Install anyway(仍要安装in Chinese). No extra checkbox or second confirmation step is required. - The safe spec is derived only from structured fields: a valid npm package name plus the API's exact version when present; otherwise a canonical GitHub repository rendered as
github:owner/repo. Forgithub+npmrecords, npm is preferred. Blank or missingpackage_name/versionis treated exactly likenull. - Unsafe targets are refused: invalid, unsupported, ambiguous, non-GitHub Git, tarball, local-path, or shell-like targets.
install_commandis display data only and is never executed. Runtime source undersrc/imports nochild_process, builds no shell command, and never treats the API-provided command as executable input.- Serialized installs: only one installation may run at a time; a second request receives
install_busy. - The target is always the current profile: v1 installs only through the official Plugin Manager's
pluginManager.installBundle. It spawns nodshprocess, writes no other profile, offers no profile picker, and has nodefaultProfilesetting. The route is alwaysplugin-manager. - v1 does not update, disable, or remove: use DSH's own plugin management surface for those actions. Installed entries show their local version and hide the normal Install action.
Why v1 does not install across profiles
See design §15.1. The packaged Desktop runtime and the dsh on PATH can be different DSH generations. ProfileContext.packageManager exists precisely because packaged applications supply a bundled runtime instead of relying on a PATH executable. The current profile is also the only profile whose facts the Host can observe and whose mutation the Plugin Manager can validate end to end. The cross-profile CLI route, profile picker, and desktop exception path are deferred to v1.1.
Catalog reality and empty states
Observed against the production catalog on 2026-11-04 (7,567 public records; sample of 200):
verifiedwasfalsefor every sampled record, andfeaturedwas also alwaysfalse. Unverified is the normal path, so the unverified warning is routine, not exceptional.- Only 1 of the 200 sampled list records had a non-empty
readme; detail responses are frequently empty too. package_nameandversionappear only ongithub+npmrecords (58 of 200);githubrecords carry neither.- Stable IDs come in two namespaced forms:
github:owner/repoandrepo:owner/name. Both are accepted, and neither is re-derived fromrepository.
The UI therefore renders explicit empty states: a missing README shows the localized "This plugin provides no README." instead of an empty block, and a missing version or license shows "Unknown". These are expected catalog states, not load failures. API-supplied plugin names, descriptions, READMEs, and repository metadata remain unchanged.
API prerequisite
The bundle depends on the existing GET /market/plugins and GET /market/plugins/meta endpoints, plus the deployed exact-detail endpoint:
GET /market/plugins/detail?id=github%3Aowner%2Frepository
The endpoint was verified live on 2026-11-04 (200 with readme, verified, and featured; 400 for an empty id; 404 for an unknown id; CORS and Cache-Control: public, max-age=60, s-maxage=300 on the response). The separate read-only pnpm verify:live-api check passed again on 2026-11-06 for list, metadata, stable-ID detail, and an unknown ID; it does not recheck every historical HTTP/CORS/cache-header assertion above. The detail API implementation plan belongs to the external API repository; this repository validates only the deployed read-only contract.
Contract summary:
- Exactly one non-empty
idquery parameter is accepted. Stable IDs can contain/, so the value must be URL-encoded. - Lookup is an exact primary-key lookup and returns only an active public record.
- The success body contains the public list-item fields plus the complete
readme,verified, andfeaturedfields. It must not return moderation, synchronization, credential, or internal provenance fields. - Stable error responses:
400 {"error":"invalid_plugin_id"}404 {"error":"plugin_not_found"}(unknown or inactive)405 {"error":"method_not_allowed"}502 {"error":"database_error"}(without leaking database details)
- It uses the existing market CORS policy and public cache headers. The route must be matched before any generic
/market/plugins/<segment>route.
The Host maps network, timeout, invalid-response, not-found, slug ambiguity, install-busy, confirmation-expired, source-changed, invalid-profile, incompatible, and install-failed failures to stable public codes with a recovery action where one exists.
Verification and known limits
Latest full automated gate results in this repository (2026-11-06):
| Check | Result |
|---|---|
pnpm typecheck |
Passed (Host and Client tsconfigs) |
pnpm build |
Passed; produced lib/index.js, lib/plugin.js, lib/client.js, declarations, and sourcemaps |
pnpm test |
348 Node tests passed, 0 failed, 0 skipped |
pnpm test:e2e |
16 tests passed (15 desktop + 1 @narrow), covering 1440×900, 1024×768, and 390×844; zero pixel differences across nine baselines |
pnpm verify:package |
npm dry-run preview passed: 48 entries, both READMEs, the MIT license, the changelog, and required runtime artifacts; no tarball generated or published |
pnpm verify:release |
Deterministic aggregate of type checks, build, Node tests, Playwright, and package preview passed |
pnpm verify:live-api |
Separate networked read-only check passed: 1 list result, 7,567 total records, detail github:morluto/rea, unknown ID not_found |
| Forbidden-pattern scan | No runtime execution of catalog commands; matches are only README safety text and the npm-preview script's child_process import |
The 348 Node tests cover Client HTTP transport/store/locale/UI, Host routes and services, cache/install/catalog/profile behavior, entry/build contracts, real DSH Loader composition, package contents, the live verifier, and owned validation-profile lifecycle protections. They cover HTTP request validation, error envelopes, cache TTL/LRU/schema version/atomic replacement, slug resolution, install-spec allowlisting, confirmation expiry and source changes, revision refresh after loading more pages, tool output bounds, and the Client HTTP route contract.
What these results prove, and what they do not:
- Catalog installation boundaries remain verified against a Plugin-Manager-compatible fake. Separate acceptance installed only this local marketplace bundle through the real bundled CLI, composed configuration, and cleaned up the owned validation profile. This does not prove third-party marketplace installation, application/restart behavior, or build approvals.
- Cache durability is verified through the real Storage Domain with a test-owned file-backed backend. The deployed backend's media, per-record,
compatibleVersions, and backup semantics are out of scope. - Playwright proves the built
lib/client.jsartifact, workflows, and layout with a fake shell and fake Host HTTP route. It does not prove the packaged shell's live seats, real module table, style variables, or the production Connection carrier round trip. - The integration fixture is an inert spec target: it is never installed and has no entry module, so it is not bootable. Do not treat it as a runnable example plugin.
pnpm buildmust run beforepnpm test:test/integration/loader.test.tshas an mtime-based freshness guard that fails fast when artifacts are missing or older than the newestsrc/file.- Unverified: the packaged Desktop shell's Connection route round trip, arbitrary third-party catalog installation, and cross-profile installation. Exact-version download from public npm and installation into a validation profile through the bundled CLI passed.
- The Playwright screenshot baselines are Chromium/macOS/1×/UTC/light-specific. A different font stack or Chromium version may require
--update-snapshots; that is a platform baseline change, not a UI change. - Desktop 0.2.1-rc.5 acceptance: App and bundled CLI versions matched; CLI local-bundle installation and configuration composition passed.
open -na ... --args --profile cctor-release-validationreturned 0 but started no validation Host; only the existingdesktopHost remained. Read-only inspection found a fixedprofiles/desktoppath and a single-instance lock. Native automation returned no UI state, and no UI interaction occurred. The linked-peer warning remains unvalidated in the real Desktop runtime. - The user explicitly waived real Desktop UI acceptance for
0.1.0: the 2026-11-05 Typert mount issue was addressed by using the same-origin Connection HTTP route and passes automated tests. Real Desktop list, search, details, bilingual copy, confirmation, cancellation, and route diagnostics remain unexecuted. This is an accepted first-release risk and no longer blocks0.1.0, but it does not establish that the real Desktop UI passed acceptance. See the acceptance record. - The owned validation profile was cleaned up; before/after fingerprints of three existing direct manifests matched.
cctor-dsh-marketplace@0.1.0was published and passed npm and bundled-CLI installation checks; no catalog plugin was installed and no API was deployed.
Screenshots
The nine screenshots below come from the Task 9 Playwright harness and were each inspected with the image reader. The harness bar is hidden, Date.now is frozen at 2026-11-04T12:05:00Z, and the data is a deterministic fixture rather than the production catalog. Dates, counts, and plugin names in these images demonstrate layout only.
| List | Detail | Confirmation |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
What I actually confirmed in these images:
- 1440×900 list: the toolbar stays on one line, with the search field taking most of the width and category, sort, refresh, reset-cache, and the read-only current-profile label aligned to the right. Above the list are the catalog total and sync date; beside the list heading is "updated 5 minutes ago · from network". Multiple rows and right-aligned unverified/verified/installed badges are visible; a long plugin name wraps across several lines without clipping. No plugin is selected yet, so the detail pane shows "Select a plugin to view details." The viewport cuts off later rows at the bottom, with no horizontal overflow.
- 1440×900 detail: the selected row is highlighted. "Alpha unverified plugin" shows its unverified state, a pink warning block, repository, author, version, license, tags, published/updated dates, stars/weekly downloads, and cache age. The long README extends past the viewport and is clipped by the detail column; the blue Install button begins at the bottom edge with its lower part clipped by the viewport — the detail column scrolls internally, so about 16 px of scrolling makes it fully visible and clickable.
- 1440×900 confirmation: a centered dialog over the dimmed workspace, not covering the top toolbar. It contains the "Confirm install" title, the unverified badge and warning, plugin, repository, target profile
web, route "Plugin Manager", package@cctor-lab/alpha-tool@1.2.3, command preview, the expiry date/time (12:10 on 2026-11-04), and Cancel / "Install anyway" actions. The command preview wraps to two lines. - 1024×768 list/detail: the toolbar is still one line; the list is narrower, long names wrap across more lines, and the last rows are cut off at the bottom. The detail column is narrower but fields and README wrap normally; the Install button sits below the fold (about 148 px of internal detail scrolling reveals it, and the button itself is clickable). The confirmation dialog fits within the 768 px height.
- 390×844 list: the toolbar wraps to two rows (search and category on the first; sort, refresh, reset-cache, and the profile label on the second), and the profile label remains visible. The list is full width, long names wrap across several lines, and badges stay inside the right-hand column.
- 390×844 detail: the list is hidden and a "← Back" control appears at the top, followed by the full unverified warning, fields, and wrapped README. There is no horizontal scrolling.
- 390×844 confirmation: the narrow dialog fits the viewport width; the warning, fields, and three-line command preview wrap cleanly, the Cancel / "Install anyway" actions are visible at the bottom, and the underlying detail is dimmed.
These are pixel baselines (maxDiffPixels: 0, threshold: 0) that guard against layout regressions. They are not acceptance screenshots of the real DSH desktop shell.
Development and verification
pnpm install
pnpm verify:release # type checks, build, 348 Node tests, 16 Playwright tests, package preview
pnpm verify:live-api # explicit networked read-only check, outside the deterministic gate
Re-run Playwright after changing the Client; re-run pnpm build after changing src/. Playwright's webServer builds the harness assets itself and listens on 127.0.0.1:4517; it requires lib/client.js to exist.
Explicitly out of scope for this release
- API deployment and arbitrary third-party catalog installation remain unverified; public npm publication, exact-version installation, and owned-profile CLI composition passed.
- No update, disable, remove, cross-profile install, profile picker, or
defaultProfile. - No execution of the API-provided
install_command; no shell ordshsubprocess. - No cache writes to session history and no cache internals exposed to the model.









No comments yet. Be the first to write one.