@huanlin/dsh-plugin-merge-tool-calls 0.2.2 → 0.3.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.
@@ -1,13 +1,16 @@
1
1
  /**
2
2
  * Pure card/row derivation from a frozen call slice, mirroring ui-tool's
3
- * tool-call/read-card/search-card/diff-card/terminal-card/web-card models at
4
- * the plugin boundary (those models are ui-tool internals and cannot be
5
- * imported cross-package). Same wire contract, same defensive treatment of
6
- * untrusted result views. A merged row renders the same surface the built-in
7
- * row would: a variant title/icon plus a card primitive or IN/OUT text.
3
+ * meta-based card models (read/search/diff/terminal/web) at the plugin
4
+ * boundary (those models are ui-tool internals and cannot be imported
5
+ * cross-package). Same wire contract, same defensive treatment of untrusted
6
+ * result metadata: cards derive from the call arguments plus the persisted
7
+ * result `meta` and single text block. A merged row renders the same surface
8
+ * the built-in row would: a variant title/icon plus a card primitive or IN/OUT
9
+ * text. The localized label props each primitive now requires are supplied by
10
+ * the render site (`rows.tsx`), not here.
8
11
  * @module
9
12
  */
10
- import { type ToolCallBlock, type ToolResultNode } from '@deepseek-ai/dsh-client-runtime/client';
13
+ import type { ToolCallBlock, ToolResultNode } from '@deepseek-ai/dsh-client-ui-chat/client';
11
14
  import type { DiffBlockProps, ReadBlockProps, SearchBlockProps, TerminalBlockProps, WebBlockProps } from '@deepseek-ai/dsh-client-ui-primitives';
12
15
  import { type ToolVariant } from './tool-names.ts';
13
16
  /** Row state semantic, mirroring ui-tool's ToolRowState. */
@@ -15,29 +18,26 @@ export type RowState = 'running' | 'ok' | 'error' | 'stopped';
15
18
  export type { ToolVariant } from './tool-names.ts';
16
19
  /** Read-card props the ReadBlock primitive draws (per-render maxLines owned by the caller). */
17
20
  export type ReadCardModel = Pick<ReadBlockProps, 'label' | 'lines' | 'totalLines' | 'lang'>;
18
- /**
19
- * Distributive `Omit`: a plain `Omit<A | B, K>` keeps only the keys common to
20
- * both members, dropping the discriminated `files`/`paths` fields. Distributing
21
- * over the naked type parameter preserves each shape.
22
- */
23
21
  type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
22
+ /** Search-card props (the primitive's own union minus the render site's fields). */
23
+ type SearchCardModelProps = DistributiveOmit<SearchBlockProps, 'labels' | 'maxLines' | 'className'>;
24
24
  /** Search-card props plus the capped-result recovery locator (mirrors ui-tool). */
25
25
  export interface SearchCardModel {
26
- readonly card: DistributiveOmit<SearchBlockProps, 'maxLines' | 'className'>;
27
- /** The result view's replacement title, which outranks the args summary. */
28
- readonly title: string | undefined;
26
+ readonly card: SearchCardModelProps;
29
27
  readonly recovery: string | undefined;
30
28
  }
31
- /** Diff-card props (mirrors ui-tool; maxLines/className belong to the render site). */
29
+ /** Diff-card props (mirrors ui-tool; maxLines/labels/className belong to the render site). */
32
30
  export interface DiffCardModel {
33
31
  readonly card: Pick<DiffBlockProps, 'diffs'>;
34
32
  }
35
- /** Terminal-card props (mirrors ui-tool; maxLines/className/labels belong to the render site). */
33
+ /** Terminal-card props (mirrors ui-tool; maxLines/labels/className belong to the render site). */
36
34
  export interface TerminalCardModel {
37
35
  readonly card: Pick<TerminalBlockProps, 'command' | 'cwd' | 'output' | 'exitCode' | 'signal' | 'running'>;
38
- /** The call view's model-authored description shown above the card. */
36
+ /** The call's model-authored description shown above the card. */
39
37
  readonly description: string | undefined;
40
38
  }
39
+ /** Web-card props (the primitive's own union minus the render site's fields). */
40
+ export type WebCardModel = DistributiveOmit<WebBlockProps, 'labels' | 'className'>;
41
41
  /** True when a settled terminal card reports a failing exit (mirrors ui-tool). */
42
42
  export declare function terminalFailed(model: TerminalCardModel): boolean;
43
43
  /** Everything a merged row needs, derived once from the frozen slice. */
