dsh-code-review-graph 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../src/backend.ts", "../src/safety.ts", "../src/refactor.ts", "../src/workflows.ts"],
4
- "sourcesContent": ["import type { Context } from '@deepseek-ai/cordis';\nimport type { ToolDefinition, ToolRunContext } from '@deepseek-ai/dsh-tools';\nimport type {} from '@deepseek-ai/dsh-agent';\nimport type {} from '@deepseek-ai/dsh-skill';\nimport type {} from '@deepseek-ai/dsh-system-prompt';\nimport z from '@deepseek-ai/schemastery';\nimport { Ajv } from 'ajv';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport { BackendPool, run, valueOf, type Engine } from './backend.ts';\nimport { repository, checkedPath, sha256 } from './safety.ts';\nimport { commitPlan, type EditPlan } from './refactor.ts';\nimport { exposed, groups, publicName, skillWorkflow, type Workflow } from './workflows.ts';\n\nexport const name = 'code-review-graph';\nexport const inject = ['tools', 'agents', 'fs', 'sandboxPolicy', 'skills', 'systemPrompt'];\nconst engineDir = join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'code-review-graph', 'engine');\nexport const Config = z.object({\n engineCommand: z.string().default(join(engineDir, process.platform === 'win32' ? 'Scripts/code-review-graph.exe' : 'bin/code-review-graph')),\n engineArgs: z.array(z.string()).default([]),\n timeoutMs: z.number().min(1000).default(120000),\n authorizedRepos: z.array(z.string()).default([]),\n embeddingProviders: z.array(z.string()).default(['local']),\n embeddingEnv: z.array(z.string()).default([]),\n});\nexport interface Configuration { engineCommand: string; engineArgs: string[]; timeoutMs: number; authorizedRepos: string[]; embeddingProviders: string[]; embeddingEnv: string[] }\ninterface Capability { name: string; description?: string; inputSchema: Record<string, unknown> & { properties?: Record<string, unknown>; required?: string[] } }\nexport const output: ToolDefinition['output'] = {\n schema: { type: 'object', additionalProperties: true },\n render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],\n};\n\nexport async function apply(ctx: Context, config: Configuration): Promise<void> {\n const engine: Engine = { command: config.engineCommand, args: config.engineArgs, timeoutMs: config.timeoutMs, env: Object.fromEntries(config.embeddingEnv.filter(key => /^(OPENAI|GOOGLE|GEMINI|MINIMAX|VOYAGE|CRG)_/.test(key) && process.env[key] !== undefined).map(key => [key, process.env[key]!])) };\n const pool = new BackendPool(engine);\n const snapshot = JSON.parse(await readFile(new URL('../capabilities.json', import.meta.url), 'utf8')) as { tools: Capability[] };\n const tools = snapshot.tools.filter(t => t.name !== 'get_refactor_edit_plan_tool');\n const names = tools.map(t => t.name);\n const masks = new Map<string, () => void>();\n const ajv = new Ajv({ strict: false, allErrors: true });\n const life = new AbortController();\n ctx.effect(() => () => { life.abort(); for (const dispose of masks.values()) dispose(); return pool.dispose(); });\n const switchWorkflow = (agent: NonNullable<ToolRunContext['agent']>, workflow?: Workflow) => {\n pool.activate(agent.id);\n const available = workflow ? exposed(workflow, names) : [];\n masks.get(agent.id)?.();\n masks.set(agent.id, agent.ctx.tools.restrict({ deny: names.filter(n => !available.includes(n)).map(publicName) }));\n return available.map(publicName);\n };\n\n async function rootFor(exec: ToolRunContext) {\n if (!exec.agent) throw new Error('Graph tools require a session-owned agent');\n return repository(exec.agent.session.header.cwd);\n }\n\n async function invoke(raw: string, args: Record<string, unknown>, exec: ToolRunContext) {\n const root = await rootFor(exec);\n const owner = exec.agent!.id;\n const signal = AbortSignal.any([exec.signal, life.signal]);\n const providerKey = ['build_or_update_graph_tool', 'run_postprocess_tool'].includes(raw) ? 'embedding_provider' : 'provider';\n const provider = args[providerKey];\n if (raw === 'get_docs_section_tool') await checkedPath(root, 'docs/LLM-OPTIMIZED-REFERENCE.md', true);\n if (provider && (typeof provider !== 'string' || !config.embeddingProviders.includes(provider))) throw new Error('Embedding provider has not been authorized in plugin configuration');\n if (['semantic_search_nodes_tool', 'embed_graph_tool'].includes(raw) && !provider) args = { ...args, provider: 'local' };\n for (const key of ['file_path', 'file', 'path']) {\n if (typeof args[key] === 'string') await checkedPath(root, args[key] as string);\n }\n for (const key of ['changed_files', 'files']) {\n if (Array.isArray(args[key])) for (const path of args[key] as string[]) await checkedPath(root, path, true);\n }\n if (raw === 'list_repos_tool') {\n const roots = [...new Set([root, ...await Promise.all(config.authorizedRepos.map(repository))])];\n return { status: 'ok', repos: roots.map(path => ({ alias: roots.filter(r => basename(r) === basename(path)).length > 1 ? `${basename(path)}@${sha256(path).slice(0, 8)}` : basename(path), path })) };\n }\n if (raw === 'cross_repo_search_tool') {\n const roots = [...new Set([root, ...await Promise.all(config.authorizedRepos.map(repository))])];\n const aliases = roots.map(path => ({ path, alias: roots.filter(r => basename(r) === basename(path)).length > 1 ? `${basename(path)}@${sha256(path).slice(0, 8)}` : basename(path) }));\n const selected = Array.isArray(args.repos) ? args.repos as string[] : [];\n if (selected.some(n => !aliases.some(r => r.alias === n))) throw new Error('Repository is not authorized');\n const results: Record<string, unknown>[] = [];\n for (const { path: repo, alias } of aliases.filter(r => !selected.length || selected.includes(r.alias))) {\n if (repo !== root && !await stat(join(repo, '.code-review-graph/graph.db')).then(() => true, () => false)) throw new Error(`Build ${repo} in its own session first`);\n await pool.ensure(repo, owner, signal);\n const data = valueOf(await pool.call(repo, owner, 'semantic_search_nodes_tool', { query: args.query, kind: args.kind, limit: args.limit ?? 20, provider: 'local', repo_root: repo }, signal));\n for (const result of data.results as Record<string, unknown>[]) results.push({ ...result, repo: alias });\n }\n results.sort((a, b) => Number(b.score ?? 0) - Number(a.score ?? 0));\n const limit = Math.min(Number(args.max_results ?? 50), 100);\n return { status: 'ok', results: results.slice(0, limit), total: results.length, results_omitted: Math.max(0, results.length - limit), truncated: results.length > limit };\n }\n const graphUpdate = raw !== 'build_or_update_graph_tool' ? await pool.ensure(root, owner, signal) : undefined;\n if (raw === 'apply_refactor_tool' && !args.dry_run) {\n const plan = valueOf(await pool.call(root, owner, 'get_refactor_edit_plan_tool', { refactor_id: args.refactor_id, repo_root: root }, signal)) as unknown as EditPlan;\n const result = await commitPlan(ctx, exec, root, plan);\n if (result.status === 'ok') {\n try { return { ...result, graph_update: valueOf(await pool.call(root, owner, 'build_or_update_graph_tool', { repo_root: root }, signal)) }; }\n catch (error) { return { ...result, graph_update_error: String(error) }; }\n }\n return result;\n }\n if (raw === 'apply_refactor_tool') args = { ...args, dry_run: true };\n const result = valueOf(await pool.call(root, owner, raw, { ...args, repo_root: root }, signal));\n if (raw === 'build_or_update_graph_tool') await pool.ensure(root, owner, signal);\n return graphUpdate ? { ...result, graph_update: graphUpdate } : result;\n }\n\n for (const tool of tools) {\n const parameters = structuredClone(tool.inputSchema);\n delete parameters.properties?.repo_root;\n parameters.required = parameters.required?.filter(n => n !== 'repo_root');\n parameters.additionalProperties = false;\n const validate = ajv.compile(parameters);\n const definition = {\n name: publicName(tool.name), description: tool.description ?? tool.name, parameters, output,\n timeoutMs: config.timeoutMs,\n execute: async (args: unknown, exec: ToolRunContext) => {\n if (!validate(args)) throw new Error(ajv.errorsText(validate.errors));\n return invoke(tool.name, args as Record<string, unknown>, exec);\n },\n } as ToolDefinition;\n ctx.effect(() => ctx.tools.register(definition));\n }\n\n ctx.effect(() => ctx.tools.register({ name: 'crg_workflow', description: 'Select code graph tools: context, review, refactor, export, advanced or all. Begin with get_minimal_context.',\n parameters: { type: 'object', properties: { workflow: { type: 'string', enum: [...groups] } }, required: ['workflow'], additionalProperties: false }, output,\n execute: async (args, exec) => {\n const workflow = (args as { workflow: Workflow }).workflow;\n if (!groups.includes(workflow) || !exec.agent) throw new Error('Invalid workflow or missing agent');\n return { tools: switchWorkflow(exec.agent, workflow) };\n },\n }));\n\n const visualizationSchema = { type: 'object', properties: {\n mode: { type: 'string', enum: ['auto', 'file', 'community', 'full'] },\n format: { type: 'string', enum: ['html', 'json', 'graphml', 'cypher', 'obsidian', 'svg'] },\n seed_file: { type: 'array', items: { type: 'string' } }, seed_symbol: { type: 'string' }, seed_changed: { type: 'boolean' }, seed_changed_base: { type: 'string' }, seed_flow: { type: 'string' },\n path_from: { type: 'string' }, path_to: { type: 'string' }, depth: { type: 'integer', minimum: 0 }, render_depth: { type: 'integer', minimum: 0 }, max_nodes: { type: 'integer', minimum: 1 },\n }, additionalProperties: false };\n const validateVisualization = ajv.compile(visualizationSchema);\n ctx.effect(() => ctx.tools.register({ name: 'crg_visualize', description: 'Generate the local interactive graph for the DSH Code graph sidebar, or export HTML, JSON, GraphML, Cypher, Obsidian or SVG. Supports file, community, symbol, changed-code, flow and shortest-path views.',\n parameters: visualizationSchema, output,\n timeoutMs: config.timeoutMs,\n execute: async (value, exec) => {\n if (!validateVisualization(value)) throw new Error(ajv.errorsText(validateVisualization.errors));\n const args = value as Record<string, unknown>;\n const root = await rootFor(exec);\n const signal = AbortSignal.any([exec.signal, life.signal]);\n await pool.ensure(root, exec.agent!.id, signal);\n for (const path of (args.seed_file ?? []) as string[]) await checkedPath(root, path, true);\n const command = ['visualize', '--repo', root];\n for (const [key, value] of Object.entries(args)) {\n const flag = `--${key.replaceAll('_', '-')}`;\n if (Array.isArray(value)) for (const item of value) command.push(flag, String(item));\n else if (value === true) command.push(flag);\n else if (value !== undefined && value !== false) command.push(flag, String(value));\n }\n const { log } = await run(engine, command, root, signal);\n const format = String(args.format ?? 'html');\n return { status: 'ok', path: join(root, '.code-review-graph', format === 'obsidian' ? 'obsidian' : `graph.${format}`), ...(format === 'html' ? { sidebar: 'code-review-graph' } : {}), log };\n },\n }));\n const promptNames = ['review_changes', 'architecture_map', 'debug_issue', 'onboard_developer', 'pre_merge_check'];\n const promptSchema = { type: 'object', properties: { name: { type: 'string', enum: promptNames }, base: { type: 'string' }, description: { type: 'string' } }, required: ['name'], additionalProperties: false };\n const validatePrompt = ajv.compile(promptSchema);\n ctx.effect(() => ctx.tools.register({ name: 'crg_prompt', description: 'Load one of the five original CRG workflows and reveal its graph tools.', parameters: promptSchema, output,\n execute: async (args, exec) => {\n if (!validatePrompt(args) || !exec.agent) throw new Error('Invalid workflow prompt or missing agent');\n const { name, ...parameters } = args as { name: string; base?: string; description?: string };\n const workflow: Workflow = name === 'pre_merge_check' ? 'all' : name === 'review_changes' ? 'review' : name === 'debug_issue' ? 'review' : 'advanced';\n switchWorkflow(exec.agent, workflow);\n const root = await rootFor(exec);\n const { client } = await pool.acquire(root, exec.agent.id);\n const result = await client.getPrompt({ name, arguments: parameters }, { signal: AbortSignal.any([exec.signal, life.signal]), timeout: config.timeoutMs });\n return { ...result, messages: result.messages.map(message => ({ ...message, content: message.content.type === 'text' ? { ...message.content, text: message.content.text.replace(/\\b([a-z_]+_tool)\\b/g, raw => names.includes(raw) ? publicName(raw) : raw) } : message.content })) };\n },\n }));\n ctx.on('agent/created', ({ agent }) => { switchWorkflow(agent); return undefined; });\n ctx.on('agent/disposed', ({ agent }) => { masks.get(agent.id)?.(); masks.delete(agent.id); return pool.release(agent.id); });\n for (const agent of ctx.agents.list()) switchWorkflow(agent);\n ctx.effect(() => ctx.systemPrompt.section({ name: 'code-review-graph', order: 80, interpolate: false,\n text: 'Use crg_workflow to reveal task-specific local code graph tools, then get_minimal_context_tool before broader queries. Prefer minimal detail. crg_visualize opens the local graph in the Code graph sidebar. Refactors use session filesystem permissions.' }));\n\n const skillsDir = new URL('../skills/', import.meta.url);\n for (const slug of await readdir(skillsDir)) {\n const path = new URL(`${slug}/SKILL.md`, skillsDir);\n const body = await readFile(path, 'utf8');\n const content = body.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n/, '').replace(/\\b([a-z_]+_tool)\\b/g, raw => names.includes(raw) ? publicName(raw) : raw);\n if (!skillWorkflow[slug]) throw new Error(`Unmapped CRG skill: ${slug}`);\n ctx.effect(() => ctx.skills.register({ name: `crg-${slug}`, description: `Code review graph: ${slug}`, source: 'bundled', content: `First call crg_workflow with workflow \"${skillWorkflow[slug]}\". Tool names use mcp__code_review_graph__ prefixes.\\n\\n${content}` }));\n }\n}\n", "import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { checkedData, scrubEnv } from './safety.ts';\n\nexport interface Engine { command: string; args: string[]; timeoutMs: number; env?: Record<string, string> }\nconst environment = (engine: Engine) => ({ ...scrubEnv(process.env), ...engine.env });\nexport function valueOf(result: unknown): Record<string, unknown> {\n const r = result as { isError?: boolean; structuredContent?: Record<string, unknown>; content?: { type: string; text?: string }[] };\n const text = r.content?.filter(x => x.type === 'text').map(x => x.text).join('\\n') ?? '';\n if (r.isError) throw new Error(text || 'Engine tool failed');\n const value = r.structuredContent ?? (() => { try { return JSON.parse(text); } catch { return { text }; } })();\n if (value.status === 'error') throw new Error(String(value.error));\n return value;\n}\n\nexport async function connect(engine: Engine, cwd: string): Promise<Client> {\n await checkedData(cwd);\n const transport = new StdioClientTransport({ command: engine.command, args: [...engine.args, 'serve', '--repo', cwd], cwd, env: environment(engine), stderr: 'pipe' });\n transport.stderr?.on('data', () => {});\n const client = new Client({ name: 'dsh-code-review-graph', version: '0.1.0' });\n try { await client.connect(transport); return client; }\n catch (error) { await transport.close(); throw new Error(`CRG engine unavailable. Run dsh-crg prepare explicitly. ${String(error)}`); }\n}\n\nasync function stop(child?: ChildProcess): Promise<void> {\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n await new Promise<void>(resolve => {\n const timer = setTimeout(() => { child.kill('SIGKILL'); resolve(); }, 3000);\n child.once('exit', () => { clearTimeout(timer); resolve(); });\n child.kill();\n });\n}\ninterface Entry { client: Client; owners: Set<string>; ready?: Promise<void>; watcher?: ChildProcess; watchError?: string; queue: Promise<unknown>; update?: Record<string, unknown> }\nexport class BackendPool {\n private entries = new Map<string, Promise<Entry>>();\n private retired = new Set<string>();\n private closed = false;\n constructor(readonly engine: Engine) {}\n activate(owner: string): void { this.retired.delete(owner); }\n\n async acquire(root: string, owner: string): Promise<Entry> {\n if (this.closed || this.retired.has(owner)) throw new Error('Session has been released');\n let promise = this.entries.get(root);\n if (!promise) {\n promise = connect(this.engine, root).then(client => ({ client, owners: new Set<string>(), queue: Promise.resolve() }));\n this.entries.set(root, promise);\n promise.catch(() => { if (this.entries.get(root) === promise) this.entries.delete(root); });\n }\n const entry = await promise;\n if (this.closed || this.retired.has(owner)) throw new Error('Session has been released');\n entry.owners.add(owner);\n return entry;\n }\n\n async call(root: string, owner: string, name: string, args: Record<string, unknown>, signal: AbortSignal) {\n const entry = await this.acquire(root, owner);\n // One mutation at a time per SQLite graph; cancellation restarts this repository's shared worker.\n const work = entry.queue.catch(() => {}).then(async () => {\n signal.throwIfAborted();\n const cancel = () => { this.entries.delete(root); void stop(entry.watcher); void entry.client.close(); };\n signal.addEventListener('abort', cancel, { once: true });\n let result: unknown;\n try {\n await checkedData(root);\n if (entry.watchError) throw new Error(`Incremental watcher stopped: ${entry.watchError}`);\n result = await entry.client.callTool({ name, arguments: args }, undefined, { signal, timeout: this.engine.timeoutMs });\n } catch (error) {\n // A timed-out Python thread cannot safely be left mutating the graph.\n this.entries.delete(root); await stop(entry.watcher); await entry.client.close();\n throw error;\n } finally { signal.removeEventListener('abort', cancel); }\n // A normal tool error must not discard another call's pending refactor preview.\n valueOf(result);\n return result;\n });\n entry.queue = work;\n return work;\n }\n\n async ensure(root: string, owner: string, signal: AbortSignal): Promise<Record<string, unknown> | undefined> {\n const entry = await this.acquire(root, owner);\n entry.ready ??= (async () => {\n // An existing database can be stale after all sessions were closed.\n const update = valueOf(await this.call(root, owner, 'build_or_update_graph_tool', { repo_root: root }, signal));\n if (update.status === 'partial' || Array.isArray(update.warnings) && update.warnings.length) entry.update = update;\n signal.throwIfAborted();\n const watcher = spawn(this.engine.command, [...this.engine.args, 'watch', '--repo', root], { cwd: root, env: environment(this.engine), stdio: 'ignore', windowsHide: true });\n entry.watcher = watcher;\n await new Promise<void>((resolve, reject) => { watcher.once('spawn', resolve); watcher.once('error', reject); });\n watcher.on('error', error => { entry.watchError = String(error); });\n watcher.on('exit', (code, reason) => { if (entry.watcher === watcher) entry.watchError = `exit ${code ?? reason}`; });\n })().catch(error => { entry.ready = undefined; throw error; });\n await entry.ready;\n if (entry.watchError) throw new Error(`Incremental watcher stopped: ${entry.watchError}`);\n return entry.update;\n }\n\n async release(owner: string): Promise<void> {\n this.retired.add(owner);\n for (const [root, promise] of this.entries) {\n const entry = await promise.catch(() => undefined);\n if (!entry) continue;\n entry.owners.delete(owner);\n if (!entry.owners.size) { this.entries.delete(root); const watcher = entry.watcher; entry.watcher = undefined; await stop(watcher); await entry.client.close(); }\n }\n }\n\n async dispose(): Promise<void> {\n this.closed = true;\n const entries = [...this.entries.values()]; this.entries.clear();\n for (const promise of entries) {\n const entry = await promise.catch(() => undefined);\n if (entry) { const watcher = entry.watcher; entry.watcher = undefined; await stop(watcher); await entry.client.close(); }\n }\n }\n}\n\nexport async function run(engine: Engine, args: string[], cwd: string, signal: AbortSignal): Promise<{ log: string }> {\n await checkedData(cwd);\n signal = AbortSignal.any([signal, AbortSignal.timeout(engine.timeoutMs)]);\n return new Promise((resolve, reject) => {\n let log = '';\n const child = spawn(engine.command, [...engine.args, ...args], { cwd, env: environment(engine), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, signal });\n const capture = (bytes: Buffer) => { log = (log + bytes.toString()).slice(-16000); };\n child.stdout?.on('data', capture); child.stderr?.on('data', capture);\n child.on('error', reject);\n child.on('exit', code => code === 0 ? resolve({ log }) : reject(new Error(`Engine command exited ${code}: ${log}`)));\n });\n}\n", "import { realpath, stat, lstat, readdir } from 'node:fs/promises';\nimport { isAbsolute, relative, resolve, sep, dirname, basename, join } from 'node:path';\nimport { createHash } from 'node:crypto';\n\nexport const sha256 = (bytes: Uint8Array | string): string => createHash('sha256').update(bytes).digest('hex');\n\nexport function contained(root: string, path: string): boolean {\n const part = relative(root, path);\n return part === '' || (!isAbsolute(part) && part !== '..' && !part.startsWith(`..${sep}`));\n}\n\nexport async function checkedPath(root: string, value: string, allowMissing = false): Promise<string> {\n const candidate = resolve(root, value);\n if (!contained(root, candidate)) throw new Error('Path is outside the authorized repository');\n let current = candidate;\n const suffix: string[] = [];\n while (allowMissing && !await lstat(current).then(() => true, () => false)) {\n suffix.unshift(basename(current)); current = dirname(current);\n }\n const canonical = join(await realpath(current), ...suffix);\n if (!contained(root, canonical)) throw new Error('Symlink escapes the authorized repository');\n return canonical;\n}\n\nexport async function repository(cwd: string | undefined): Promise<string> {\n if (!cwd || !isAbsolute(cwd)) throw new Error('This session has no local absolute workspace');\n const root = await realpath(cwd);\n if (!(await stat(root)).isDirectory()) throw new Error('Workspace is not a directory');\n for (const marker of ['.git', '.svn']) {\n if (await stat(resolve(root, marker)).then(() => true, () => false)) return root;\n }\n throw new Error('Select a Git or SVN repository before using the graph');\n}\n\nexport function scrubEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n return { ...Object.fromEntries(Object.entries(env).filter(([key, value]) => value !== undefined && !/KEY|PASSWORD|SECRET|TOKEN|^(DSH|CRG|OPENAI|GOOGLE|GEMINI|MINIMAX|VOYAGE|HF)_/i.test(key))), HF_HUB_OFFLINE: '1', TRANSFORMERS_OFFLINE: '1', HF_HUB_DISABLE_TELEMETRY: '1' } as Record<string, string>;\n}\n\nexport async function checkedData(root: string): Promise<void> {\n const dir = resolve(root, '.code-review-graph');\n if (!await lstat(dir).then(() => true, () => false)) return;\n await checkedPath(root, dir);\n const entries = await readdir(dir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (entry.isSymbolicLink()) await checkedPath(root, join(entry.parentPath, entry.name));\n }\n}\n", "import type { Context } from '@deepseek-ai/cordis';\nimport type { ToolRunContext } from '@deepseek-ai/dsh-tools';\nimport type {} from '@deepseek-ai/dsh-fs';\nimport type {} from '@deepseek-ai/dsh-sandbox-policy';\nimport { checkedPath, sha256 } from './safety.ts';\n\nexport interface EditPlan { files: { path: string; before_sha256: string; after_content: string; edit_count: number }[] }\nexport async function commitPlan(ctx: Context, exec: ToolRunContext, root: string, plan: EditPlan) {\n if (!exec.agent) throw new Error('Refactor requires a session-owned agent');\n const policy = ctx.sandboxPolicy.resolve({ session: exec.agent.session });\n if (policy.mode === 'read-only') throw new Error('Refactor is denied by read-only policy');\n if (!Array.isArray(plan.files)) throw new Error('Invalid edit plan');\n const prepared = [];\n const seen = new Set<string>();\n for (const file of plan.files) {\n if (typeof file.path !== 'string' || !/^[a-f0-9]{64}$/.test(file.before_sha256) || typeof file.after_content !== 'string' || !Number.isInteger(file.edit_count) || file.edit_count < 0) throw new Error('Invalid edit plan file');\n exec.signal.throwIfAborted();\n const path = await checkedPath(root, file.path);\n if (seen.has(path)) throw new Error('Duplicate edit target');\n seen.add(path);\n const target = await ctx.fs.resolve(path, { cwd: root, signal: exec.signal });\n const before = await ctx.fs.stat(target, exec.signal);\n if (!before || before.type !== 'file') throw new Error('Edit target is not a regular file');\n const bytes = await ctx.fs.readBytes(target, exec.signal, 32 * 1024 * 1024);\n if (sha256(bytes) !== file.before_sha256) throw new Error(`Stale edit plan: ${path}`);\n const after = await ctx.fs.stat(target, exec.signal);\n if (after?.version !== before.version) throw new Error(`File changed during preflight: ${path}`);\n const intent = await ctx.waterfall('fs/write-intent', target, exec, () => undefined);\n if (intent && (intent.kind !== 'replaceIfVersion' || intent.version !== before.version)) throw new Error(`File intent disagrees with edit plan: ${path}`);\n prepared.push({ file, path, target, original: Buffer.from(bytes).toString('utf8'), intent: intent ?? { kind: 'replaceIfVersion' as const, version: before.version } });\n }\n const applied: string[] = [];\n const recovery: EditPlan['files'] = [];\n try {\n for (const item of prepared) {\n exec.signal.throwIfAborted();\n await checkedPath(root, item.path);\n const outcome = await ctx.fs.writeText(item.target, item.file.after_content, item.intent, exec.signal, policy);\n ctx.emit('fs/observed', item.target, { kind: 'present', version: outcome.version }, exec);\n applied.push(item.path);\n recovery.push({ path: item.path, before_sha256: sha256(item.file.after_content), after_content: item.original, edit_count: item.file.edit_count });\n }\n } catch (error) {\n // Return the complete recovery patch through the tool output; never silently roll back a later edit.\n return { status: 'partial_failure', error: String(error), files_modified: applied, recovery_patch: { files: recovery } };\n }\n return { status: 'ok', files_modified: applied, edits_applied: plan.files.reduce((n, f) => n + f.edit_count, 0) };\n}\n", "export const groups = ['context', 'review', 'refactor', 'export', 'advanced', 'all'] as const;\nexport type Workflow = typeof groups[number];\nconst context = ['build_or_update_graph_tool', 'get_minimal_context_tool', 'query_graph_tool', 'semantic_search_nodes_tool', 'list_graph_stats_tool', 'get_docs_section_tool'];\nconst members: Record<Exclude<Workflow, 'all'>, string[]> = {\n context,\n review: [...context, 'detect_changes_tool', 'get_review_context_tool', 'get_impact_radius_tool', 'get_affected_flows_tool', 'list_flows_tool', 'get_flow_tool', 'list_communities_tool'],\n refactor: [...context, 'refactor_tool', 'apply_refactor_tool', 'find_large_functions_tool', 'get_impact_radius_tool', 'get_affected_flows_tool', 'detect_changes_tool'],\n export: [...context, 'generate_wiki_tool', 'get_wiki_page_tool'],\n advanced: [...context, 'embed_graph_tool', 'run_postprocess_tool', 'list_repos_tool', 'cross_repo_search_tool', 'list_communities_tool', 'get_community_tool', 'get_architecture_overview_tool', 'get_hub_nodes_tool', 'get_bridge_nodes_tool', 'get_knowledge_gaps_tool', 'get_surprising_connections_tool', 'get_suggested_questions_tool', 'traverse_graph_tool', 'detect_changes_tool', 'list_flows_tool', 'get_flow_tool', 'find_large_functions_tool'],\n};\nexport const skillWorkflow: Record<string, Workflow> = {\n 'build-graph': 'advanced', 'debug-issue': 'review', 'explore-codebase': 'advanced',\n 'refactor-safely': 'refactor', 'review-changes': 'review', 'review-delta': 'review', 'review-pr': 'review',\n};\nexport const publicName = (raw: string): string => `mcp__code_review_graph__${raw}`;\nexport function exposed(workflow: Workflow, names: string[]): string[] {\n return workflow === 'all' ? names : names.filter(name => members[workflow].includes(name));\n}\n"],
5
- "mappings": "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",
6
- "names": ["readdir", "stat", "join", "basename", "resolve", "name", "name", "join", "basename", "stat", "result", "value", "name", "readdir"]
3
+ "sources": ["../src/index.ts", "../src/backend.ts", "../src/safety.ts", "../src/refactor.ts", "../src/workflows.ts", "../src/setup.ts"],
4
+ "sourcesContent": ["import type { Context } from '@deepseek-ai/cordis';\nimport type { ToolDefinition, ToolRunContext } from '@deepseek-ai/dsh-tools';\nimport type {} from '@deepseek-ai/dsh-agent';\nimport type {} from '@deepseek-ai/dsh-skill';\nimport type {} from '@deepseek-ai/dsh-system-prompt';\nimport z from '@deepseek-ai/schemastery';\nimport { Ajv } from 'ajv';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport { BackendPool, run, valueOf, type Engine } from './backend.ts';\nimport { repository, checkedPath, sha256 } from './safety.ts';\nimport { commitPlan, type EditPlan } from './refactor.ts';\nimport { exposed, groups, publicName, skillWorkflow, type Workflow } from './workflows.ts';\nimport { prepare } from './setup.ts';\n\nexport const name = 'code-review-graph';\nexport const inject = ['tools', 'agents', 'fs', 'sandboxPolicy', 'skills', 'systemPrompt'];\nconst engineDir = join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'code-review-graph', 'engine');\nexport const Config = z.object({\n engineCommand: z.string().default(join(engineDir, process.platform === 'win32' ? 'Scripts/code-review-graph.exe' : 'bin/code-review-graph')),\n engineArgs: z.array(z.string()).default([]),\n timeoutMs: z.number().min(1000).default(120000),\n authorizedRepos: z.array(z.string()).default([]),\n embeddingProviders: z.array(z.string()).default(['local']),\n embeddingEnv: z.array(z.string()).default([]),\n});\nexport interface Configuration { engineCommand: string; engineArgs: string[]; timeoutMs: number; authorizedRepos: string[]; embeddingProviders: string[]; embeddingEnv: string[] }\ninterface Capability { name: string; description?: string; inputSchema: Record<string, unknown> & { properties?: Record<string, unknown>; required?: string[] } }\nexport const output: ToolDefinition['output'] = {\n schema: { type: 'object', additionalProperties: true },\n render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],\n};\n\nexport async function apply(ctx: Context, config: Configuration): Promise<void> {\n const engine: Engine = { command: config.engineCommand, args: config.engineArgs, timeoutMs: config.timeoutMs, env: Object.fromEntries(config.embeddingEnv.filter(key => /^(OPENAI|GOOGLE|GEMINI|MINIMAX|VOYAGE|CRG)_/.test(key) && process.env[key] !== undefined).map(key => [key, process.env[key]!])) };\n const pool = new BackendPool(engine);\n const snapshot = JSON.parse(await readFile(new URL('../capabilities.json', import.meta.url), 'utf8')) as { tools: Capability[] };\n const tools = snapshot.tools.filter(t => t.name !== 'get_refactor_edit_plan_tool');\n const names = tools.map(t => t.name);\n const masks = new Map<string, () => void>();\n const ajv = new Ajv({ strict: false, allErrors: true });\n const life = new AbortController();\n ctx.effect(() => () => { life.abort(); for (const dispose of masks.values()) dispose(); return pool.dispose(); });\n const switchWorkflow = (agent: NonNullable<ToolRunContext['agent']>, workflow?: Workflow) => {\n pool.activate(agent.id);\n const available = workflow ? exposed(workflow, names) : [];\n masks.get(agent.id)?.();\n masks.set(agent.id, agent.ctx.tools.restrict({ deny: names.filter(n => !available.includes(n)).map(publicName) }));\n return available.map(publicName);\n };\n\n async function rootFor(exec: ToolRunContext) {\n if (!exec.agent) throw new Error('Graph tools require a session-owned agent');\n return repository(exec.agent.session.header.cwd);\n }\n\n async function invoke(raw: string, args: Record<string, unknown>, exec: ToolRunContext) {\n const root = await rootFor(exec);\n const owner = exec.agent!.id;\n const signal = AbortSignal.any([exec.signal, life.signal]);\n const providerKey = ['build_or_update_graph_tool', 'run_postprocess_tool'].includes(raw) ? 'embedding_provider' : 'provider';\n const provider = args[providerKey];\n if (raw === 'get_docs_section_tool') await checkedPath(root, 'docs/LLM-OPTIMIZED-REFERENCE.md', true);\n if (provider && (typeof provider !== 'string' || !config.embeddingProviders.includes(provider))) throw new Error('Embedding provider has not been authorized in plugin configuration');\n if (['semantic_search_nodes_tool', 'embed_graph_tool'].includes(raw) && !provider) args = { ...args, provider: 'local' };\n for (const key of ['file_path', 'file', 'path']) {\n if (typeof args[key] === 'string') await checkedPath(root, args[key] as string);\n }\n for (const key of ['changed_files', 'files']) {\n if (Array.isArray(args[key])) for (const path of args[key] as string[]) await checkedPath(root, path, true);\n }\n if (raw === 'list_repos_tool') {\n const roots = [...new Set([root, ...await Promise.all(config.authorizedRepos.map(repository))])];\n return { status: 'ok', repos: roots.map(path => ({ alias: roots.filter(r => basename(r) === basename(path)).length > 1 ? `${basename(path)}@${sha256(path).slice(0, 8)}` : basename(path), path })) };\n }\n if (raw === 'cross_repo_search_tool') {\n const roots = [...new Set([root, ...await Promise.all(config.authorizedRepos.map(repository))])];\n const aliases = roots.map(path => ({ path, alias: roots.filter(r => basename(r) === basename(path)).length > 1 ? `${basename(path)}@${sha256(path).slice(0, 8)}` : basename(path) }));\n const selected = Array.isArray(args.repos) ? args.repos as string[] : [];\n if (selected.some(n => !aliases.some(r => r.alias === n))) throw new Error('Repository is not authorized');\n const results: Record<string, unknown>[] = [];\n for (const { path: repo, alias } of aliases.filter(r => !selected.length || selected.includes(r.alias))) {\n if (repo !== root && !await stat(join(repo, '.code-review-graph/graph.db')).then(() => true, () => false)) throw new Error(`Build ${repo} in its own session first`);\n await pool.ensure(repo, owner, signal);\n const data = valueOf(await pool.call(repo, owner, 'semantic_search_nodes_tool', { query: args.query, kind: args.kind, limit: args.limit ?? 20, provider: 'local', repo_root: repo }, signal));\n for (const result of data.results as Record<string, unknown>[]) results.push({ ...result, repo: alias });\n }\n results.sort((a, b) => Number(b.score ?? 0) - Number(a.score ?? 0));\n const limit = Math.min(Number(args.max_results ?? 50), 100);\n return { status: 'ok', results: results.slice(0, limit), total: results.length, results_omitted: Math.max(0, results.length - limit), truncated: results.length > limit };\n }\n const graphUpdate = raw !== 'build_or_update_graph_tool' ? await pool.ensure(root, owner, signal) : undefined;\n if (raw === 'apply_refactor_tool' && !args.dry_run) {\n const plan = valueOf(await pool.call(root, owner, 'get_refactor_edit_plan_tool', { refactor_id: args.refactor_id, repo_root: root }, signal)) as unknown as EditPlan;\n const result = await commitPlan(ctx, exec, root, plan);\n if (result.status === 'ok') {\n try { return { ...result, graph_update: valueOf(await pool.call(root, owner, 'build_or_update_graph_tool', { repo_root: root }, signal)) }; }\n catch (error) { return { ...result, graph_update_error: String(error) }; }\n }\n return result;\n }\n if (raw === 'apply_refactor_tool') args = { ...args, dry_run: true };\n const result = valueOf(await pool.call(root, owner, raw, { ...args, repo_root: root }, signal));\n if (raw === 'build_or_update_graph_tool') await pool.ensure(root, owner, signal);\n return graphUpdate ? { ...result, graph_update: graphUpdate } : result;\n }\n\n for (const tool of tools) {\n const parameters = structuredClone(tool.inputSchema);\n delete parameters.properties?.repo_root;\n parameters.required = parameters.required?.filter(n => n !== 'repo_root');\n parameters.additionalProperties = false;\n const validate = ajv.compile(parameters);\n const definition = {\n name: publicName(tool.name), description: tool.description ?? tool.name, parameters, output,\n timeoutMs: config.timeoutMs,\n execute: async (args: unknown, exec: ToolRunContext) => {\n if (!validate(args)) throw new Error(ajv.errorsText(validate.errors));\n return invoke(tool.name, args as Record<string, unknown>, exec);\n },\n } as ToolDefinition;\n ctx.effect(() => ctx.tools.register(definition));\n }\n\n ctx.effect(() => ctx.tools.register({ name: 'crg_workflow', description: 'Select code graph tools: context, review, refactor, export, advanced or all. Begin with get_minimal_context.',\n parameters: { type: 'object', properties: { workflow: { type: 'string', enum: [...groups] } }, required: ['workflow'], additionalProperties: false }, output,\n execute: async (args, exec) => {\n const workflow = (args as { workflow: Workflow }).workflow;\n if (!groups.includes(workflow) || !exec.agent) throw new Error('Invalid workflow or missing agent');\n return { tools: switchWorkflow(exec.agent, workflow) };\n },\n }));\n\n const visualizationSchema = { type: 'object', properties: {\n mode: { type: 'string', enum: ['auto', 'file', 'community', 'full'] },\n format: { type: 'string', enum: ['html', 'json', 'graphml', 'cypher', 'obsidian', 'svg'] },\n seed_file: { type: 'array', items: { type: 'string' } }, seed_symbol: { type: 'string' }, seed_changed: { type: 'boolean' }, seed_changed_base: { type: 'string' }, seed_flow: { type: 'string' },\n path_from: { type: 'string' }, path_to: { type: 'string' }, depth: { type: 'integer', minimum: 0 }, render_depth: { type: 'integer', minimum: 0 }, max_nodes: { type: 'integer', minimum: 1 },\n }, additionalProperties: false };\n const validateVisualization = ajv.compile(visualizationSchema);\n async function visualize(args: Record<string, unknown>, agent: NonNullable<ToolRunContext['agent']>, signal: AbortSignal) {\n const root = await repository(agent.session.header.cwd);\n signal = AbortSignal.any([signal, life.signal]);\n const graphUpdate = await pool.ensure(root, agent.id, signal);\n for (const path of (args.seed_file ?? []) as string[]) await checkedPath(root, path, true);\n const command = ['visualize', '--repo', root];\n for (const [key, value] of Object.entries(args)) {\n const flag = `--${key.replaceAll('_', '-')}`;\n if (Array.isArray(value)) for (const item of value) command.push(flag, String(item));\n else if (value === true) command.push(flag);\n else if (value !== undefined && value !== false) command.push(flag, String(value));\n }\n const { log } = await run(engine, command, root, signal);\n const format = String(args.format ?? 'html');\n return { status: 'ok', path: join(root, '.code-review-graph', format === 'obsidian' ? 'obsidian' : `graph.${format}`), ...(format === 'html' ? { sidebar: 'code-review-graph' } : {}), ...(graphUpdate ? { graph_update: graphUpdate } : {}), log };\n }\n\n // Native human commands reuse DSH's session/Agent lookup, cancellation and command history.\n // They never send a prompt or tool request to a model.\n let preparation: Promise<void> | undefined;\n const prepareDefault = (signal: AbortSignal) => {\n if (config.engineCommand !== join(engineDir, process.platform === 'win32' ? 'Scripts/code-review-graph.exe' : 'bin/code-review-graph') || config.engineArgs.length) {\n throw new Error('A custom engine is configured. Prepare that engine, or restore the default engine configuration. / \u5F53\u524D\u914D\u7F6E\u4E86\u81EA\u5B9A\u4E49\u5F15\u64CE\uFF0C\u8BF7\u51C6\u5907\u8BE5\u5F15\u64CE\u6216\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E\u3002');\n }\n return preparation ??= prepare(undefined, undefined, { signal: AbortSignal.any([signal, life.signal]) }).finally(() => { preparation = undefined; });\n };\n type HumanInvocation = { agent: NonNullable<ToolRunContext['agent']>; signal: AbortSignal; rawInput: string };\n ctx.inject(['commands'], scope => {\n const commands = scope.get('commands') as { register(definition: { name: string; description: string; handler: (invocation: HumanInvocation) => Promise<{ kind: 'success'; text: string }> }): () => void };\n scope.effect(() => commands.register({ name: 'crg-setup', description: '\u51C6\u5907\u672C\u5730\u56FE\u8C31\u5F15\u64CE / Prepare the local graph engine', handler: async ({ signal, rawInput }) => {\n if (rawInput.trim()) throw new Error('/crg-setup does not need parameters / \u65E0\u9700\u586B\u5199\u53C2\u6570');\n await prepareDefault(signal);\n return { kind: 'success', text: '\u56FE\u8C31\u5F15\u64CE\u5DF2\u51C6\u5907\u597D\u3002\u6253\u5F00\u53F3\u4FA7\u4EE3\u7801\u56FE\u8C31\uFF0C\u70B9\u51FB\u751F\u6210\u56FE\u8C31\u3002 / Engine ready. Open Code graph and click Generate graph.' };\n } }));\n scope.effect(() => commands.register({ name: 'crg-graph', description: '\u751F\u6210\uFF0F\u66F4\u65B0\u4EA4\u4E92\u4EE3\u7801\u56FE\u8C31\uFF0C\u65E0\u9700\u6A21\u578B / Generate or update the interactive code graph without a model', handler: async ({ agent, signal, rawInput }) => {\n if (rawInput.trim()) throw new Error('/crg-graph does not need parameters / \u65E0\u9700\u586B\u5199\u53C2\u6570');\n await repository(agent.session.header.cwd);\n if (config.engineCommand === join(engineDir, process.platform === 'win32' ? 'Scripts/code-review-graph.exe' : 'bin/code-review-graph') && !config.engineArgs.length) await prepareDefault(signal);\n const result = await visualize({ mode: 'full', format: 'html' }, agent, signal);\n return { kind: 'success', text: `\u56FE\u8C31\u5DF2\u751F\u6210 / Graph generated: ${result.path}${result.graph_update ? '\\n\u89E3\u6790\u8B66\u544A / Parse warnings: ' + JSON.stringify(result.graph_update) : ''}` };\n } }));\n });\n ctx.effect(() => ctx.tools.register({ name: 'crg_visualize', description: 'Generate the local interactive graph for the DSH Code graph sidebar, or export HTML, JSON, GraphML, Cypher, Obsidian or SVG. Supports file, community, symbol, changed-code, flow and shortest-path views.',\n parameters: visualizationSchema, output,\n timeoutMs: config.timeoutMs,\n execute: async (value, exec) => {\n if (!validateVisualization(value)) throw new Error(ajv.errorsText(validateVisualization.errors));\n if (!exec.agent) throw new Error('Graph tools require a session-owned agent');\n return visualize(value as Record<string, unknown>, exec.agent, exec.signal);\n },\n }));\n const promptNames = ['review_changes', 'architecture_map', 'debug_issue', 'onboard_developer', 'pre_merge_check'];\n const promptSchema = { type: 'object', properties: { name: { type: 'string', enum: promptNames }, base: { type: 'string' }, description: { type: 'string' } }, required: ['name'], additionalProperties: false };\n const validatePrompt = ajv.compile(promptSchema);\n ctx.effect(() => ctx.tools.register({ name: 'crg_prompt', description: 'Load one of the five original CRG workflows and reveal its graph tools.', parameters: promptSchema, output,\n execute: async (args, exec) => {\n if (!validatePrompt(args) || !exec.agent) throw new Error('Invalid workflow prompt or missing agent');\n const { name, ...parameters } = args as { name: string; base?: string; description?: string };\n const workflow: Workflow = name === 'pre_merge_check' ? 'all' : name === 'review_changes' ? 'review' : name === 'debug_issue' ? 'review' : 'advanced';\n switchWorkflow(exec.agent, workflow);\n const root = await rootFor(exec);\n const { client } = await pool.acquire(root, exec.agent.id);\n const result = await client.getPrompt({ name, arguments: parameters }, { signal: AbortSignal.any([exec.signal, life.signal]), timeout: config.timeoutMs });\n return { ...result, messages: result.messages.map(message => ({ ...message, content: message.content.type === 'text' ? { ...message.content, text: message.content.text.replace(/\\b([a-z_]+_tool)\\b/g, raw => names.includes(raw) ? publicName(raw) : raw) } : message.content })) };\n },\n }));\n ctx.on('agent/created', ({ agent }) => { switchWorkflow(agent); return undefined; });\n ctx.on('agent/disposed', ({ agent }) => { masks.get(agent.id)?.(); masks.delete(agent.id); return pool.release(agent.id); });\n for (const agent of ctx.agents.list()) switchWorkflow(agent);\n ctx.effect(() => ctx.systemPrompt.section({ name: 'code-review-graph', order: 80, interpolate: false,\n text: 'Use crg_workflow to reveal task-specific local code graph tools, then get_minimal_context_tool before broader queries. Prefer minimal detail. crg_visualize generates a local graph for the Code graph sidebar; users can also generate it directly from that page without a model. Refactors use session filesystem permissions.' }));\n\n const skillsDir = new URL('../skills/', import.meta.url);\n for (const slug of await readdir(skillsDir)) {\n const path = new URL(`${slug}/SKILL.md`, skillsDir);\n const body = await readFile(path, 'utf8');\n const content = body.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n/, '').replace(/\\b([a-z_]+_tool)\\b/g, raw => names.includes(raw) ? publicName(raw) : raw);\n if (!skillWorkflow[slug]) throw new Error(`Unmapped CRG skill: ${slug}`);\n ctx.effect(() => ctx.skills.register({ name: `crg-${slug}`, description: `Code review graph: ${slug}`, source: 'bundled', content: `First call crg_workflow with workflow \"${skillWorkflow[slug]}\". Tool names use mcp__code_review_graph__ prefixes.\\n\\n${content}` }));\n }\n}\n", "import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { checkedData, scrubEnv } from './safety.ts';\n\nexport interface Engine { command: string; args: string[]; timeoutMs: number; env?: Record<string, string> }\nconst environment = (engine: Engine) => ({ ...scrubEnv(process.env), ...engine.env });\nexport function valueOf(result: unknown): Record<string, unknown> {\n const r = result as { isError?: boolean; structuredContent?: Record<string, unknown>; content?: { type: string; text?: string }[] };\n const text = r.content?.filter(x => x.type === 'text').map(x => x.text).join('\\n') ?? '';\n if (r.isError) throw new Error(text || 'Engine tool failed');\n const value = r.structuredContent ?? (() => { try { return JSON.parse(text); } catch { return { text }; } })();\n if (value.status === 'error') throw new Error(String(value.error));\n return value;\n}\n\nexport async function connect(engine: Engine, cwd: string): Promise<Client> {\n await checkedData(cwd);\n const transport = new StdioClientTransport({ command: engine.command, args: [...engine.args, 'serve', '--repo', cwd], cwd, env: environment(engine), stderr: 'pipe' });\n transport.stderr?.on('data', () => {});\n const client = new Client({ name: 'dsh-code-review-graph', version: '0.1.2' });\n try { await client.connect(transport); return client; }\n catch (error) { await transport.close(); throw new Error(`CRG engine unavailable. Open Code graph and click Set up engine, or run /crg-setup (CLI: dsh-crg prepare). ${String(error)}`); }\n}\n\nasync function stop(child?: ChildProcess): Promise<void> {\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n await new Promise<void>(resolve => {\n const timer = setTimeout(() => { child.kill('SIGKILL'); resolve(); }, 3000);\n child.once('exit', () => { clearTimeout(timer); resolve(); });\n child.kill();\n });\n}\ninterface Entry { client: Client; owners: Set<string>; ready?: Promise<void>; watcher?: ChildProcess; watchError?: string; queue: Promise<unknown>; update?: Record<string, unknown> }\nexport class BackendPool {\n private entries = new Map<string, Promise<Entry>>();\n private retired = new Set<string>();\n private closed = false;\n constructor(readonly engine: Engine) {}\n activate(owner: string): void { this.retired.delete(owner); }\n\n async acquire(root: string, owner: string): Promise<Entry> {\n if (this.closed || this.retired.has(owner)) throw new Error('Session has been released');\n let promise = this.entries.get(root);\n if (!promise) {\n promise = connect(this.engine, root).then(client => ({ client, owners: new Set<string>(), queue: Promise.resolve() }));\n this.entries.set(root, promise);\n promise.catch(() => { if (this.entries.get(root) === promise) this.entries.delete(root); });\n }\n const entry = await promise;\n if (this.closed || this.retired.has(owner)) throw new Error('Session has been released');\n entry.owners.add(owner);\n return entry;\n }\n\n async call(root: string, owner: string, name: string, args: Record<string, unknown>, signal: AbortSignal) {\n const entry = await this.acquire(root, owner);\n // One mutation at a time per SQLite graph; cancellation restarts this repository's shared worker.\n const work = entry.queue.catch(() => {}).then(async () => {\n signal.throwIfAborted();\n const cancel = () => { this.entries.delete(root); void stop(entry.watcher); void entry.client.close(); };\n signal.addEventListener('abort', cancel, { once: true });\n let result: unknown;\n try {\n await checkedData(root);\n if (entry.watchError) throw new Error(`Incremental watcher stopped: ${entry.watchError}`);\n result = await entry.client.callTool({ name, arguments: args }, undefined, { signal, timeout: this.engine.timeoutMs });\n } catch (error) {\n // A timed-out Python thread cannot safely be left mutating the graph.\n this.entries.delete(root); await stop(entry.watcher); await entry.client.close();\n throw error;\n } finally { signal.removeEventListener('abort', cancel); }\n // A normal tool error must not discard another call's pending refactor preview.\n valueOf(result);\n return result;\n });\n entry.queue = work;\n return work;\n }\n\n async ensure(root: string, owner: string, signal: AbortSignal): Promise<Record<string, unknown> | undefined> {\n const entry = await this.acquire(root, owner);\n entry.ready ??= (async () => {\n // An existing database can be stale after all sessions were closed.\n const update = valueOf(await this.call(root, owner, 'build_or_update_graph_tool', { repo_root: root }, signal));\n if (update.status === 'partial' || Array.isArray(update.warnings) && update.warnings.length) entry.update = update;\n signal.throwIfAborted();\n const watcher = spawn(this.engine.command, [...this.engine.args, 'watch', '--repo', root], { cwd: root, env: environment(this.engine), stdio: 'ignore', windowsHide: true });\n entry.watcher = watcher;\n await new Promise<void>((resolve, reject) => { watcher.once('spawn', resolve); watcher.once('error', reject); });\n watcher.on('error', error => { entry.watchError = String(error); });\n watcher.on('exit', (code, reason) => { if (entry.watcher === watcher) entry.watchError = `exit ${code ?? reason}`; });\n })().catch(error => { entry.ready = undefined; throw error; });\n await entry.ready;\n if (entry.watchError) throw new Error(`Incremental watcher stopped: ${entry.watchError}`);\n return entry.update;\n }\n\n async release(owner: string): Promise<void> {\n this.retired.add(owner);\n for (const [root, promise] of this.entries) {\n const entry = await promise.catch(() => undefined);\n if (!entry) continue;\n entry.owners.delete(owner);\n if (!entry.owners.size) { this.entries.delete(root); const watcher = entry.watcher; entry.watcher = undefined; await stop(watcher); await entry.client.close(); }\n }\n }\n\n async dispose(): Promise<void> {\n this.closed = true;\n const entries = [...this.entries.values()]; this.entries.clear();\n for (const promise of entries) {\n const entry = await promise.catch(() => undefined);\n if (entry) { const watcher = entry.watcher; entry.watcher = undefined; await stop(watcher); await entry.client.close(); }\n }\n }\n}\n\nexport async function run(engine: Engine, args: string[], cwd: string, signal: AbortSignal): Promise<{ log: string }> {\n await checkedData(cwd);\n signal = AbortSignal.any([signal, AbortSignal.timeout(engine.timeoutMs)]);\n return new Promise((resolve, reject) => {\n let log = '';\n const child = spawn(engine.command, [...engine.args, ...args], { cwd, env: environment(engine), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, signal });\n const capture = (bytes: Buffer) => { log = (log + bytes.toString()).slice(-16000); };\n child.stdout?.on('data', capture); child.stderr?.on('data', capture);\n child.on('error', reject);\n child.on('exit', code => code === 0 ? resolve({ log }) : reject(new Error(`Engine command exited ${code}: ${log}`)));\n });\n}\n", "import { realpath, stat, lstat, readdir } from 'node:fs/promises';\nimport { isAbsolute, relative, resolve, sep, dirname, basename, join } from 'node:path';\nimport { createHash } from 'node:crypto';\n\nexport const sha256 = (bytes: Uint8Array | string): string => createHash('sha256').update(bytes).digest('hex');\n\nexport function contained(root: string, path: string): boolean {\n const part = relative(root, path);\n return part === '' || (!isAbsolute(part) && part !== '..' && !part.startsWith(`..${sep}`));\n}\n\nexport async function checkedPath(root: string, value: string, allowMissing = false): Promise<string> {\n const candidate = resolve(root, value);\n if (!contained(root, candidate)) throw new Error('Path is outside the authorized repository');\n let current = candidate;\n const suffix: string[] = [];\n while (allowMissing && !await lstat(current).then(() => true, () => false)) {\n suffix.unshift(basename(current)); current = dirname(current);\n }\n const canonical = join(await realpath(current), ...suffix);\n if (!contained(root, canonical)) throw new Error('Symlink escapes the authorized repository');\n return canonical;\n}\n\nexport async function repository(cwd: string | undefined): Promise<string> {\n if (!cwd || !isAbsolute(cwd)) throw new Error('This session has no local absolute workspace');\n const root = await realpath(cwd);\n if (!(await stat(root)).isDirectory()) throw new Error('Workspace is not a directory');\n for (const marker of ['.git', '.svn']) {\n if (await stat(resolve(root, marker)).then(() => true, () => false)) return root;\n }\n throw new Error('Select a Git or SVN repository before using the graph');\n}\n\nexport function scrubEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n return { ...Object.fromEntries(Object.entries(env).filter(([key, value]) => value !== undefined && !/KEY|PASSWORD|SECRET|TOKEN|^(DSH|CRG|OPENAI|GOOGLE|GEMINI|MINIMAX|VOYAGE|HF)_/i.test(key))), HF_HUB_OFFLINE: '1', TRANSFORMERS_OFFLINE: '1', HF_HUB_DISABLE_TELEMETRY: '1' } as Record<string, string>;\n}\n\nexport async function checkedData(root: string): Promise<void> {\n const dir = resolve(root, '.code-review-graph');\n if (!await lstat(dir).then(() => true, () => false)) return;\n await checkedPath(root, dir);\n const entries = await readdir(dir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (entry.isSymbolicLink()) await checkedPath(root, join(entry.parentPath, entry.name));\n }\n}\n", "import type { Context } from '@deepseek-ai/cordis';\nimport type { ToolRunContext } from '@deepseek-ai/dsh-tools';\nimport type {} from '@deepseek-ai/dsh-fs';\nimport type {} from '@deepseek-ai/dsh-sandbox-policy';\nimport { checkedPath, sha256 } from './safety.ts';\n\nexport interface EditPlan { files: { path: string; before_sha256: string; after_content: string; edit_count: number }[] }\nexport async function commitPlan(ctx: Context, exec: ToolRunContext, root: string, plan: EditPlan) {\n if (!exec.agent) throw new Error('Refactor requires a session-owned agent');\n const policy = ctx.sandboxPolicy.resolve({ session: exec.agent.session });\n if (policy.mode === 'read-only') throw new Error('Refactor is denied by read-only policy');\n if (!Array.isArray(plan.files)) throw new Error('Invalid edit plan');\n const prepared = [];\n const seen = new Set<string>();\n for (const file of plan.files) {\n if (typeof file.path !== 'string' || !/^[a-f0-9]{64}$/.test(file.before_sha256) || typeof file.after_content !== 'string' || !Number.isInteger(file.edit_count) || file.edit_count < 0) throw new Error('Invalid edit plan file');\n exec.signal.throwIfAborted();\n const path = await checkedPath(root, file.path);\n if (seen.has(path)) throw new Error('Duplicate edit target');\n seen.add(path);\n const target = await ctx.fs.resolve(path, { cwd: root, signal: exec.signal });\n const before = await ctx.fs.stat(target, exec.signal);\n if (!before || before.type !== 'file') throw new Error('Edit target is not a regular file');\n const bytes = await ctx.fs.readBytes(target, exec.signal, 32 * 1024 * 1024);\n if (sha256(bytes) !== file.before_sha256) throw new Error(`Stale edit plan: ${path}`);\n const after = await ctx.fs.stat(target, exec.signal);\n if (after?.version !== before.version) throw new Error(`File changed during preflight: ${path}`);\n const intent = await ctx.waterfall('fs/write-intent', target, exec, () => undefined);\n if (intent && (intent.kind !== 'replaceIfVersion' || intent.version !== before.version)) throw new Error(`File intent disagrees with edit plan: ${path}`);\n prepared.push({ file, path, target, original: Buffer.from(bytes).toString('utf8'), intent: intent ?? { kind: 'replaceIfVersion' as const, version: before.version } });\n }\n const applied: string[] = [];\n const recovery: EditPlan['files'] = [];\n try {\n for (const item of prepared) {\n exec.signal.throwIfAborted();\n await checkedPath(root, item.path);\n const outcome = await ctx.fs.writeText(item.target, item.file.after_content, item.intent, exec.signal, policy);\n ctx.emit('fs/observed', item.target, { kind: 'present', version: outcome.version }, exec);\n applied.push(item.path);\n recovery.push({ path: item.path, before_sha256: sha256(item.file.after_content), after_content: item.original, edit_count: item.file.edit_count });\n }\n } catch (error) {\n // Return the complete recovery patch through the tool output; never silently roll back a later edit.\n return { status: 'partial_failure', error: String(error), files_modified: applied, recovery_patch: { files: recovery } };\n }\n return { status: 'ok', files_modified: applied, edits_applied: plan.files.reduce((n, f) => n + f.edit_count, 0) };\n}\n", "export const groups = ['context', 'review', 'refactor', 'export', 'advanced', 'all'] as const;\nexport type Workflow = typeof groups[number];\nconst context = ['build_or_update_graph_tool', 'get_minimal_context_tool', 'query_graph_tool', 'semantic_search_nodes_tool', 'list_graph_stats_tool', 'get_docs_section_tool'];\nconst members: Record<Exclude<Workflow, 'all'>, string[]> = {\n context,\n review: [...context, 'detect_changes_tool', 'get_review_context_tool', 'get_impact_radius_tool', 'get_affected_flows_tool', 'list_flows_tool', 'get_flow_tool', 'list_communities_tool'],\n refactor: [...context, 'refactor_tool', 'apply_refactor_tool', 'find_large_functions_tool', 'get_impact_radius_tool', 'get_affected_flows_tool', 'detect_changes_tool'],\n export: [...context, 'generate_wiki_tool', 'get_wiki_page_tool'],\n advanced: [...context, 'embed_graph_tool', 'run_postprocess_tool', 'list_repos_tool', 'cross_repo_search_tool', 'list_communities_tool', 'get_community_tool', 'get_architecture_overview_tool', 'get_hub_nodes_tool', 'get_bridge_nodes_tool', 'get_knowledge_gaps_tool', 'get_surprising_connections_tool', 'get_suggested_questions_tool', 'traverse_graph_tool', 'detect_changes_tool', 'list_flows_tool', 'get_flow_tool', 'find_large_functions_tool'],\n};\nexport const skillWorkflow: Record<string, Workflow> = {\n 'build-graph': 'advanced', 'debug-issue': 'review', 'explore-codebase': 'advanced',\n 'refactor-safely': 'refactor', 'review-changes': 'review', 'review-delta': 'review', 'review-pr': 'review',\n};\nexport const publicName = (raw: string): string => `mcp__code_review_graph__${raw}`;\nexport function exposed(workflow: Workflow, names: string[]): string[] {\n return workflow === 'all' ? names : names.filter(name => members[workflow].includes(name));\n}\n", "#!/usr/bin/env node\nimport { spawn } from 'node:child_process';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport const environment = join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'code-review-graph', 'engine');\nexport const pythonIn = (dir: string) => join(dir, process.platform === 'win32' ? 'Scripts/python.exe' : 'bin/python');\ninterface Preparation { signal?: AbortSignal; onProgress?: (text: string) => void }\nasync function command(exe: string, args: string[], quiet = false, options: Preparation = {}): Promise<void> {\n options.signal?.throwIfAborted();\n await new Promise<void>((resolve, reject) => {\n let log = '';\n const child = spawn(exe, args, { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, signal: options.signal });\n const capture = (bytes: Buffer) => { const text = bytes.toString(); log = (log + text).slice(-16000); if (!quiet) options.onProgress?.(text); };\n child.stdout.on('data', capture); child.stderr.on('data', capture);\n child.on('error', reject); child.on('close', code => code === 0 ? resolve() : reject(new Error(`${exe} exited ${code}: ${log}`)));\n });\n}\nexport async function prepare(source?: string, python?: string, options: Preparation = {}): Promise<void> {\n options = { ...options, signal: AbortSignal.any([...(options.signal ? [options.signal] : []), AbortSignal.timeout(15 * 60 * 1000)]) };\n options.signal!.throwIfAborted();\n const execute = (exe: string, args: string[], quiet = false) => command(exe, args, quiet, options);\n const engine = JSON.parse(await readFile(new URL('../engine.json', import.meta.url), 'utf8'));\n const pinned = source ?? engine.source;\n const stamp = join(environment, 'dsh-crg-source.json');\n if (await readFile(stamp, 'utf8').then(value => JSON.parse(value).source === pinned, () => false)) {\n try { await execute(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true); options.onProgress?.('CRG engine is already prepared.'); return; } catch { options.signal!.throwIfAborted(); }\n }\n await mkdir(environment, { recursive: true });\n let uv = false;\n try { await execute('uv', ['--version'], true); uv = true; } catch { options.signal!.throwIfAborted(); }\n if (uv && !python) {\n await execute('uv', ['venv', '--allow-existing', '--python', '>=3.10', environment]);\n await execute('uv', ['pip', 'install', '--python', pythonIn(environment), pinned]);\n } else {\n let selected: { exe: string; args: string[] } | undefined;\n for (const candidate of python ? [{ exe: python, args: [] }] : [{ exe: 'python3', args: [] }, { exe: 'python', args: [] }, { exe: 'py', args: ['-3'] }]) {\n try { await execute(candidate.exe, [...candidate.args, '-c', 'import sys; assert sys.version_info >= (3,10)'], true); selected = candidate; break; } catch { options.signal!.throwIfAborted(); }\n }\n if (!selected) throw new Error('Install uv or real Python 3.10+; Windows Store aliases are not a Python runtime.');\n await execute(selected.exe, [...selected.args, '-m', 'venv', environment]);\n await execute(pythonIn(environment), ['-m', 'pip', 'install', pinned]);\n }\n await execute(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true);\n options.signal!.throwIfAborted();\n await writeFile(stamp, JSON.stringify({ source: pinned }), 'utf8');\n}\nif (process.argv[1] && resolve(fileURLToPath(import.meta.url)) === resolve(process.argv[1])) {\n if (process.argv[2] !== 'prepare') { console.error('Usage: dsh-crg prepare [engine-source] [--python executable]'); process.exitCode = 2; }\n else {\n const args = process.argv.slice(3);\n const flag = args.indexOf('--python');\n const python = flag >= 0 ? args.splice(flag, 2)[1] : undefined;\n try { await prepare(args[0], python, { onProgress: text => process.stdout.write(text.endsWith('\\n') ? text : text + '\\n') }); } catch (error) { console.error(String(error)); process.exitCode = 1; }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["readFile", "readdir", "stat", "join", "basename", "homedir", "resolve", "name", "name", "spawn", "join", "resolve", "environment", "join", "homedir", "readFile", "basename", "stat", "result", "command", "name", "readdir"]
7
7
  }
