dsh-diff-approval 0.2.0

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.
@@ -0,0 +1,62 @@
1
+ /** Pending-edit review UI dictionaries. */
2
+ export declare const NS = "diff-approval";
3
+ /** Simplified Chinese pending-edit review messages. */
4
+ export declare const zh: {
5
+ 'panel.title': string;
6
+ 'panel.empty': string;
7
+ 'panel.loading': string;
8
+ 'panel.readFailed': string;
9
+ 'panel.group.current': string;
10
+ 'panel.group.others': string;
11
+ 'panel.aria': string;
12
+ 'panel.stats': string;
13
+ 'panel.selectHint': string;
14
+ 'panel.missing': string;
15
+ 'panel.missingHint': string;
16
+ 'panel.createHint': string;
17
+ 'row.create': string;
18
+ 'action.keep': string;
19
+ 'action.revert': string;
20
+ 'action.busy': string;
21
+ 'action.prevDiff': string;
22
+ 'action.nextDiff': string;
23
+ 'action.copyRange': string;
24
+ 'action.copied': string;
25
+ 'status.kept': string;
26
+ 'status.reverted': string;
27
+ 'status.missing': string;
28
+ };
29
+ /** Translation keys owned by the pending-edit review namespace. */
30
+ export type DiffApprovalKey = keyof typeof zh;
31
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
32
+ interface LocaleNamespaceMap {
33
+ /** Pending-edit review UI copy. */
34
+ 'diff-approval': DiffApprovalKey;
35
+ }
36
+ }
37
+ /** English pending-edit review messages. */
38
+ export declare const en: {
39
+ 'panel.title': string;
40
+ 'panel.empty': string;
41
+ 'panel.loading': string;
42
+ 'panel.readFailed': string;
43
+ 'panel.group.current': string;
44
+ 'panel.group.others': string;
45
+ 'panel.aria': string;
46
+ 'panel.stats': string;
47
+ 'panel.selectHint': string;
48
+ 'panel.missing': string;
49
+ 'panel.missingHint': string;
50
+ 'panel.createHint': string;
51
+ 'row.create': string;
52
+ 'action.keep': string;
53
+ 'action.revert': string;
54
+ 'action.busy': string;
55
+ 'action.prevDiff': string;
56
+ 'action.nextDiff': string;
57
+ 'action.copyRange': string;
58
+ 'action.copied': string;
59
+ 'status.kept': string;
60
+ 'status.reverted': string;
61
+ 'status.missing': string;
62
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Connection-channel port: narrows `ctx.connection.rpc.call` to this
3
+ * package's business verbs and validates the wire values it receives. The
4
+ * host half owns the channel; this module is the browser's one caller.
5
+ * @module dsh-diff-approval/client/port
6
+ */
7
+ import type { ClientConnectionRpc, SessionId } from '@deepseek-ai/dsh-client-connection/client';
8
+ import type { DiffApprovalActionValue, PendingFileDiff } from '../types.ts';
9
+ /** The channel the host half registers and this port calls. */
10
+ export declare const DIFF_APPROVAL_CHANNEL = "/diff-approval";
11
+ /** This package's business verbs over the review channel. */
12
+ export interface DiffApprovalPort {
13
+ /** Read one session's pending entries, oldest capture first. */
14
+ list(sessionId: SessionId): Promise<PendingFileDiff[]>;
15
+ /** Keep one operation. */
16
+ keep(sessionId: SessionId, id: string): Promise<DiffApprovalActionValue>;
17
+ /** Revert one operation. */
18
+ revert(sessionId: SessionId, id: string): Promise<DiffApprovalActionValue>;
19
+ }
20
+ /** Build the port over one generic RPC caller.
21
+ * @param rpc - the connection's channel caller.
22
+ * @returns the typed port.
23
+ */
24
+ export declare function createDiffApprovalPort(rpc: ClientConnectionRpc): DiffApprovalPort;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Reference labels for the selection toolbar: a file name plus a 1-based line
3
+ * range, using the short name when unambiguous and the full path otherwise.
4
+ * Pure derivation so the display rule is unit-testable without the panel.
5
+ * @module dsh-diff-approval/client/reference
6
+ */
7
+ import type { PendingFileDiff } from '../types.ts';
8
+ /**
9
+ * Last path segment of a file path, any separator style.
10
+ * @param path - the path to shorten.
11
+ * @returns the segment after the final separator.
12
+ */
13
+ export declare function basenameOf(path: string): string;
14
+ /**
15
+ * The path shown in a copied reference: the short name when no other listed
16
+ * file shares it, the full path otherwise.
17
+ * @param path - the selected file's path.
18
+ * @param files - every currently listed pending file.
19
+ * @returns the display path for a copied reference.
20
+ */
21
+ export declare function copyDisplayPath(path: string, files: readonly PendingFileDiff[]): string;
22
+ /**
23
+ * Format one line range as a reference suffix: a single line number, or the
24
+ * inclusive range when the selection spans more than one line.
25
+ * @param start - first selected line number.
26
+ * @param end - last selected line number (at least `start`).
27
+ * @returns the range label.
28
+ */
29
+ export declare function lineRangeLabel(start: number, end: number): string;
30
+ /**
31
+ * Build the clipboard text for a selected line range.
32
+ * @param path - the selected file's path.
33
+ * @param files - every currently listed pending file.
34
+ * @param start - first selected line number.
35
+ * @param end - last selected line number.
36
+ * @returns the `path:range` reference text.
37
+ */
38
+ export declare function referenceOf(path: string, files: readonly PendingFileDiff[], start: number, end: number): string;
@@ -0,0 +1,28 @@
1
+ /** The panel's injected business face and its observable snapshot. */
2
+ import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
3
+ import type { SessionId } from '@deepseek-ai/dsh-client-connection/client';
4
+ import type { PendingFileDiff } from '../types.ts';
5
+ /** What the panel reads and drives: the pending list plus in-flight entries. */
6
+ export interface PendingDiffSnapshot {
7
+ /** Whether a list read has completed at least once. */
8
+ read: boolean;
9
+ /** Pending entries, one per file, oldest capture first. */
10
+ files: PendingFileDiff[];
11
+ /** A read failure's message; absent while the latest read succeeded. */
12
+ error?: string;
13
+ /** Entry ids whose keep/revert is in flight; their controls are disabled. */
14
+ busy: ReadonlySet<string>;
15
+ }
16
+ /** The injected face the panel component receives from the plugin body. */
17
+ export interface PendingPanelFace {
18
+ hooks: {
19
+ /** Live pending-diff snapshot for the current page. */
20
+ pending: HostObservable<PendingDiffSnapshot>;
21
+ };
22
+ /** Read the pending list for the current session into the snapshot. */
23
+ onRefresh: (sessionId: SessionId | undefined) => void;
24
+ /** Keep one operation (remove it from the pending list). */
25
+ onKeep: (sessionId: SessionId, id: string) => Promise<void>;
26
+ /** Revert one operation (restore its prior content, or remove a created file). */
27
+ onRevert: (sessionId: SessionId, id: string) => Promise<void>;
28
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Pending-diff observable store: the page's one reading of the host's pending
3
+ * list. Refreshed on panel open, on an interval while the panel stays open,
4
+ * and after each action; a successful action also removes its path locally so
5
+ * the row leaves without waiting for the next poll.
6
+ * @module dsh-diff-approval/client/store
7
+ */
8
+ import type { SessionId } from '@deepseek-ai/dsh-client-connection/client';
9
+ import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
10
+ import type { PendingDiffSnapshot } from './slots.ts';
11
+ import type { DiffApprovalPort } from './port.ts';
12
+ /** The observable the panel reads and the plugin body drives. */
13
+ export interface PendingDiffStore extends HostObservable<PendingDiffSnapshot> {
14
+ /** Re-read one session's pending list (an absent session empties the view). */
15
+ refresh: (sessionId: SessionId | undefined) => Promise<void>;
16
+ /** Keep one operation. */
17
+ keep: (sessionId: SessionId, id: string) => Promise<void>;
18
+ /** Revert one operation. */
19
+ revert: (sessionId: SessionId, id: string) => Promise<void>;
20
+ /** Drop every local fact (used on connection reset). */
21
+ reset: () => void;
22
+ }
23
+ /**
24
+ * Create the store over the review-channel port.
25
+ * @param port - the typed channel port.
26
+ * @returns the observable store.
27
+ */
28
+ export declare function createPendingDiffStore(port: DiffApprovalPort): PendingDiffStore;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Whole-file diff model for the pending review viewer: one unified row list
3
+ * over the complete old and new contents, so the viewer renders the entire
4
+ * file with changed lines marked and unchanged lines as context. Pure
5
+ * derivation; the panel owns rendering. The `diff` package is browser-safe.
6
+ * @module dsh-diff-approval/client/whole-file-diff
7
+ */
8
+ /** One rendered body line of the whole-file view. */
9
+ export interface WholeFileDiffRow {
10
+ /** `context` lines are unchanged, `del`/`add` mark the removed/added sides. */
11
+ kind: 'context' | 'del' | 'add';
12
+ /** The line's text, without the terminating newline. */
13
+ text: string;
14
+ /** 1-based line number on the old side; absent on `add` lines. */
15
+ oldLine: number | undefined;
16
+ /** 1-based line number on the new side; absent on `del` lines. */
17
+ newLine: number | undefined;
18
+ }
19
+ /** The derived view: a flat row list plus the +/- totals. */
20
+ export interface WholeFileDiff {
21
+ /** Body rows in file order; every line of both sides appears once. */
22
+ rows: WholeFileDiffRow[];
23
+ /** Number of removed lines. */
24
+ removed: number;
25
+ /** Number of added lines. */
26
+ added: number;
27
+ }
28
+ /**
29
+ * Compute the whole-file view between two contents. The context budget is the
30
+ * side lengths, so every hunk covers the file and unchanged lines survive as
31
+ * context rows; the `` patch marker is annotation
32
+ * and never becomes a row.
33
+ * @param oldText - the file content before the pending change.
34
+ * @param newText - the file content after the pending change.
35
+ * @returns the complete row list with totals.
36
+ */
37
+ export declare function computeWholeFileDiff(oldText: string, newText: string): WholeFileDiff;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pending-edit review, host half. Captures every successful `edit` and `write`
3
+ * tool result (an unscoped `tools/result` listener receives per-session tool
4
+ * executions because scoped emissions route through the shared root hook
5
+ * table), folds each operation into its file's entry in the
6
+ * {@link PendingDiffStore} (one entry per path), serves the `/diff-approval`
7
+ * connection RPC channel (list/keep/revert), and applies a revert by writing
8
+ * the entry's `oldText` back through `ctx.fs` (a created file's revert
9
+ * removes it, and a tracked file that has since disappeared is restored by
10
+ * its revert).
11
+ *
12
+ * Mount this row in any profile's `cordis.patch.yml`:
13
+ *
14
+ * ```yaml
15
+ * - insert:
16
+ * - id: diff-approval
17
+ * name: 'dsh-diff-approval'
18
+ * # Optional: relocate durable pending state (defaults to
19
+ * # <dshHome>/diff-approval/workspaces).
20
+ * # config:
21
+ * # storageDir: ~/.dsh/diff-approval/workspaces
22
+ * ```
23
+ *
24
+ * Pending entries persist per (workspace, session) so an unhandled operation
25
+ * survives a harness restart; the list endpoint re-reads the live file, so a
26
+ * change or deletion made after the tracked operation is reported after
27
+ * restart exactly as it is mid-session.
28
+ *
29
+ * @module dsh-diff-approval
30
+ */
31
+ import { Context } from '@deepseek-ai/cordis';
32
+ export type { DiffApprovalActionOutcome, DiffApprovalActionValue, DiffApprovalListValue, PendingEntry, PendingEntryKind, PendingFileDiff, } from './types.ts';
33
+ export { PendingDiffStore } from './pending.ts';
34
+ export { PendingPersistence, defaultStorageDir } from './persist.ts';
35
+ /** Stable Cordis plugin name. */
36
+ export declare const name = "diff-approval";
37
+ /** Services required before the review surface activates. */
38
+ export declare const inject: string[];
39
+ /** The connection RPC channel this plugin serves. */
40
+ export declare const DIFF_APPROVAL_CHANNEL = "/diff-approval";
41
+ /**
42
+ * Plugin configuration overridable from the profile's `cordis.patch.yml`.
43
+ */
44
+ export interface DiffApprovalConfig {
45
+ /**
46
+ * Root directory for durable pending state, defaulting to
47
+ * `<dshHome>/diff-approval/workspaces`. Must be a non-empty string when set;
48
+ * `~` prefixes expand to the OS home.
49
+ */
50
+ storageDir?: string;
51
+ }
52
+ /**
53
+ * Mount the pending-edit review surface.
54
+ * @param ctx - Cordis context carrying the filesystem, connection, and workspace registry services.
55
+ * @param config - optional plugin configuration (`storageDir` relocates durable state).
56
+ */
57
+ export declare function apply(ctx: Context, config?: DiffApprovalConfig): void;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * In-memory pending-diff store: one entry per (session, path), holding the
3
+ * file's full set of unhandled changes as one cumulative span. Every later
4
+ * operation to a tracked path folds into its entry — `oldText` stays the
5
+ * earliest basis, `newText` takes the latest content — even when the chain
6
+ * breaks (an outside writer changed the file between operations): the list
7
+ * still shows one element per file. Pure state and transitions; the plugin
8
+ * body owns the `tools/result` observation, the RPC surface, and the
9
+ * filesystem I/O.
10
+ * @module dsh-diff-approval/src/pending
11
+ */
12
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
13
+ import type { PendingEntry } from './types.ts';
14
+ /**
15
+ * The pending-diff store. Keep/Revert decides one whole file at a time.
16
+ */
17
+ export declare class PendingDiffStore {
18
+ private readonly entries;
19
+ private readonly pathIndex;
20
+ /** Merge one operation into the store, keyed by (session, path). */
21
+ private merge;
22
+ /**
23
+ * Fold one captured operation into its file's entry. A no-op (equal before
24
+ * and after) folds nothing.
25
+ * @param entry - the captured operation (id assigned by the caller).
26
+ * @returns whether the stored entry changed.
27
+ */
28
+ fold(entry: PendingEntry): boolean;
29
+ /**
30
+ * Merge persisted entries into the store, one per path after folding. An
31
+ * already-keyed live entry wins over a persisted one: the live entry is
32
+ * newer by construction (it was captured after the persisted state was
33
+ * written), so the path's whole persisted run is skipped.
34
+ * @param sessionId - the session the entries belong to.
35
+ * @param entries - persisted entries, oldest capture first, to fold in.
36
+ */
37
+ hydrate(sessionId: SessionId, entries: readonly PendingEntry[]): void;
38
+ /**
39
+ * Copy the session's entries, oldest capture first.
40
+ * @param sessionId - the session whose entries to list.
41
+ * @returns detached entries in capture order.
42
+ */
43
+ list(sessionId: SessionId): PendingEntry[];
44
+ /**
45
+ * Read one entry without removing it.
46
+ * @param sessionId - the owning session.
47
+ * @param id - the entry id.
48
+ * @returns the entry, or `undefined` when the pair has none.
49
+ */
50
+ get(sessionId: SessionId, id: string): PendingEntry | undefined;
51
+ /**
52
+ * Remove one entry.
53
+ * @param sessionId - the owning session.
54
+ * @param id - the entry id.
55
+ * @returns whether an entry was removed.
56
+ */
57
+ remove(sessionId: SessionId, id: string): boolean;
58
+ /** Total entry count across all sessions. */
59
+ get size(): number;
60
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Durable pending-entry persistence under the harness home. One JSON file per
3
+ * workspace holds every session's entries, at
4
+ * `<storageDir>/<workspaceId>.json`; the default root is
5
+ * `<dshHome>/diff-approval/workspaces` and the plugin's `storageDir` config
6
+ * relocates it. `save` rewrites the whole workspace file so sibling sessions
7
+ * survive; a session with no entries leaves the file, and a workspace with no
8
+ * sessions loses its file. Writes are serialized per file, staged as a
9
+ * sibling temp file, and atomically renamed, so a crash leaves either the old
10
+ * or the new file. Missing files read as empty; corrupt content and unknown
11
+ * versions throw so the caller can fail loud instead of silently dropping
12
+ * persisted data.
13
+ * @module dsh-diff-approval/src/persist
14
+ */
15
+ import type { PendingEntry } from './types.ts';
16
+ /** Default persistence root: this plugin's own directory under the harness home. */
17
+ export declare function defaultStorageDir(): string;
18
+ /**
19
+ * File-backed pending entries keyed by (workspace, session).
20
+ */
21
+ export declare class PendingPersistence {
22
+ private readonly root;
23
+ private readonly tails;
24
+ /**
25
+ * @param root - directory holding one JSON file per workspace.
26
+ */
27
+ constructor(root: string);
28
+ private fileOf;
29
+ /** Read one workspace file; a missing file reads as empty. */
30
+ private readWorkspace;
31
+ /** Stage the envelope as a sibling temp file and atomically rename it into place. */
32
+ private writeWorkspace;
33
+ /**
34
+ * Load one session's entries from its workspace file, oldest capture first.
35
+ * @param workspaceId - the owning workspace's stable id.
36
+ * @param sessionId - the session whose entries to load.
37
+ * @returns the persisted entries; empty when none were saved.
38
+ */
39
+ load(workspaceId: string, sessionId: string): Promise<PendingEntry[]>;
40
+ /**
41
+ * Replace one session's entries durably. Saves to one file are serialized;
42
+ * a previous save's failure does not block the next one.
43
+ * @param workspaceId - the owning workspace's stable id.
44
+ * @param sessionId - the session whose entries to replace.
45
+ * @param entries - the session's complete entry list, possibly empty.
46
+ * @returns resolution after the file is durable.
47
+ */
48
+ save(workspaceId: string, sessionId: string, entries: readonly PendingEntry[]): Promise<void>;
49
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Client-safe wire vocabulary shared by this package's host half and browser
3
+ * half. Type-only and Node-free.
4
+ * @module dsh-diff-approval/types
5
+ */
6
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
7
+ /**
8
+ * One file's pending entry in one session: the complete set of unhandled
9
+ * changes folded into a single cumulative span. `oldText` is the earliest
10
+ * captured basis and `newText` the latest captured content, so Keep/Revert
11
+ * decides the whole file at once.
12
+ */
13
+ export interface PendingEntry {
14
+ /** Stable per-entry id (generated at capture; persisted with the entry). */
15
+ id: string;
16
+ /** The session whose agent ran the operation. */
17
+ sessionId: SessionId;
18
+ /** Backend-resolved display path (the tool's output `path`). */
19
+ path: string;
20
+ /** What the operation did: an in-place change or a file creation. */
21
+ kind: PendingEntryKind;
22
+ /** File content before the operation (empty for a creation). */
23
+ oldText: string;
24
+ /** File content after the operation. */
25
+ newText: string;
26
+ /** Epoch milliseconds of the capture. */
27
+ updatedAt: number;
28
+ }
29
+ /** What one captured operation did to the file. */
30
+ export type PendingEntryKind = 'edit' | 'create';
31
+ /**
32
+ * One listed pending entry: the stored operation plus the live file state the
33
+ * list endpoint computes by reading the file's current content.
34
+ */
35
+ export interface PendingFileDiff extends PendingEntry {
36
+ /**
37
+ * Whether the file no longer exists (or cannot be resolved). Reverting a
38
+ * missing entry restores its old content, which recreates the file.
39
+ */
40
+ missing: boolean;
41
+ /**
42
+ * Whether the file's current content no longer equals the newest tracked
43
+ * content for its path. The cause is not attributed: any writer — another
44
+ * tool, an editor, a second process — may have changed it after the tracked
45
+ * operations. A Revert on a diverged entry overwrites whatever the file now
46
+ * holds.
47
+ */
48
+ diverged: boolean;
49
+ }
50
+ /** Value returned by the channel's list endpoint. */
51
+ export interface DiffApprovalListValue {
52
+ /** Pending entries for the requested session, oldest capture first. */
53
+ files: PendingFileDiff[];
54
+ }
55
+ /** Outcome of one keep/revert request. */
56
+ export type DiffApprovalActionOutcome = 'kept' | 'reverted' | 'missing';
57
+ /** Value returned by the channel's keep and revert endpoints. */
58
+ export interface DiffApprovalActionValue {
59
+ /** What the request did; `missing` means no pending entry existed. */
60
+ outcome: DiffApprovalActionOutcome;
61
+ }
package/package.json ADDED
@@ -0,0 +1,104 @@
1
+ {
2
+ "name": "dsh-diff-approval",
3
+ "version": "0.2.0",
4
+ "description": "DeepSeek Harness plugin: pending-edit review with whole-file diff and Keep/Revert",
5
+ "author": "Wu Zhiwei",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9087/dsh-diff-approval.git"
9
+ },
10
+ "homepage": "https://github.com/9087/dsh-diff-approval#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/9087/dsh-diff-approval/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "lib/index.js",
16
+ "types": "lib/types/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./lib/types/index.d.ts",
20
+ "default": "./lib/index.js"
21
+ },
22
+ "./client": {
23
+ "types": "./lib/types/client/index.d.ts",
24
+ "default": "./lib/client.js"
25
+ },
26
+ "./src/*": "./src/*",
27
+ "./package.json": "./package.json"
28
+ },
29
+ "files": [
30
+ "lib/index.js",
31
+ "lib/client.js",
32
+ "lib/types/**/*.d.ts",
33
+ "cordis.patch.yml"
34
+ ],
35
+ "dsh": {
36
+ "bundle": {
37
+ "patch": "./cordis.patch.yml"
38
+ },
39
+ "client": {
40
+ "inject": [
41
+ "@deepseek-ai/dsh-client-runtime",
42
+ "@deepseek-ai/dsh-client-connection",
43
+ "@deepseek-ai/dsh-client-locale",
44
+ "@deepseek-ai/dsh-client-ui-sidebar"
45
+ ],
46
+ "platform": "web"
47
+ }
48
+ },
49
+ "scripts": {
50
+ "typecheck": "tsc -b tsconfig.json",
51
+ "build": "tsc -b tsconfig.json && tsdown --env.DSH_BUILD_FACE client",
52
+ "test": "vitest run",
53
+ "prepare": "tsc -b tsconfig.json && tsdown --env.DSH_BUILD_FACE client",
54
+ "release": "release-it"
55
+ },
56
+ "license": "MIT",
57
+ "dependencies": {
58
+ "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.5",
59
+ "@shikijs/langs": "^4.4.3",
60
+ "diff": "^9.0.0",
61
+ "shiki": "^4.4.3"
62
+ },
63
+ "peerDependencies": {
64
+ "@deepseek-ai/cordis": ">=4.0.1",
65
+ "@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.5",
66
+ "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.5",
67
+ "@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.5",
68
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.5",
69
+ "@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.0-rc.5",
70
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.5",
71
+ "@deepseek-ai/dsh-fs": ">=0.1.0-rc.5",
72
+ "@deepseek-ai/dsh-host-apiproxy": ">=0.1.0-rc.5",
73
+ "@deepseek-ai/dsh-session": ">=0.1.0-rc.5",
74
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.5",
75
+ "@deepseek-ai/dsh-workspace": ">=0.1.0-rc.5",
76
+ "react": "^18.2.0"
77
+ },
78
+ "devDependencies": {
79
+ "@deepseek-ai/cordis": "^4.0.1",
80
+ "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.5",
81
+ "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.5",
82
+ "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.5",
83
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.5",
84
+ "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.5",
85
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.5",
86
+ "@deepseek-ai/dsh-fs": "^0.1.0-rc.5",
87
+ "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.5",
88
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.5",
89
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.5",
90
+ "@deepseek-ai/dsh-workspace": "^0.1.0-rc.5",
91
+ "@release-it/conventional-changelog": "^12.0.0",
92
+ "@testing-library/react": "^16.1.0",
93
+ "@types/node": "^22.0.0",
94
+ "@types/react": "~18.3.1",
95
+ "jsdom": "^29.1.1",
96
+ "lightningcss": "^1.32.0",
97
+ "react": "^18.2.0",
98
+ "react-dom": "^18.2.0",
99
+ "release-it": "^21.0.2",
100
+ "tsdown": "^0.22.2",
101
+ "typescript": "^6.0.3",
102
+ "vitest": "^4.1.8"
103
+ }
104
+ }