@@ -63,7 +63,7 @@ export interface CallRowModel {
63
63
  readonly diff: DiffCardModel | null;
64
64
  readonly read: ReadCardModel | null;
65
65
  readonly search: SearchCardModel | null;
66
- readonly web: WebBlockProps | null;
66
+ readonly web: WebCardModel | null;
67
67
  }
68
68
  /**
69
69
  * Flatten a settled result's content blocks to display text.
@@ -74,4 +74,4 @@ export declare function resultText(node: ToolResultNode): string;
74
74
  /** Strip the workspace root from a workspace-rooted absolute path (display only). */
75
75
  export declare function relativizeToCwd(text: string, cwd: string | undefined): string;
76
76
  /** Derive the row model for one call of a grouped tool. */
77
- export declare function callRowModel(toolName: string, block: ToolCallBlock, cwd: string | undefined): CallRowModel;
77
+ export declare function callRowModel(toolName: string, block: ToolCallBlock, cwd: string | undefined, home: string | undefined): CallRowModel;
@@ -1,9 +1,16 @@
1
1
  /**
2
2
  * The 19 better-locale override languages for the merged tool-call row copy,
3
- * keyed by language id. Each dictionary carries the same key set as `en`/`zh`
4
- * in `./locales.ts` (enforced by the `Record<MergeToolCallsKey, string>`
5
- * annotation); values keep `{placeholder}` interpolation (e.g. `{n}` in
6
- * `mergedCount`), matching the better-locale store's `LocaleDict` contract.
3
+ * keyed by language id. Values keep `{placeholder}` interpolation (e.g. `{n}`
4
+ * in `mergedCount`), matching the better-locale store's `LocaleDict`
5
+ * contract.
6
+ *
7
+ * Each dictionary is PARTIAL: languages carry the keys they translate, and a
8
+ * missing key falls through the locale lookup chain to the base `en`/`zh`
9
+ * dictionary registered by the plugin. Dictionaries written before the
10
+ * v0.1.2-alpha.1 adaptation predate the read/search/diff/web card-label keys
11
+ * (`read.*` / `search.*` / `diff.*` / `web.*` / `markdown.*` / `copy` /
12
+ * `copied`); those render in English under an override language until a
13
+ * translation lands here.
7
14
  *
8
15
  * The apply function registers these into `ctx.betterLocale` (the override
9
16
  * store) under `NS`, so when the user selects an override language through
@@ -12,4 +19,4 @@
12
19
  */
13
20
  import type { MergeToolCallsKey } from './locales.ts';
14
21
  /** All override-language dictionaries for the `NS` namespace. */
15
- export declare const dicts: Record<string, Record<MergeToolCallsKey, string>>;
22
+ export declare const dicts: Record<string, Partial<Record<MergeToolCallsKey, string>>>;
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @module @dsh-external/dsh-plugin-merge-tool-calls/client
12
12
  */
13
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
13
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
14
14
  import { type MergeToolCallsConfig } from '../types.ts';
15
15
  import { type MergeToolCallsKey } from './locales.ts';