package/dist/setup.js CHANGED
@@ -8,50 +8,66 @@ import { join, resolve } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
9
  var environment = join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), "code-review-graph", "engine");
10
10
  var pythonIn = (dir) => join(dir, process.platform === "win32" ? "Scripts/python.exe" : "bin/python");
11
- async function command(exe, args, quiet = false) {
11
+ async function command(exe, args, quiet = false, options = {}) {
12
+ options.signal?.throwIfAborted();
12
13
  await new Promise((resolve2, reject) => {
13
- const child = spawn(exe, args, { stdio: quiet ? "ignore" : "inherit", windowsHide: true });
14
+ let log = "";
15
+ const child = spawn(exe, args, { stdio: ["ignore", "pipe", "pipe"], windowsHide: true, signal: options.signal });
16
+ const capture = (bytes) => {
17
+ const text = bytes.toString();
18
+ log = (log + text).slice(-16e3);
19
+ if (!quiet) options.onProgress?.(text);
20
+ };
21
+ child.stdout.on("data", capture);
22
+ child.stderr.on("data", capture);
14
23
  child.on("error", reject);
15
- child.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`${exe} exited ${code}`)));
24
+ child.on("close", (code) => code === 0 ? resolve2() : reject(new Error(`${exe} exited ${code}: ${log}`)));
16
25
  });
