diff --git a/package.json b/package.json index 6529557..eacefe3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dsh-plugin-xquant", - "version": "0.1.0", + "version": "0.1.1", "packageManager": "pnpm@10.33.0", "description": "One-command xquant MCP integration for DeepSeek Harness", "type": "module", diff --git a/scripts/smoke.mjs b/scripts/smoke.mjs index acf132c..bc644ec 100644 --- a/scripts/smoke.mjs +++ b/scripts/smoke.mjs @@ -1,12 +1,13 @@ -import { execFileSync } from 'node:child_process' +import { execFileSync, spawnSync } from 'node:child_process' import { mkdtempSync, readFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' const workspace = mkdtempSync(join(tmpdir(), 'dsh-plugin-xquant-')) +const packageVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version execFileSync('pnpm', ['pack', '--pack-destination', workspace], { stdio: 'inherit' }) -const tarball = join(workspace, 'dsh-plugin-xquant-0.1.0.tgz') +const tarball = join(workspace, `dsh-plugin-xquant-${packageVersion}.tgz`) const environment = { ...process.env, DSH_HOME: join(workspace, 'home') } execFileSync('pnpm', ['dlx', '@deepseek-ai/dsh@0.1.0-rc.7', 'plugin', '--profile', 'web', 'add', tarball], { stdio: 'inherit', @@ -19,4 +20,14 @@ if (manifest.dependencies?.['dsh-plugin-xquant'] === undefined throw new Error('dsh did not register dsh-plugin-xquant as a web-profile bundle') } -console.log('dsh plugin install smoke passed') +const boot = spawnSync('pnpm', ['dlx', '@deepseek-ai/dsh@0.1.0-rc.7', '--profile', 'web', '--no-open', '--port', '0'], { + encoding: 'utf8', + env: environment, + timeout: 8_000, +}) +const bootOutput = `${boot.stdout}${boot.stderr}` +if (!bootOutput.includes('dsh web: http://')) { + throw new Error(`dsh web failed to start after plugin installation:\n${bootOutput}`) +} + +console.log('dsh plugin install and boot smoke passed') diff --git a/src/index.ts b/src/index.ts index 1e3ed1a..92636a6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,6 +33,10 @@ export function xquantMcpUrl(origin = process.env.XQUANT_MCP_ORIGIN): string { export const name = 'xquant' +// Cordis only exposes services that a plugin declares up front. Keep this +// explicit so the prompt section works when loaded from a dsh profile bundle. +export const inject = ['systemPrompt'] + export async function apply(ctx: Context): Promise { ctx.effect(() => ctx.systemPrompt.section({ name: 'xquant:research-guidance', diff --git a/tests/plugin.spec.ts b/tests/plugin.spec.ts index 20269db..b1cdd3f 100644 --- a/tests/plugin.spec.ts +++ b/tests/plugin.spec.ts @@ -1,7 +1,7 @@ import { readFileSync } from 'node:fs' import { describe, expect, it, vi } from 'vitest' -import { apply, RESEARCH_GUIDANCE, xquantMcpUrl } from '../src/index.js' +import { apply, inject, RESEARCH_GUIDANCE, xquantMcpUrl } from '../src/index.js' describe('xquant MCP endpoint', () => { it('uses the official endpoint when no override is supplied', () => { @@ -23,6 +23,10 @@ describe('xquant MCP endpoint', () => { }) describe('Cordis plugin', () => { + it('declares the system prompt service required by apply', () => { + expect(inject).toEqual(['systemPrompt']) + }) + it('registers the research prompt without mounting a second MCP client', async () => { const ctx = { effect: vi.fn((effect: () => unknown) => effect()),