16
16
  declare module '@deepseek-ai/dsh-client-ui-slots' {
@@ -13,6 +13,8 @@ export declare const zh: {
13
13
  countCommands: string;
14
14
  countPrograms: string;
15
15
  countCalls: string;
16
+ copy: string;
17
+ copied: string;
16
18
  'terminal.signal': string;
17
19
  'terminal.exitCode': string;
18
20
  'terminal.running': string;
@@ -25,6 +27,27 @@ export declare const zh: {
25
27
  'terminal.collapse': string;
26
28
  'terminal.expandAria': string;
27
29
  'terminal.expandRest': string;
30
+ 'read.window': string;
31
+ 'read.collapseAria': string;
32
+ 'read.expandAria': string;
33
+ 'read.expandRest': string;
34
+ 'search.paths': string;
35
+ 'search.paths.truncated': string;
36
+ 'search.matches': string;
37
+ 'search.matches.truncated': string;
38
+ 'search.noResults': string;
39
+ 'search.collapseAria': string;
40
+ 'search.expandAria': string;
41
+ 'search.expandRest': string;
42
+ 'diff.collapseAria': string;
43
+ 'diff.expandAria': string;
44
+ 'diff.expandRest': string;
45
+ 'diff.files': string;
46
+ 'web.noResults': string;
47
+ 'web.sourcesTruncated': string;
48
+ 'web.http': string;
49
+ 'web.contentTruncated': string;
50
+ 'markdown.footnotes': string;
28
51
  };
29
52
  export type MergeToolCallsKey = keyof typeof zh;
30
53
  export declare const en: {
@@ -41,6 +64,8 @@ export declare const en: {
41
64
  countCommands: string;
42
65
  countPrograms: string;
43
66
  countCalls: string;
67
+ copy: string;
68
+ copied: string;
44
69
  'terminal.signal': string;
45
70
  'terminal.exitCode': string;
46
71
  'terminal.running': string;
@@ -53,5 +78,26 @@ export declare const en: {
53
78
  'terminal.collapse': string;
54
79
  'terminal.expandAria': string;
55
80
  'terminal.expandRest': string;
81
+ 'read.window': string;
82
+ 'read.collapseAria': string;
83
+ 'read.expandAria': string;
84
+ 'read.expandRest': string;
85
+ 'search.paths': string;
86
+ 'search.paths.truncated': string;
87
+ 'search.matches': string;
88
+ 'search.matches.truncated': string;
89
+ 'search.noResults': string;
90
+ 'search.collapseAria': string;
91
+ 'search.expandAria': string;
92
+ 'search.expandRest': string;
93
+ 'diff.collapseAria': string;
94
+ 'diff.expandAria': string;
95
+ 'diff.expandRest': string;
96
+ 'diff.files': string;
97
+ 'web.noResults': string;
98
+ 'web.sourcesTruncated': string;
99
+ 'web.http': string;
100
+ 'web.contentTruncated': string;
101
+ 'markdown.footnotes': string;
56
102
  };
57
103
  export declare const NS = "merge-tool-calls";
@@ -6,7 +6,7 @@
6
6
  * display is deterministic under replay: the web layer recomputes it per frame.
7
7
  * @module
8
8
  */
9
- import type { ChatNodeStore, ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client';
9
+ import type { ChatNodeStore, ToolCallBlock } from '@deepseek-ai/dsh-client-ui-chat/client';
10
10
  import type { MergeGroupMode } from '../types.ts';
11
11
  /** The wire tool name of a call in either lifecycle form (mirrors ui-tool). */
12
12
  export declare function callNameOf(block: ToolCallBlock): string;
@@ -23,7 +23,10 @@ export interface ReadRun {
23
23
  * Compute the merged group this call belongs to.
24
24
  *
25
25
  * 1. Locates this call's node in the chat order; null when it is not a chat
26
- * tool-call node (e.g. a read dispatched as a subcall).
26
+ * tool-call node (e.g. a read dispatched as a subcall). The node key
27
+ * format stays a ui-conversation internal, so the seat finds itself by
28
+ * scanning the store for the tool-call node owning its call id instead of
29
+ * recomputing the key.
27
30
  * 2. Walks backward/forward to the maximal consecutive run containing it. A
28
31
  * call continues the run when it is a grouped tool AND same-tool-same-run:
29
32
  * the identical wire name, or a sibling of the same known variant family
@@ -9,14 +9,16 @@
9
9
  * falls back to a plain single row so the call never disappears.
10
10
  *
11
11
  * The row surface mirrors the built-in generic ToolRow: a variant title/icon
12
- * plus the settled card (read/search/diff/terminal/web) or IN/OUT text.
12
+ * plus the settled card (read/search/diff/terminal/web) or IN/OUT text. The
13
+ * card primitives' localized label props are built here from the plugin's own
14
+ * dictionary (the primitives are cordis-free and require complete labels).
13
15
  *
14
16
  * Everything here is a pure function of the chat snapshot + the frozen call
15
17
  * slices (replay-deterministic); expand state is component-local view state.
16
18
  * @module
17
19
  */
18
20
  import { type ReactNode } from 'react';
19
- import type { ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client';
21
+ import type { ToolCallBlock } from '@deepseek-ai/dsh-client-ui-chat/client';
20
22
  import type { ToolCallViewProps } from '@deepseek-ai/dsh-client-ui-tool/client';
21
23
  import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
22
24
  import type { MergeToolCallsConfig } from '../types.ts';
@@ -36,6 +38,7 @@ export declare const RowCard: import("react").NamedExoticComponent<{
36
38
  toolName: string;
37
39
  block: ToolCallBlock;
38
40
  cwd: string | undefined;
41
+ home: string | undefined;
39
42
  openFile: (path: string) => void;
40
43
  inspect: (() => void) | undefined;
41
44
  t: MergedToolRowProps["t"];
@@ -55,6 +58,7 @@ export declare const ChildRow: import("react").NamedExoticComponent<{
55
58
  toolName: string;
56
59
  block: ToolCallBlock;
57
60
  cwd: string | undefined;
61
+ home: string | undefined;
58
62
  openFile: (path: string) => void;
59
63
  t: MergedToolRowProps["t"];
60
64
  }>;
@@ -70,4 +74,4 @@ export declare const ChildRow: import("react").NamedExoticComponent<{
70
74
  * and indents the children so their dots and paths land on the main row's
71
75
  * columns — no font/title constants to keep in sync.
72
76
  */
73
- export declare function MergedToolRow({ callId, toolName, block, cwd, openFile, inspect, t, cfg, useSession }: MergedToolRowProps): import("react").JSX.Element | null;
77
+ export declare function MergedToolRow({ callId, toolName, block, cwd, home, openFile, inspect, t, cfg, useChat }: MergedToolRowProps): import("react").JSX.Element | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huanlin/dsh-plugin-merge-tool-calls",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -17,10 +17,6 @@
17
17
  "types": "./lib/types/index.d.ts",
18
18
  "import": "./lib/index.js"
19
19
  },
20
- "./invariant": {
21
- "types": "./lib/types/invariant.d.ts",
22
- "import": "./lib/invariant.js"
23
- },
24
20
  "./client": {
25
21
  "types": "./lib/types/client/index.d.ts",
26
22
  "default": "./lib/client.js"
@@ -38,9 +34,10 @@
38
34
  },
39
35
  "client": {
40
36
  "inject": [
41
- "@deepseek-ai/dsh-client-runtime",
42
37
  "@deepseek-ai/dsh-client-locale",
38
+ "@deepseek-ai/dsh-client-ui-renderer",
43
39
  "@deepseek-ai/dsh-client-ui-tool",
40
+ "@deepseek-ai/dsh-client-ui-chat",
44
41
  "@deepseek-ai/dsh-client-ui-slots",
45
42
  "@deepseek-ai/dsh-client-ui-primitives"
46
43
  ],
@@ -48,17 +45,18 @@
48
45
  }
49
46
  },
50
47
  "peerDependencies": {
51
- "cordis": "^4.0.0-rc.7",
48
+ "@deepseek-ai/cordis": "^4.0.1",
52
49
  "react": "^18.2.0",
53
50
  "schemastery": "^3.18.0",
54
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
55
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
56
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
57
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
58
- "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6"
51
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
52
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-rc.1",
53
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
54
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-rc.1",
55
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
56
+ "@deepseek-ai/dsh-client-ui-tool": "^0.1.2-rc.1"
59
57
  },
60
58
  "peerDependenciesMeta": {
61
- "cordis": {
59
+ "@deepseek-ai/cordis": {
62
60
  "optional": true
63
61
  },
64
62
  "react": {
@@ -70,12 +68,15 @@
70
68
  "@deepseek-ai/dsh-client-locale": {
71
69
  "optional": true
72
70
  },
73
- "@deepseek-ai/dsh-client-runtime": {
71
+ "@deepseek-ai/dsh-client-ui-chat": {
74
72
  "optional": true
75
73
  },
76
74
  "@deepseek-ai/dsh-client-ui-primitives": {
77
75
  "optional": true
78
76
  },
77
+ "@deepseek-ai/dsh-client-ui-renderer": {
78
+ "optional": true
79
+ },
79
80
  "@deepseek-ai/dsh-client-ui-slots": {
80
81
  "optional": true
81
82
  },
@@ -84,17 +85,9 @@
84
85
  }
85
86
  },
86
87
  "devDependencies": {
87
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
88
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
89
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6",
90
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
91
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
92
- "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6",
93
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
94
88
  "@deepseek-ai/schemastery": "^3.18.1",
95
89
  "@types/node": "^22.20.1",
96
90
  "@types/react": "~18.3.31",
97
- "cordis": "^4.0.0-rc.7",
98
91
  "jsdom": "^26.0.0",
99
92
  "react": "^18.2.0",
100
93
  "react-dom": "^18.2.0",
package/lib/invariant.js DELETED
@@ -1,11 +0,0 @@
1
- //#region src/invariant.ts
2
- const PACKAGE_NAME = "@huanlin/dsh-plugin-merge-tool-calls";
3
- const name = "merge-tool-calls-invariant";
4
- const inject = ["invariants"];
5
- /** No runtime invariant: this package contributes client-only slot entries. */
6
- const install = () => {};
7
- /** Register package ownership with the invariant service. */
8
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
9
-
10
- //#endregion
11
- export { apply, inject, name };
@@ -1,12 +0,0 @@
1
- /** Package invariant companion for dsh-plugin-merge-tool-calls. */
2
- import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants';
3
- export declare const name = "merge-tool-calls-invariant";
4
- export declare const inject: string[];
5
- interface InvariantContext {
6
- invariants: {
7
- register: (name: string, installer: InvariantInstaller) => () => void;
8
- };
9
- }
10
- /** Register package ownership with the invariant service. */
11
- export declare const apply: (ctx: InvariantContext) => Promise<() => void>;
12
- export {};