17
26
  }
18
- async function prepare(source, python) {
27
+ async function prepare(source, python, options = {}) {
28
+ options = { ...options, signal: AbortSignal.any([...options.signal ? [options.signal] : [], AbortSignal.timeout(15 * 60 * 1e3)]) };
29
+ options.signal.throwIfAborted();
30
+ const execute = (exe, args, quiet = false) => command(exe, args, quiet, options);
19
31
  const engine = JSON.parse(await readFile(new URL("../engine.json", import.meta.url), "utf8"));
20
32
  const pinned = source ?? engine.source;
21
33
  const stamp = join(environment, "dsh-crg-source.json");
22
34
  if (await readFile(stamp, "utf8").then((value) => JSON.parse(value).source === pinned, () => false)) {
23
35
  try {
24
- await command(pythonIn(environment), ["-c", "from code_review_graph.refactor import get_refactor_edit_plan"], true);
25
- console.log("CRG engine is already prepared.");
36
+ await execute(pythonIn(environment), ["-c", "from code_review_graph.refactor import get_refactor_edit_plan"], true);
37
+ options.onProgress?.("CRG engine is already prepared.");
26
38
  return;
27
39
  } catch {
40
+ options.signal.throwIfAborted();
28
41
  }
29
42
  }
30
43
  await mkdir(environment, { recursive: true });
31
44
  let uv = false;
32
45
  try {
33
- await command("uv", ["--version"], true);
46
+ await execute("uv", ["--version"], true);
34
47
  uv = true;
35
48
  } catch {
49
+ options.signal.throwIfAborted();
36
50
  }
37
51
  if (uv && !python) {
38
- await command("uv", ["venv", "--allow-existing", "--python", ">=3.10", environment]);
39
- await command("uv", ["pip", "install", "--python", pythonIn(environment), pinned]);
52
+ await execute("uv", ["venv", "--allow-existing", "--python", ">=3.10", environment]);
53
+ await execute("uv", ["pip", "install", "--python", pythonIn(environment), pinned]);
40
54
  } else {
41
55
  let selected;
42
56
  for (const candidate of python ? [{ exe: python, args: [] }] : [{ exe: "python3", args: [] }, { exe: "python", args: [] }, { exe: "py", args: ["-3"] }]) {
43
57
  try {
44
- await command(candidate.exe, [...candidate.args, "-c", "import sys; assert sys.version_info >= (3,10)"], true);
58
+ await execute(candidate.exe, [...candidate.args, "-c", "import sys; assert sys.version_info >= (3,10)"], true);
45
59
  selected = candidate;
46
60
  break;
47
61
  } catch {
62
+ options.signal.throwIfAborted();
48
63
  }
49
64
  }
50
65
  if (!selected) throw new Error("Install uv or real Python 3.10+; Windows Store aliases are not a Python runtime.");
51
- await command(selected.exe, [...selected.args, "-m", "venv", environment]);
52
- await command(pythonIn(environment), ["-m", "pip", "install", pinned]);
66
+ await execute(selected.exe, [...selected.args, "-m", "venv", environment]);
67
+ await execute(pythonIn(environment), ["-m", "pip", "install", pinned]);
53
68
  }
54
- await command(pythonIn(environment), ["-c", "from code_review_graph.refactor import get_refactor_edit_plan"], true);
69
+ await execute(pythonIn(environment), ["-c", "from code_review_graph.refactor import get_refactor_edit_plan"], true);
70
+ options.signal.throwIfAborted();
55
71
  await writeFile(stamp, JSON.stringify({ source: pinned }), "utf8");
56
72
  }
57
73
  if (process.argv[1] && resolve(fileURLToPath(import.meta.url)) === resolve(process.argv[1])) {
@@ -63,7 +79,7 @@ if (process.argv[1] && resolve(fileURLToPath(import.meta.url)) === resolve(proce
63
79
  const flag = args.indexOf("--python");
64
80
  const python = flag >= 0 ? args.splice(flag, 2)[1] : void 0;
65
81
  try {
66
- await prepare(args[0], python);
82
+ await prepare(args[0], python, { onProgress: (text) => process.stdout.write(text.endsWith("\n") ? text : text + "\n") });
67
83
  } catch (error) {
68
84
  console.error(String(error));
69
85
  process.exitCode = 1;
package/dist/setup.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/setup.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\nimport { spawn } from 'node:child_process';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport const environment = join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'code-review-graph', 'engine');\nexport const pythonIn = (dir: string) => join(dir, process.platform === 'win32' ? 'Scripts/python.exe' : 'bin/python');\nasync function command(exe: string, args: string[], quiet = false): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(exe, args, { stdio: quiet ? 'ignore' : 'inherit', windowsHide: true });\n child.on('error', reject); child.on('exit', code => code === 0 ? resolve() : reject(new Error(`${exe} exited ${code}`)));\n });\n}\nexport async function prepare(source?: string, python?: string): Promise<void> {\n const engine = JSON.parse(await readFile(new URL('../engine.json', import.meta.url), 'utf8'));\n const pinned = source ?? engine.source;\n const stamp = join(environment, 'dsh-crg-source.json');\n if (await readFile(stamp, 'utf8').then(value => JSON.parse(value).source === pinned, () => false)) {\n try { await command(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true); console.log('CRG engine is already prepared.'); return; } catch {}\n }\n await mkdir(environment, { recursive: true });\n let uv = false;\n try { await command('uv', ['--version'], true); uv = true; } catch {}\n if (uv && !python) {\n await command('uv', ['venv', '--allow-existing', '--python', '>=3.10', environment]);\n await command('uv', ['pip', 'install', '--python', pythonIn(environment), pinned]);\n } else {\n let selected: { exe: string; args: string[] } | undefined;\n for (const candidate of python ? [{ exe: python, args: [] }] : [{ exe: 'python3', args: [] }, { exe: 'python', args: [] }, { exe: 'py', args: ['-3'] }]) {\n try { await command(candidate.exe, [...candidate.args, '-c', 'import sys; assert sys.version_info >= (3,10)'], true); selected = candidate; break; } catch {}\n }\n if (!selected) throw new Error('Install uv or real Python 3.10+; Windows Store aliases are not a Python runtime.');\n await command(selected.exe, [...selected.args, '-m', 'venv', environment]);\n await command(pythonIn(environment), ['-m', 'pip', 'install', pinned]);\n }\n await command(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true);\n await writeFile(stamp, JSON.stringify({ source: pinned }), 'utf8');\n}\nif (process.argv[1] && resolve(fileURLToPath(import.meta.url)) === resolve(process.argv[1])) {\n if (process.argv[2] !== 'prepare') { console.error('Usage: dsh-crg prepare [engine-source] [--python executable]'); process.exitCode = 2; }\n else {\n const args = process.argv.slice(3);\n const flag = args.indexOf('--python');\n const python = flag >= 0 ? args.splice(flag, 2)[1] : undefined;\n try { await prepare(args[0], python); } catch (error) { console.error(String(error)); process.exitCode = 1; }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\nimport { spawn } from 'node:child_process';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport const environment = join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'code-review-graph', 'engine');\nexport const pythonIn = (dir: string) => join(dir, process.platform === 'win32' ? 'Scripts/python.exe' : 'bin/python');\ninterface Preparation { signal?: AbortSignal; onProgress?: (text: string) => void }\nasync function command(exe: string, args: string[], quiet = false, options: Preparation = {}): Promise<void> {\n options.signal?.throwIfAborted();\n await new Promise<void>((resolve, reject) => {\n let log = '';\n const child = spawn(exe, args, { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, signal: options.signal });\n const capture = (bytes: Buffer) => { const text = bytes.toString(); log = (log + text).slice(-16000); if (!quiet) options.onProgress?.(text); };\n child.stdout.on('data', capture); child.stderr.on('data', capture);\n child.on('error', reject); child.on('close', code => code === 0 ? resolve() : reject(new Error(`${exe} exited ${code}: ${log}`)));\n });\n}\nexport async function prepare(source?: string, python?: string, options: Preparation = {}): Promise<void> {\n options = { ...options, signal: AbortSignal.any([...(options.signal ? [options.signal] : []), AbortSignal.timeout(15 * 60 * 1000)]) };\n options.signal!.throwIfAborted();\n const execute = (exe: string, args: string[], quiet = false) => command(exe, args, quiet, options);\n const engine = JSON.parse(await readFile(new URL('../engine.json', import.meta.url), 'utf8'));\n const pinned = source ?? engine.source;\n const stamp = join(environment, 'dsh-crg-source.json');\n if (await readFile(stamp, 'utf8').then(value => JSON.parse(value).source === pinned, () => false)) {\n try { await execute(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true); options.onProgress?.('CRG engine is already prepared.'); return; } catch { options.signal!.throwIfAborted(); }\n }\n await mkdir(environment, { recursive: true });\n let uv = false;\n try { await execute('uv', ['--version'], true); uv = true; } catch { options.signal!.throwIfAborted(); }\n if (uv && !python) {\n await execute('uv', ['venv', '--allow-existing', '--python', '>=3.10', environment]);\n await execute('uv', ['pip', 'install', '--python', pythonIn(environment), pinned]);\n } else {\n let selected: { exe: string; args: string[] } | undefined;\n for (const candidate of python ? [{ exe: python, args: [] }] : [{ exe: 'python3', args: [] }, { exe: 'python', args: [] }, { exe: 'py', args: ['-3'] }]) {\n try { await execute(candidate.exe, [...candidate.args, '-c', 'import sys; assert sys.version_info >= (3,10)'], true); selected = candidate; break; } catch { options.signal!.throwIfAborted(); }\n }\n if (!selected) throw new Error('Install uv or real Python 3.10+; Windows Store aliases are not a Python runtime.');\n await execute(selected.exe, [...selected.args, '-m', 'venv', environment]);\n await execute(pythonIn(environment), ['-m', 'pip', 'install', pinned]);\n }\n await execute(pythonIn(environment), ['-c', 'from code_review_graph.refactor import get_refactor_edit_plan'], true);\n options.signal!.throwIfAborted();\n await writeFile(stamp, JSON.stringify({ source: pinned }), 'utf8');\n}\nif (process.argv[1] && resolve(fileURLToPath(import.meta.url)) === resolve(process.argv[1])) {\n if (process.argv[2] !== 'prepare') { console.error('Usage: dsh-crg prepare [engine-source] [--python executable]'); process.exitCode = 2; }\n else {\n const args = process.argv.slice(3);\n const flag = args.indexOf('--python');\n const python = flag >= 0 ? args.splice(flag, 2)[1] : undefined;\n try { await prepare(args[0], python, { onProgress: text => process.stdout.write(text.endsWith('\\n') ? text : text + '\\n') }); } catch (error) { console.error(String(error)); process.exitCode = 1; }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["resolve"]
7
7
  }
@@ -0,0 +1,29 @@
1
+ # 0.1.2
2
+
3
+ 交互图谱可以直接操作,无需模型或工具参数:
4
+
5
+ - 右侧代码图谱页新增“准备引擎并生成图谱”和“更新图谱”按钮,首次主动操作自动准备隔离、固定版本的引擎。
6
+ - 新增真正的 DSH 用户命令 `/crg-setup`、`/crg-graph`,不接受参数、不运行模型。
7
+ - 支持取消、重试、解析警告和 HTML 导出;仍沿用当前会话的仓库绑定和已有后端生命周期。
8
+ - 中英文 README 改为界面优先,并解释高级工具选项。
9
+
10
+ 桌面版通过原生插件管理器安装 `dsh-code-review-graph@0.1.2`,启用后在项目会话打开
11
+ 右侧栏 → 新标签页 → 开始 → Code graph,点击“准备引擎并生成图谱”。首次需要联网及
12
+ uv 或真实 Python 3.10+;自定义引擎仍由用户自行准备。正常启动不下载依赖。
13
+
14
+ 安装脚本受 pnpm 执行审批限制,因此准备入口在安装后的首次主动操作中;本版不添加
15
+ 隐藏的 npm `postinstall`。验证范围及发行包证据见 [验证记录](validation.md)。
16
+
17
+ ## English
18
+
19
+ - Generate/update the interactive graph directly from its native sidebar, without a model or JSON parameters.
20
+ - Add native `/crg-setup` and `/crg-graph` user commands. Both execute directly with no arguments.
21
+ - Prepare the isolated pinned engine on the first explicit UI action; retain cancellation, retry, parse warnings, HTML export and session-bound repository ownership.
22
+ - Update both READMEs with UI-first instructions and explanations of advanced options.
23
+
24
+ Install `dsh-code-review-graph@0.1.2` through the native Desktop manager, enable it,
25
+ then open the project session's right sidebar → New tab → Start → Code graph.
26
+ Click **Set up and generate graph**. First preparation needs network access and
27
+ uv or real Python 3.10+. Custom engines remain user-managed; ordinary startup
28
+ does not download dependencies. No hidden npm `postinstall` is added because
29
+ pnpm install scripts require execution approval. See [validation](validation.md).
@@ -1,19 +1,44 @@
1
1
  # Validation / 验证记录
2
2
 
3
+ ## 0.1.2 发行验证
4
+
5
+ 0.1.2 的验证记录作为 [v0.1.2 发行页](https://github.com/sumingwang233/dsh-code-review-graph/releases/tag/v0.1.2)
6
+ 附件保存,包含发行包 SHA-256、GitHub CI 结果和真实 Windows Desktop 证据。
7
+
8
+ - 两版真实 DSH 会话增加原生 `CommandRuntime.execute('/crg-graph')`,调用真实引擎,拒绝额外目录参数。
9
+ - 浏览器测试执行发行 Client,覆盖首次生成按钮、失败、取消、重试及原有图谱交互。
10
+ - 真实 Windows Desktop 0.2.0-rc.2 从空隔离引擎目录开始,通过图谱页按钮准备固定版本引擎,
11
+ 生成图谱,再经真实工作区文件接口读取、搜索和导出。测试不再提前用 CLI 生成图谱。
12
+ - Windows/Linux/macOS × DSH 0.1.5-rc.2、0.2.0-rc.2 的六项 CI 覆盖会话、浏览器、CLI 生命周期及依赖准备。
13
+ - 无真实模型推理;其他 Desktop 平台及版本未整机实测。原安装器超时仍未复现。
14
+
15
+ Release 0.1.2 evidence is attached to its release page, including the exact tarball hash,
16
+ six-job compatibility CI and the actual Windows Desktop run. Native commands run
17
+ the real engine without a model. Desktop setup/generation is driven by the native
18
+ button from an empty isolated engine directory. Browser command services remain
19
+ fixtures; they test the published Client, including failure/cancellation/retry.
20
+
21
+ ## 0.1.1 验证快照 / Previous release snapshot
22
+
3
23
  Local checkpoint: **2026-10-08**, Windows, Node **24.14.1**, Python **3.11.16**.
4
24
  CRG base **2.3.9**; exact contribution engine commit is in `engine.json`.
5
25
  DSH packages are the real published releases **0.1.5-rc.2** and **0.2.0-rc.2**.
6
26
 
7
- Windows 本地验证及 Windows/Linux/macOS 的远程 CI 均已通过。桌面版已检查
8
- 原生插件 ownership 规则及共享 Client 图谱组件,**尚未启动 Electron 应用进行整机实测**。
9
- 这些范围不同,不能把组件测试描述为桌面整机验收。未运行真实模型推理。
27
+ 0.1.1 修复了真实原生加载器才会暴露的两个问题:Client 发行文件必须使用
28
+ `window.__ModuleLoader__.load({ id, factory })`,侧栏正文必须按 provider ID 注册。
29
+ 0.1.0 的浏览器测试重新打包了源文件,并错误地接受了按 kind 注册正文,未发现这两个问题。
30
+ 回归测试现在直接执行发行 Client 文件,并检查 provider ID。
31
+
32
+ Windows 本地增加实际安装的 DSH Desktop **0.2.0-rc.2** 验证;三平台、两版 DSH
33
+ 的 CI 覆盖原生运行时、CLI 和浏览器组件。Desktop 0.1.5-rc.2、Linux/macOS
34
+ 桌面应用尚未整机实测。未运行真实模型推理。
10
35
 
11
36
  ## Results
12
37
 
13
38
  | Check | Local result | Scope |
14
39
  | --- | --- | --- |
15
- | TypeScript and Host/Client build | Passed | Prebuilt ESM Host, CLI, browser Client |
16
- | Plugin safety contracts | 4 passed | Root/linked-directory fences, all 30 tools, both readers, offline iframe, full refactor recovery |
40
+ | TypeScript and Host/Client build | Passed | ESM Host/CLI; native closure-factory browser Client |
41
+ | Plugin safety and native Client contracts | 5 passed | Root/linked-directory fences, all 30 tools, both readers, offline iframe, full refactor recovery; actual published Client executes as a classic script |
17
42
  | Real engine worker lifecycle | 3 passed | Shared root worker, last owner cleanup, resumed owner, cancellation, timeout, missing engine |
18
43
  | DSH 0.1.5-rc.2 session | Passed | 52 recorded deterministic tool calls, including 9 expected refusals |
19
44
  | DSH 0.2.0-rc.2 session | Passed | Same native session and real engine checks |
@@ -24,7 +49,8 @@ Windows 本地验证及 Windows/Linux/macOS 的远程 CI 均已通过。桌面
24
49
  | Ruff for changed Python sources/tests | Passed | All modified Python files |
25
50
  | Windows/Linux/macOS × both DSH releases | 6 CI jobs passed | Real pinned engine, isolated native installation, session calls, browser graph and explicit setup |
26
51
  | Core Windows/Linux/macOS regression matrix | 3 CI jobs passed | 808 passed, 1 platform-specific skip on each OS |
27
- | Electron application launch | Not run | Native shared Client contribution and ownership are covered separately |
52
+ | Windows Desktop 0.2.0-rc.2 | Passed | Actual packaged Electron application, native install/enable/remove/reinstall, graph reading/search/HTML download, unrelated configuration retained; no model |
53
+ | Other Desktop releases/platforms | Not run | Browser/CLI checks do not establish complete Electron coverage |
28
54
  | Real model inference | Not run | Deterministic automation only, no paid inference jobs |
29
55
 
30
56
  The four local core skips comprise three existing symlink checks requiring
@@ -62,10 +88,41 @@ the transcript retains the structured value and omits duplicate rendering;
62
88
  error content is kept. Upstream reviewers decide whether deterministic evidence
63
89
  satisfies their contribution requirement.
64
90
 
65
- The Playwright harness imports the **actual native client contribution** and
66
- mounts its graph in Chromium, using a fixture for each release's workspace asset
67
- reader. It checks native sidebar identity/slot registration. This verifies the
68
- shared Web/Desktop component, not an entire DSH Web server or Electron process.
91
+ The Playwright browser harness executes **`dist/client.js` as published**, through
92
+ the native classic-script factory contract, and mounts its graph in Chromium.
93
+ Only the host services and each release's workspace reader are fixtures. It
94
+ checks provider ID/slot registration. This remains a component test, separate
95
+ from the real Desktop test.
96
+
97
+ ## Desktop regression and reported timeout
98
+
99
+ - [Clean Desktop profile evidence](evidence/desktop-0.2.0-rc.2-win32-clean.json)
100
+ - [Existing dependency combination evidence](evidence/desktop-0.2.0-rc.2-win32-dependency-combination.json)
101
+
102
+ `tests/desktop.mjs` launches the actual installed Electron executable with a
103
+ temporary DSH_HOME, userData, HOME/USERPROFILE and APPDATA. It uses the native
104
+ plugin manager to install the packed tarball, enable it, uninstall it, reinstall
105
+ it and uninstall it again. It checks that existing dependencies, bundles and an
106
+ unrelated user setting survive. The real engine CLI builds a small Python graph;
107
+ the Desktop sidebar reads it through the actual workspace-file service, searches
108
+ it and exports the HTML through Electron's download pipeline. Session creation
109
+ is deterministic, without model inference. This complements the real DSH tool
110
+ session transcripts; it does not claim that the model drove the Desktop UI.
111
+
112
+ The official Desktop Host hardcodes port 19387. A test-only preload changes that
113
+ test process's listener to an OS-assigned port so the user's running Desktop is
114
+ untouched. Test windows stay hidden; the native welcome flow uses “Set up later”
115
+ without signing in, copying credentials or configuring a model key. No test
116
+ settings are written to the user's profile.
117
+
118
+ The reported pnpm log said `Done in 4.1s`, followed by the Host's 600000 ms
119
+ no-output timeout. The same 0.1.0 package completed successfully with bundled
120
+ Electron/pnpm, a clean native Desktop profile, and a native Desktop profile
121
+ containing the three existing plugins and package-manager policy files. The
122
+ latter reproduced the same `+98 -27` dependency change. The original hang has
123
+ **not been reproduced**. 0.1.1 fixes the two independently confirmed Client
124
+ defects and the missing regression coverage; it does not claim to fix that
125
+ unresolved package-manager timeout.
69
126
 
70
127
  ## Reproduction
71
128
 
@@ -90,6 +147,17 @@ installation use the publicly available exact source in `engine.json`.
90
147
  Test profiles use temporary
91
148
  `DSH_HOME` values and never modify the user's DSH profiles or credentials.
92
149
 
150
+ For the separate real Desktop check, first run `npm pack`, set
151
+ `DSH_DESKTOP_EXECUTABLE` to a supported installed Desktop application and
152
+ `CRG_COMMAND` to a prepared real engine, then run `npm run test:desktop`.
153
+ `DSH_VERSION` must match the actual application version (default 0.2.0-rc.2).
154
+ Missing application/engine inputs fail explicitly. To reproduce a dependency
155
+ combination, additionally set `DSH_DESKTOP_PROFILE_FIXTURE` to a profile directory
156
+ and `DSH_DESKTOP_PNPM` to the application's bundled pnpm entry. Only
157
+ `package.json`, `pnpm-lock.yaml` and `pnpm-workspace.yaml` are copied to the
158
+ temporary profile. Evidence is written to `test-results/desktop-*.json` with the
159
+ tested package SHA-256 and native operation results.
160
+
93
161
  Core regression command:
94
162
 
95
163
  ```sh
@@ -101,7 +169,7 @@ Linux and macOS using a real pinned engine, isolated profile lifecycle, browser
101
169
  checks and dependency preparation. The core's `dsh-platform.yml` runs the Python
102
170
  contract/regression set on the same three OS families.
103
171
 
104
- - [Adapter CI: all six combinations passed](https://github.com/sumingwang233/dsh-code-review-graph/actions/runs/37716247823), source `9c478191b743ecc443cc0eede5d67927a367d7ed`.
172
+ - [Historical 0.1.0 adapter CI: six combinations passed](https://github.com/sumingwang233/dsh-code-review-graph/actions/runs/37716247823), source `9c478191b743ecc443cc0eede5d67927a367d7ed`; the old browser harness missed the Client packaging/slot defects described above.
105
173
  - [Core CI: all three OS jobs passed](https://github.com/sumingwang233/code-review-graph/actions/runs/37717599685), source `8ac789138463cd3b8282688bb94d682e90ca1df3`.
106
174
 
107
175
  Each adapter CI artifact contains its native session transcript, browser report,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-code-review-graph",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Local code intelligence, review workflows and interactive graphs for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,7 +8,7 @@
8
8
  "engines": { "node": ">=22.19" },
9
9
  "exports": { ".": "./dist/index.js", "./client": "./dist/client.js", "./package.json": "./package.json" },
10
10
  "bin": { "dsh-crg": "./dist/setup.js" },
11
- "files": ["dist", "cordis.patch.yml", "engine.json", "capabilities.json", "skills", "LICENSE", "NOTICE", "README.md", "README.en.md", "docs/capabilities.md", "docs/validation.md"],
11
+ "files": ["dist", "cordis.patch.yml", "engine.json", "capabilities.json", "skills", "LICENSE", "NOTICE", "README.md", "README.en.md", "docs/capabilities.md", "docs/validation.md", "docs/release-0.1.2.md"],
12
12
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" }, "client": { "platform": "web", "inject": ["@deepseek-ai/dsh-api-workspace-files", "@deepseek-ai/dsh-client-ui-sidebar-right", "@deepseek-ai/dsh-api-remotes"] } },
13
13
  "scripts": {
14
14
  "build": "node scripts/build.mjs",
@@ -16,6 +16,7 @@
16
16
  "test": "node --test tests/*.test.mjs",
17
17
  "test:integration": "node --test tests/integration.mjs",
18
18
  "test:browser": "node --test tests/browser.mjs",
19
+ "test:desktop": "node --test tests/desktop.mjs",
19
20
  "test:install": "node --test tests/install.mjs",
20
21
  "test:setup": "node --test tests/setup.mjs",
21
22
  "test:backend": "node --test tests/backend.mjs",