@deepseek-harness-tui/dsh-tui 0.8.7 → 0.8.8

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.
Files changed (37) hide show
  1. package/README.md +2 -2
  2. package/bin/dsh-tui.js +1 -1
  3. package/lib/types/components/FileSuggestions.d.ts +8 -4
  4. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  5. package/lib/types/components/FileSuggestions.js +22 -12
  6. package/lib/types/components/LogoV2.d.ts +5 -1
  7. package/lib/types/components/LogoV2.d.ts.map +1 -1
  8. package/lib/types/components/LogoV2.js +12 -3
  9. package/lib/types/components/PromptInput.d.ts.map +1 -1
  10. package/lib/types/components/PromptInput.js +25 -21
  11. package/lib/types/dsh-adapter/channel.d.ts +11 -1
  12. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  13. package/lib/types/dsh-adapter/channel.js +100 -37
  14. package/lib/types/dsh-adapter/contract.d.ts +58 -18
  15. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  16. package/lib/types/dsh-adapter/contract.js +124 -36
  17. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  18. package/lib/types/dsh-adapter/index.js +6 -12
  19. package/lib/types/i18n.d.ts +18 -1
  20. package/lib/types/i18n.d.ts.map +1 -1
  21. package/lib/types/i18n.js +22 -2
  22. package/lib/types/ink/ink.d.ts.map +1 -1
  23. package/lib/types/ink/ink.js +38 -23
  24. package/lib/types/ink/render-node-to-output.d.ts +6 -3
  25. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  26. package/lib/types/ink/render-node-to-output.js +33 -7
  27. package/lib/types/ink/selection.d.ts +29 -4
  28. package/lib/types/ink/selection.d.ts.map +1 -1
  29. package/lib/types/ink/selection.js +41 -5
  30. package/lib/types/tips.d.ts.map +1 -1
  31. package/lib/types/tips.js +22 -4
  32. package/lib/types/utils/fileSuggestions.d.ts +19 -0
  33. package/lib/types/utils/fileSuggestions.d.ts.map +1 -0
  34. package/lib/types/utils/fileSuggestions.js +40 -0
  35. package/lib/types/utils/mentions.d.ts.map +1 -1
  36. package/lib/types/utils/mentions.js +3 -1
  37. package/package.json +67 -66
@@ -1,14 +1,18 @@
1
1
  /** Primary validated upstream line (newest). */
2
- export declare const UPSTREAM_VALIDATED_VERSION = "0.1.0-rc.8";
3
- /** Every upstream rc line the adapter has been validated against.
2
+ export declare const UPSTREAM_VALIDATED_VERSION = "0.1.1-rc.2";
3
+ /**
4
+ * Every upstream prerelease line the adapter has been validated against,
5
+ * oldest first.
4
6
  *
5
- * rc.8 = primary; rc.7 = previous line (full CI coverage); rc.6 = legacy
6
- * line (install- and type-level compatibility, feature surface may lack
7
- * rc.7/rc.8 additions — new features must degrade gracefully there).
7
+ * 0.1.1-rc.2 = primary; 0.1.1-rc.1 = transitional line of the same family
8
+ * (install- and type-level compatibility); 0.1.0-rc.8 = previous family
9
+ * (full CI coverage); 0.1.0-rc.7 = full CI coverage as well; 0.1.0-rc.6 =
10
+ * legacy line (install- and type-level compatibility, feature surface may
11
+ * lack later additions — new features must degrade gracefully there).
8
12
  * The peer range in package.json is deliberately wider than this list: an
9
- * install on an older line is allowed but reports drift at boot.
13
+ * install on an older or newer line is allowed but reports drift at boot.
10
14
  */
11
- export declare const UPSTREAM_VALIDATED_RC_LINES: readonly [6, 7, 8];
15
+ export declare const UPSTREAM_VALIDATED_VERSIONS: readonly ["0.1.0-rc.6", "0.1.0-rc.7", "0.1.0-rc.8", "0.1.1-rc.1", "0.1.1-rc.2"];
12
16
  /**
13
17
  * Framework packages version on their own lines; the contract validates
14
18
  * their MAJOR (breaking surface), not the harness rc number.
@@ -21,23 +25,59 @@ export interface UpstreamDriftEntry {
21
25
  installed: string | undefined;
22
26
  validated: string;
23
27
  }
24
- /** Human-readable summary of the validated lines, e.g. `0.1.0-rc.8 (rc.6/rc.7/rc.8)`. */
28
+ /** A parsed upstream prerelease version, e.g. `0.1.1-rc.2` → `[0, 1, 1, 2]`. */
29
+ export type UpstreamVersionTuple = readonly [number, number, number, number];
30
+ /** Parse an upstream prerelease version; undefined when unparseable. */
31
+ export declare function parseUpstreamVersion(version: string | undefined): UpstreamVersionTuple | undefined;
32
+ /** Human-readable summary of the validated lines, e.g. `0.1.1-rc.2 (0.1.0-rc.6/7/8, 0.1.1-rc.1/2)`. */
25
33
  export declare const UPSTREAM_VALIDATED_LABEL: string;
26
34
  export declare function installedUpstreamVersions(): Record<string, string | undefined>;
27
- /** The installed upstream rc line of one blessed package (undefined when
28
- * missing or not on the 0.1.0-rc line). Feature gates compare this against
29
- * the line a behavior was introduced on, so the adapter degrades on older
30
- * installs instead of calling APIs they do not have. */
31
- export declare function installedLineOf(packageName: string): number | undefined;
32
- /** The distinct upstream rc lines installed across the blessed harness
33
- * packages (framework packages excluded). One line = coherent install;
34
- * several = a mixed tree, which the per-package drift check cannot see.
35
- * Empty when nothing (or no harness package) is installed. */
36
- export declare function installedUpstreamLines(): number[];
35
+ /**
36
+ * The installed upstream version of one blessed package, parsed; undefined
37
+ * when missing or not on an `x.y.z-rc.n` prerelease line. Feature gates
38
+ * compare this against the line a behavior was introduced on, so the
39
+ * adapter degrades on older installs instead of calling APIs they do not
40
+ * have.
41
+ */
42
+ export declare function installedUpstreamVersion(packageName: string): UpstreamVersionTuple | undefined;
43
+ /**
44
+ * Whether the installed version of `packageName` is at or beyond `minimum`
45
+ * (a literal like `'0.1.0-rc.8'`). Unparseable or older installs return
46
+ * false so features introduced on the minimum line degrade gracefully.
47
+ */
48
+ export declare function installedMeetsVersion(packageName: string, minimum: string): boolean;
49
+ /**
50
+ * The distinct installed prerelease versions across the blessed harness
51
+ * packages (framework packages excluded). One entry = coherent install;
52
+ * several = a mixed tree, which the per-package drift check cannot see.
53
+ * Empty when nothing (or no harness package) is installed.
54
+ */
55
+ export declare function installedUpstreamLines(): string[];
37
56
  /**
38
57
  * Report every blessed package whose installed version is NOT one of the
39
58
  * validated release lines. Empty array = the running install matches the
40
59
  * contract.
41
60
  */
42
61
  export declare function upstreamDrift(): UpstreamDriftEntry[];
62
+ /**
63
+ * Classification of a drifted install for the one-line boot notice:
64
+ * `newer` / `older` — every drifted harness package sits on a single
65
+ * parseable version off one end of the validated window; `mixed` — several
66
+ * distinct versions coexist (unstable tree); `broken` — something is
67
+ * missing or unparseable and wording cannot get more specific.
68
+ */
69
+ export type UpstreamDriftKind = 'newer' | 'older' | 'mixed' | 'broken';
70
+ /** Merged drift verdict consumed by the logo header notice (LogoV2). */
71
+ export interface UpstreamDriftSummary {
72
+ kind: UpstreamDriftKind;
73
+ /** Distinct installed versions among drifted packages ('missing' for absent ones). */
74
+ versions: string[];
75
+ }
76
+ /**
77
+ * Collapse {@link upstreamDrift} into a single summary for the boot notice:
78
+ * undefined when the install matches the contract. Only harness rc packages
79
+ * decide newer/older/mixed; a framework-only drift (e.g. a cordis major
80
+ * bump) reports `broken`, since its version line is not comparable.
81
+ */
82
+ export declare function upstreamDriftSummary(): UpstreamDriftSummary | undefined;
43
83
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/contract.ts"],"names":[],"mappings":"AAgBA,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,eAAe,CAAA;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,oBAAqB,CAAA;AAE7D;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG5D,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,2zBA2B5B,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,yFAAyF;AACzF,eAAO,MAAM,wBAAwB,QAAmG,CAAA;AAYxI,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAqB9E;AAED;;;yDAGyD;AACzD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAOD;;;+DAG+D;AAC/D,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,kBAAkB,EAAE,CAuBpD"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/contract.ts"],"names":[],"mappings":"AAiBA,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,eAAe,CAAA;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,iFAM9B,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG5D,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,2zBA2B5B,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,gFAAgF;AAChF,MAAM,MAAM,oBAAoB,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE5E,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAGlG;AA4BD,uGAAuG;AACvG,eAAO,MAAM,wBAAwB,QAA6D,CAAA;AAYlG,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAqB9E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE9F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,kBAAkB,EAAE,CAuBpD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtE,wEAAwE;AACxE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAA;IACvB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,GAAG,SAAS,CAuBvE"}
@@ -1,29 +1,40 @@
1
1
  /**
2
2
  * Upstream compatibility contract.
3
3
  *
4
- * The TUI is validated against a set of upstream release lines — the
5
- * current primary (0.1.0-rc.8) plus older lines kept in backward
6
- * compatibility (0.1.0-rc.7, 0.1.0-rc.6). Every official package this
7
- * adapter touches is blessed here; anything else must go through upstream
8
- * channels or the adapter, never the UI.
4
+ * The TUI is validated against a set of upstream prerelease lines — the
5
+ * current primary (0.1.1-rc.2) plus older lines kept in backward
6
+ * compatibility across the 0.1.1 and 0.1.0 release families. Every official
7
+ * package this adapter touches is blessed here; anything else must go
8
+ * through upstream channels or the adapter, never the UI.
9
9
  *
10
- * `upstreamDrift()` powers both the boot-time warning (dev visibility) and
11
- * the CI gate (scripts/verify-upstream-contract.ts) so a mismatched
12
- * install fails in CI before it fails on a user's machine.
10
+ * `upstreamDrift()` powers the CI gate (scripts/verify-upstream-contract.ts)
11
+ * so a mismatched install fails in CI before it fails on a user's machine.
12
+ * `upstreamDriftSummary()` collapses the per-package entries into the
13
+ * single natural-language boot notice the logo header shows (see LogoV2).
13
14
  */
14
15
  import { readFileSync } from 'node:fs';
15
16
  import { fileURLToPath } from 'node:url';
16
17
  /** Primary validated upstream line (newest). */
17
- export const UPSTREAM_VALIDATED_VERSION = '0.1.0-rc.8';
18
- /** Every upstream rc line the adapter has been validated against.
18
+ export const UPSTREAM_VALIDATED_VERSION = '0.1.1-rc.2';
19
+ /**
20
+ * Every upstream prerelease line the adapter has been validated against,
21
+ * oldest first.
19
22
  *
20
- * rc.8 = primary; rc.7 = previous line (full CI coverage); rc.6 = legacy
21
- * line (install- and type-level compatibility, feature surface may lack
22
- * rc.7/rc.8 additions — new features must degrade gracefully there).
23
+ * 0.1.1-rc.2 = primary; 0.1.1-rc.1 = transitional line of the same family
24
+ * (install- and type-level compatibility); 0.1.0-rc.8 = previous family
25
+ * (full CI coverage); 0.1.0-rc.7 = full CI coverage as well; 0.1.0-rc.6 =
26
+ * legacy line (install- and type-level compatibility, feature surface may
27
+ * lack later additions — new features must degrade gracefully there).
23
28
  * The peer range in package.json is deliberately wider than this list: an
24
- * install on an older line is allowed but reports drift at boot.
29
+ * install on an older or newer line is allowed but reports drift at boot.
25
30
  */
26
- export const UPSTREAM_VALIDATED_RC_LINES = [6, 7, 8];
31
+ export const UPSTREAM_VALIDATED_VERSIONS = [
32
+ '0.1.0-rc.6',
33
+ '0.1.0-rc.7',
34
+ '0.1.0-rc.8',
35
+ '0.1.1-rc.1',
36
+ '0.1.1-rc.2',
37
+ ];
27
38
  /**
28
39
  * Framework packages version on their own lines; the contract validates
29
40
  * their MAJOR (breaking surface), not the harness rc number.
@@ -61,8 +72,39 @@ export const UPSTREAM_BLESSED_PACKAGES = [
61
72
  '@deepseek-ai/dsh-user-approval',
62
73
  '@deepseek-ai/dsh-user-questions',
63
74
  ];
64
- /** Human-readable summary of the validated lines, e.g. `0.1.0-rc.8 (rc.6/rc.7/rc.8)`. */
65
- export const UPSTREAM_VALIDATED_LABEL = `${UPSTREAM_VALIDATED_VERSION} (${UPSTREAM_VALIDATED_RC_LINES.map((n) => `rc.${n}`).join('/')})`;
75
+ /** Parse an upstream prerelease version; undefined when unparseable. */
76
+ export function parseUpstreamVersion(version) {
77
+ const match = /^(\d+)\.(\d+)\.(\d+)-rc\.(\d+)$/u.exec(version ?? '');
78
+ return match === null ? undefined : [Number(match[1]), Number(match[2]), Number(match[3]), Number(match[4])];
79
+ }
80
+ /** Order two parsed versions: negative/positive/zero as a `<`/`>`/`=`. */
81
+ function compareVersions(a, b) {
82
+ for (let i = 0; i < a.length; i++) {
83
+ if (a[i] > b[i])
84
+ return 1;
85
+ if (a[i] < b[i])
86
+ return -1;
87
+ }
88
+ return 0;
89
+ }
90
+ /** Collapse {@link UPSTREAM_VALIDATED_VERSIONS} into per-release rc groups,
91
+ * e.g. `0.1.0-rc.6/7/8, 0.1.1-rc.1/2`. */
92
+ function validatedLinesLabel() {
93
+ const groups = [];
94
+ for (const version of UPSTREAM_VALIDATED_VERSIONS) {
95
+ const [major, minor, patch, rc] = parseUpstreamVersion(version);
96
+ const release = `${major}.${minor}.${patch}`;
97
+ let group = groups.find(candidate => candidate.release === release);
98
+ if (group === undefined) {
99
+ group = { release, rcs: [] };
100
+ groups.push(group);
101
+ }
102
+ group.rcs.push(rc);
103
+ }
104
+ return groups.map(({ release, rcs }) => `${release}-rc.${rcs.join('/')}`).join(', ');
105
+ }
106
+ /** Human-readable summary of the validated lines, e.g. `0.1.1-rc.2 (0.1.0-rc.6/7/8, 0.1.1-rc.1/2)`. */
107
+ export const UPSTREAM_VALIDATED_LABEL = `${UPSTREAM_VALIDATED_VERSION} (${validatedLinesLabel()})`;
66
108
  function resolvePackageJson(packageName) {
67
109
  try {
68
110
  const path = import.meta.resolve(`${packageName}/package.json`);
@@ -97,31 +139,44 @@ export function installedUpstreamVersions() {
97
139
  cachedVersions = Object.freeze(result);
98
140
  return cachedVersions;
99
141
  }
100
- /** The installed upstream rc line of one blessed package (undefined when
101
- * missing or not on the 0.1.0-rc line). Feature gates compare this against
102
- * the line a behavior was introduced on, so the adapter degrades on older
103
- * installs instead of calling APIs they do not have. */
104
- export function installedLineOf(packageName) {
105
- return rcNumber(installedUpstreamVersions()[packageName]);
142
+ /**
143
+ * The installed upstream version of one blessed package, parsed; undefined
144
+ * when missing or not on an `x.y.z-rc.n` prerelease line. Feature gates
145
+ * compare this against the line a behavior was introduced on, so the
146
+ * adapter degrades on older installs instead of calling APIs they do not
147
+ * have.
148
+ */
149
+ export function installedUpstreamVersion(packageName) {
150
+ return parseUpstreamVersion(installedUpstreamVersions()[packageName]);
106
151
  }
107
- function rcNumber(version) {
108
- const match = /^0\.1\.0-rc\.(\d+)$/u.exec(version ?? '');
109
- return match === null ? undefined : Number(match[1]);
152
+ /**
153
+ * Whether the installed version of `packageName` is at or beyond `minimum`
154
+ * (a literal like `'0.1.0-rc.8'`). Unparseable or older installs return
155
+ * false so features introduced on the minimum line degrade gracefully.
156
+ */
157
+ export function installedMeetsVersion(packageName, minimum) {
158
+ const installed = installedUpstreamVersion(packageName);
159
+ const floor = parseUpstreamVersion(minimum);
160
+ if (installed === undefined || floor === undefined)
161
+ return false;
162
+ return compareVersions(installed, floor) >= 0;
110
163
  }
111
- /** The distinct upstream rc lines installed across the blessed harness
112
- * packages (framework packages excluded). One line = coherent install;
113
- * several = a mixed tree, which the per-package drift check cannot see.
114
- * Empty when nothing (or no harness package) is installed. */
164
+ /**
165
+ * The distinct installed prerelease versions across the blessed harness
166
+ * packages (framework packages excluded). One entry = coherent install;
167
+ * several = a mixed tree, which the per-package drift check cannot see.
168
+ * Empty when nothing (or no harness package) is installed.
169
+ */
115
170
  export function installedUpstreamLines() {
116
171
  const lines = new Set();
117
172
  for (const packageName of UPSTREAM_BLESSED_PACKAGES) {
118
173
  if (UPSTREAM_FRAMEWORK_MAJORS[packageName] !== undefined)
119
174
  continue;
120
- const line = rcNumber(installedUpstreamVersions()[packageName]);
121
- if (line !== undefined)
122
- lines.add(line);
175
+ const version = installedUpstreamVersions()[packageName];
176
+ if (version !== undefined && parseUpstreamVersion(version) !== undefined)
177
+ lines.add(version);
123
178
  }
124
- return [...lines].sort((a, b) => a - b);
179
+ return [...lines].sort((a, b) => compareVersions(parseUpstreamVersion(a), parseUpstreamVersion(b)));
125
180
  }
126
181
  /**
127
182
  * Report every blessed package whose installed version is NOT one of the
@@ -129,6 +184,7 @@ export function installedUpstreamLines() {
129
184
  * contract.
130
185
  */
131
186
  export function upstreamDrift() {
187
+ const validated = new Set(UPSTREAM_VALIDATED_VERSIONS);
132
188
  const drift = [];
133
189
  for (const [packageName, installed] of Object.entries(installedUpstreamVersions())) {
134
190
  const expected = UPSTREAM_BLESSED_PACKAGES.includes(packageName);
@@ -141,8 +197,7 @@ export function upstreamDrift() {
141
197
  matches = installedMajor === frameworkMajor;
142
198
  }
143
199
  else {
144
- const installedLine = rcNumber(installed);
145
- matches = installedLine !== undefined && UPSTREAM_VALIDATED_RC_LINES.includes(installedLine);
200
+ matches = installed !== undefined && validated.has(installed);
146
201
  }
147
202
  if (!matches) {
148
203
  drift.push({
@@ -154,3 +209,36 @@ export function upstreamDrift() {
154
209
  }
155
210
  return drift;
156
211
  }
212
+ /**
213
+ * Collapse {@link upstreamDrift} into a single summary for the boot notice:
214
+ * undefined when the install matches the contract. Only harness rc packages
215
+ * decide newer/older/mixed; a framework-only drift (e.g. a cordis major
216
+ * bump) reports `broken`, since its version line is not comparable.
217
+ */
218
+ export function upstreamDriftSummary() {
219
+ const drift = upstreamDrift();
220
+ if (drift.length === 0)
221
+ return undefined;
222
+ const harness = drift.filter(entry => UPSTREAM_FRAMEWORK_MAJORS[entry.package] === undefined);
223
+ const versions = [...new Set(drift.map(entry => entry.installed ?? 'missing'))];
224
+ if (harness.some(entry => entry.installed === undefined)) {
225
+ return { kind: 'broken', versions };
226
+ }
227
+ const harnessVersions = [...new Set(harness.map(entry => entry.installed))];
228
+ if (harnessVersions.length > 1) {
229
+ return { kind: 'mixed', versions };
230
+ }
231
+ const installed = parseUpstreamVersion(harnessVersions[0] ?? '');
232
+ const validated = parseUpstreamVersion(UPSTREAM_VALIDATED_VERSION);
233
+ if (installed === undefined) {
234
+ return { kind: 'broken', versions };
235
+ }
236
+ const order = compareVersions(installed, validated);
237
+ if (order > 0)
238
+ return { kind: 'newer', versions };
239
+ if (order < 0)
240
+ return { kind: 'older', versions };
241
+ // Identical to the primary validated version — cannot happen (it would
242
+ // not be drift); report broken rather than staying silent.
243
+ return { kind: 'broken', versions };
244
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAsB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAErG,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,sEAAsE;IACtE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACpC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA8ChC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAsB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAErG,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,sEAAsE;IACtE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACpC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA8ChC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASvE"}
@@ -64,18 +64,12 @@ export const Config = Schema.object({
64
64
  * @returns a promise settling when the TUI teardown completes.
65
65
  */
66
66
  export async function apply(ctx, config) {
67
- const { upstreamDrift, installedUpstreamLines, UPSTREAM_VALIDATED_LABEL } = await import('./contract.js');
68
- for (const entry of upstreamDrift()) {
69
- console.warn(`[dsh-tui] upstream drift: ${entry.package} installed=${entry.installed ?? 'missing'} ` +
70
- `validated=${entry.validated} — the TUI is validated against ${UPSTREAM_VALIDATED_LABEL}; ` +
71
- `upgrade or downgrade the profile when the upstream line changes.`);
72
- }
73
- const installedLines = installedUpstreamLines();
74
- if (installedLines.length > 1) {
75
- console.warn(`[dsh-tui] mixed upstream lines detected (${installedLines.map(n => `rc.${n}`).join(', ')}) — ` +
76
- `blessed packages are on different rc lines; the TUI is validated against ${UPSTREAM_VALIDATED_LABEL} ` +
77
- `and a coherent install is strongly recommended.`);
78
- }
67
+ // Upstream drift is NO LONGER spammed to stderr here: per-package
68
+ // console.warn lines interleave with the TUI frame redraw and arrive
69
+ // garbled (typewriter animation repaints over them). The merged,
70
+ // natural-language notice now renders in the logo header under the
71
+ // startup tip (LogoV2 ← upstreamDriftSummary); CI keeps the hard gate
72
+ // via scripts/verify-upstream-contract.ts.
79
73
  const { apply: ccTuiApply } = await import('./plugin.js');
80
74
  return ccTuiApply(ctx, config);
81
75
  }
@@ -1023,6 +1023,22 @@ declare const dict: {
1023
1023
  readonly zh: "更多技巧";
1024
1024
  readonly en: "more tips";
1025
1025
  };
1026
+ readonly 'logo-drift-newer': {
1027
+ readonly zh: "dsh 引擎为 {{installed}},比本界面验证过的 {{validated}} 新,可能出现兼容问题;求稳可执行 npm i -g @deepseek-ai/dsh@{{primary}} 降级,或等待 dsh-tui 适配新版。";
1028
+ readonly en: "The dsh engine ({{installed}}) is newer than the {{validated}} this UI is validated against, so issues are possible; downgrade via npm i -g @deepseek-ai/dsh@{{primary}} for stability, or wait for a dsh-tui update.";
1029
+ };
1030
+ readonly 'logo-drift-older': {
1031
+ readonly zh: "dsh 引擎为 {{installed}},低于本界面验证过的 {{validated}},部分功能可能不可用;建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 升级。";
1032
+ readonly en: "The dsh engine ({{installed}}) is older than the {{validated}} this UI is validated against; some features may be missing. Upgrade via npm i -g @deepseek-ai/dsh@{{primary}}.";
1033
+ };
1034
+ readonly 'logo-drift-mixed': {
1035
+ readonly zh: "检测到 dsh 引擎多版本混装({{installed}}),容易出现奇怪问题;建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 统一版本。";
1036
+ readonly en: "Mixed dsh engine versions detected ({{installed}}), which can cause odd behavior; unify them via npm i -g @deepseek-ai/dsh@{{primary}}.";
1037
+ };
1038
+ readonly 'logo-drift-broken': {
1039
+ readonly zh: "dsh 引擎版本异常({{installed}}),本界面验证过 {{validated}};建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 重装。";
1040
+ readonly en: "Unexpected dsh engine versions ({{installed}}); this UI is validated against {{validated}}. Reinstall via npm i -g @deepseek-ai/dsh@{{primary}}.";
1041
+ };
1026
1042
  readonly 'input-sent-after-turn': {
1027
1043
  readonly zh: "已发送,当前回合结束后处理";
1028
1044
  readonly en: "Sent, processed after the current turn";
@@ -2654,8 +2670,9 @@ export declare function t(key: I18nKey, params?: I18nParams): string;
2654
2670
  * lives in `LOCAL_COMMANDS` / the DSH registry, the dict carries zh only).
2655
2671
  * @param key - Dictionary key, computed at runtime so it is not type-checked.
2656
2672
  * @param fallback - Text used when no translation exists.
2673
+ * @param params - Placeholder values substituted into whichever text wins.
2657
2674
  */
2658
- export declare function tOr(key: string, fallback: string): string;
2675
+ export declare function tOr(key: string, fallback: string, params?: I18nParams): string;
2659
2676
  /**
2660
2677
  * Parse a persisted `{ lang }` value; anything else yields undefined.
2661
2678
  * @param text - Raw file contents.
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2xBA,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,IAAI,CAAA;AACvC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAUxD,uEAAuE;AACvE,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAG1B,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAG5D;AAED,qCAAqC;AACrC,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAGxC;AAED,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAM/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGzD;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAS5D;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAkB,GAAG,IAAI,GAAG,SAAS,CAMtE;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQ1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAavC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6yBA,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,IAAI,CAAA;AACvC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAUxD,uEAAuE;AACvE,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAG1B,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAG5D;AAED,qCAAqC;AACrC,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAGxC;AAED,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAM/D;AAED;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAMlF;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAS5D;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAkB,GAAG,IAAI,GAAG,SAAS,CAMtE;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQ1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAavC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
package/lib/types/i18n.js CHANGED
@@ -294,6 +294,24 @@ const dict = {
294
294
  'logo-tagline': { zh: '探索未至之境!', en: 'Explore the uncharted!' },
295
295
  'logo-tip-prefix': { zh: '提示:', en: 'Tip: ' },
296
296
  'logo-tip-more': { zh: '更多技巧', en: 'more tips' },
297
+ // Upstream-drift notice (merged one-liner under the tip; copy explains
298
+ // the problem AND the fix — the command pins the validated line).
299
+ 'logo-drift-newer': {
300
+ zh: 'dsh 引擎为 {{installed}},比本界面验证过的 {{validated}} 新,可能出现兼容问题;求稳可执行 npm i -g @deepseek-ai/dsh@{{primary}} 降级,或等待 dsh-tui 适配新版。',
301
+ en: 'The dsh engine ({{installed}}) is newer than the {{validated}} this UI is validated against, so issues are possible; downgrade via npm i -g @deepseek-ai/dsh@{{primary}} for stability, or wait for a dsh-tui update.',
302
+ },
303
+ 'logo-drift-older': {
304
+ zh: 'dsh 引擎为 {{installed}},低于本界面验证过的 {{validated}},部分功能可能不可用;建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 升级。',
305
+ en: 'The dsh engine ({{installed}}) is older than the {{validated}} this UI is validated against; some features may be missing. Upgrade via npm i -g @deepseek-ai/dsh@{{primary}}.',
306
+ },
307
+ 'logo-drift-mixed': {
308
+ zh: '检测到 dsh 引擎多版本混装({{installed}}),容易出现奇怪问题;建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 统一版本。',
309
+ en: 'Mixed dsh engine versions detected ({{installed}}), which can cause odd behavior; unify them via npm i -g @deepseek-ai/dsh@{{primary}}.',
310
+ },
311
+ 'logo-drift-broken': {
312
+ zh: 'dsh 引擎版本异常({{installed}}),本界面验证过 {{validated}};建议执行 npm i -g @deepseek-ai/dsh@{{primary}} 重装。',
313
+ en: 'Unexpected dsh engine versions ({{installed}}); this UI is validated against {{validated}}. Reinstall via npm i -g @deepseek-ai/dsh@{{primary}}.',
314
+ },
297
315
  // ── components/PromptInput.tsx ──────────────────────────────────────
298
316
  'input-sent-after-turn': { zh: '已发送,当前回合结束后处理', en: 'Sent, processed after the current turn' },
299
317
  'input-interrupted-next': { zh: '已插话 · 下一步立即处理', en: 'Interrupted · processed next' },
@@ -824,10 +842,12 @@ export function t(key, params = {}) {
824
842
  * lives in `LOCAL_COMMANDS` / the DSH registry, the dict carries zh only).
825
843
  * @param key - Dictionary key, computed at runtime so it is not type-checked.
826
844
  * @param fallback - Text used when no translation exists.
845
+ * @param params - Placeholder values substituted into whichever text wins.
827
846
  */
828
- export function tOr(key, fallback) {
847
+ export function tOr(key, fallback, params = {}) {
829
848
  const entry = dict[key];
830
- return entry?.[activeLang] ?? fallback;
849
+ const template = entry?.[activeLang] ?? fallback;
850
+ return template.replace(/\{\{(\w+)\}\}/g, (match, name) => name in params ? String(params[name]) : match);
831
851
  }
832
852
  // ── persistence (~/.dsh-tui/lang.json) ─────────────────────────────────
833
853
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ink.d.ts","sourceRoot":"","sources":["../../../src/ink/ink.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ink.d.ts","sourceRoot":"","sources":["../../../src/ink/ink.tsx"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAa9C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAQrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAA4B,KAAK,aAAa,EAAiB,MAAM,uBAAuB,CAAC;AAIpG,OAAO,EAAqG,KAAK,SAAS,EAAwF,KAAK,cAAc,EAAqH,MAAM,gBAAgB,CAAC;AAgCjX,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AACF,MAAM,CAAC,OAAO,OAAO,GAAG;IA6HV,OAAO,CAAC,QAAQ,CAAC,OAAO;IA5HpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,cAAc,CAEpB;IAEF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAiB;IACjC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAgB;IACpC,OAAO,CAAC,cAAc,CAAC,CAAa;IACpC,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAa;IACrD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,UAAU,CAA8C;IAGhE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,uBAAuB,CAAuB;IACtD,OAAO,CAAC,gBAAgB,CAYtB;IACF,OAAO,CAAC,kBAAkB,CAGvB;IAIH,QAAQ,CAAC,SAAS,EAAE,cAAc,CAA0B;IAG5D,OAAO,CAAC,oBAAoB,CAAM;IAOlC,OAAO,CAAC,eAAe,CAIP;IAIhB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;IAI5D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAK1D,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,sBAAsB,CAAS;IAKvC,OAAO,CAAC,oBAAoB,CAKZ;IAMhB,OAAO,CAAC,qBAAqB,CAAS;IAMtC,OAAO,CAAC,qBAAqB,CAAS;IAMtC,OAAO,CAAC,iBAAiB,CAAkC;IAK3D,OAAO,CAAC,aAAa,CAGL;IAChB,OAAO,CAAC,gBAAgB;gBAMK,OAAO,EAAE,OAAO;IAmH7C,OAAO,CAAC,YAAY,CAqBlB;IAQF,OAAO,CAAC,YAAY,CA+ClB;IACF,kBAAkB,EAAE,MAAM,IAAI,CAAY;IAC1C,iBAAiB,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,CAAY;IACvD,eAAe,EAAE,MAAM,IAAI,CAAY;IAEvC;;;;;OAKG;IACH,oBAAoB,IAAI,IAAI;IAyB5B;;;;;;;;;;;OAWG;IACH,mBAAmB,IAAI,IAAI;IAuD3B;;;;;;;;;;;;OAYG;IACH,gBAAgB;IAIhB,0EAA0E;IAC1E,OAAO,CAAC,SAAS;IAUjB,QAAQ;IAgZR,KAAK,IAAI,IAAI;IAOb,MAAM,IAAI,IAAI;IAKd;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAUf;;;;;;;OAOG;IACH,WAAW,IAAI,IAAI;IAmBnB;;;;;;;OAOG;IACH,wBAAwB,IAAI,IAAI;IAgBhC;;;;;;;;;OASG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;;;;;OAMG;IACH,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,UAAQ,GAAG,IAAI;IA8BhE,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,qBAAqB,GAAI,0BAAwB,KAAG,IAAI,CAuCtD;IAEF;;;;;;;;;;OAUG;IACH,iBAAiB,IAAI,IAAI;IA2CzB;;;;;;;;;OASG;IACH,qBAAqB,IAAI,IAAI;IAqB7B,sBAAsB;IACtB,UAAU,IAAI,IAAI;IAIlB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,uBAAuB;IA2B/B;;;;OAIG;IACH,oBAAoB,IAAI,MAAM;IAa9B;;;OAGG;IACH,aAAa,IAAI,MAAM;IAQvB,wDAAwD;IACxD,kBAAkB,IAAI,IAAI;IAM1B;;;;;;OAMG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMvC;;;;;;;;;wEASoE;IACpE,kBAAkB,CAAC,EAAE,EAAE,GAAG,CAAC,UAAU,GAAG,aAAa,EAAE;IAgCvD;;;;iEAI6D;IAC7D,kBAAkB,CAAC,KAAK,EAAE;QACxB,SAAS,EAAE,aAAa,EAAE,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,GAAG,IAAI;IAKf;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAoBxC;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI;IAIrF;;;;;;OAMG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAY3E;;;;;;;OAOG;IACH,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IA+CzC,iDAAiD;IACjD,gBAAgB,IAAI,OAAO;IAI3B;;;OAGG;IACH,0BAA0B,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAItD,OAAO,CAAC,qBAAqB;IAK7B;;;;;;OAMG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAKhD,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7C,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAejD;;;;;;;;OAQG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAa5D;;;OAGG;IACH,gBAAgB,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAEtD;;;;OAIG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIhC;;;;;;OAMG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI;IAc9D;;;;;OAKG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAanD,OAAO,CAAC,cAAc,CAGd;IACR,OAAO,CAAC,UAAU,CAAS;IAC3B,YAAY,IAAI,IAAI;IA8BpB,WAAW,IAAI,IAAI;IAoDnB,OAAO,CAAC,QAAQ;IAGhB,OAAO,CAAC,oBAAoB,CAK1B;IACF,OAAO,CAAC,SAAS;IAGjB,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAa7B,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI;IAiFtC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC,cAAc,IAAI,IAAI;IAYtB;;;;;;;OAOG;IACH,UAAU,IAAI,IAAI;IAalB,YAAY,IAAI,MAAM,IAAI;IAqB1B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,WAAW;CAoCpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,wBAAgB,UAAU,CAAC,KAAK,GAAE,MAAM,CAAC,UAA0B,GAAG,IAAI,CAsDzE"}
@@ -30,7 +30,7 @@ import { applyPositionedHighlight, scanPositions } from './render-to-screen.js';
30
30
  import createRenderer from './renderer.js';
31
31
  import { CharPool, cellAt, createScreen, HyperlinkPool, isEmptyCellAt, migrateScreenPools, StylePool } from './screen.js';
32
32
  import { applySearchHighlight } from './searchHighlight.js';
33
- import { applySelectionOverlay, captureScrolledRows, clearSelection, createSelectionState, extendSelection, findPlainTextUrlAt, getSelectedText, hasSelection, moveFocus, selectLineAt, selectWordAt, shiftAnchor, shiftSelection, shiftSelectionForFollow, startSelection, updateSelection } from './selection.js';
33
+ import { applySelectionOverlay, captureScrolledRows, clearSelection, createSelectionState, extendSelection, findPlainTextUrlAt, getSelectedText, hasSelection, moveFocus, pickFollowForSelection, selectLineAt, selectWordAt, shiftAnchor, shiftSelection, shiftSelectionForFollow, startSelection, updateSelection } from './selection.js';
34
34
  import { isDecstbmSafe, SYNC_OUTPUT_SUPPORTED, supportsExtendedKeys, supportsWin32InputMode, writeDiffToTerminal } from './terminal.js';
35
35
  import { CURSOR_HOME, cursorMove, cursorPosition, DISABLE_KITTY_KEYBOARD, DISABLE_MODIFY_OTHER_KEYS, DISABLE_WIN32_INPUT_MODE, ENABLE_KITTY_KEYBOARD, ENABLE_MODIFY_OTHER_KEYS, ENABLE_WIN32_INPUT_MODE, ERASE_SCREEN, ERASE_SCROLLBACK, SGR_RESET } from './termio/csi.js';
36
36
  import { DBP, DFE, DISABLE_MOUSE_TRACKING, ENABLE_MOUSE_TRACKING, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, SHOW_CURSOR } from './termio/dec.js';
@@ -507,10 +507,11 @@ export default class Ink {
507
507
  prevFrameContaminated: this.prevFrameContaminated
508
508
  });
509
509
  const rendererMs = performance.now() - renderStart;
510
- // Sticky/auto-follow scrolled the ScrollBox this frame. Translate the
511
- // selection by the same delta so the highlight stays anchored to the
512
- // TEXT (native terminal behavior — the selection walks up the screen
513
- // as content scrolls, eventually clipping at the top). frontFrame
510
+ // Sticky/auto-follow or wheel-drain scrolled one or more ScrollBoxes
511
+ // this frame. Translate the selection by the same delta so the highlight
512
+ // stays anchored to the TEXT (native terminal behavior — the
513
+ // selection walks up the screen as content scrolls, eventually
514
+ // clipping at the top). frontFrame
514
515
  // still holds the PREVIOUS frame's screen (swap is at ~500 below), so
515
516
  // captureScrolledRows reads the rows that are about to scroll out
516
517
  // before they're overwritten — the text stays copyable until the
@@ -518,16 +519,28 @@ export default class Ink {
518
519
  // (screen-local) so only anchor shifts — selection grows toward the
519
520
  // mouse as the anchor walks up. After release, both ends are text-
520
521
  // anchored and move as a block.
521
- const follow = consumeFollowScroll();
522
- if (follow && this.selection.anchor &&
523
- // Only translate if the selection is ON scrollbox content. Selections
524
- // in the footer/prompt/StickyPromptHeader are on static text — the
525
- // scroll doesn't move what's under them. Without this guard, a
526
- // footer selection would be shifted by -delta then clamped to
527
- // viewportBottom, teleporting it into the scrollbox. Mirror the
528
- // bounds check the deleted check() in ScrollKeybindingHandler had.
529
- this.selection.anchor.row >= follow.viewportTop && this.selection.anchor.row <= follow.viewportBottom) {
522
+ const follow = pickFollowForSelection(consumeFollowScroll(), this.selection.anchor?.row ?? null);
523
+ // pickFollowForSelection already checked anchor-in-viewport (that IS
524
+ // the "selection is on scrollbox content" guard — footer/prompt
525
+ // selections on static text match no viewport and follow nothing).
526
+ // Innermost-viewport wins attributes correctly when several boxes
527
+ // scrolled this frame (transcript draining while an overlay panel's
528
+ // box scrolls): panels render on top, so overlap-row selections
529
+ // belong to the panel, not the covered transcript.
530
+ if (follow && this.selection.anchor) {
530
531
  const { delta, viewportTop, viewportBottom } = follow;
532
+ // Signed delta: >0 = content moved up (at-bottom follow or
533
+ // wheel-down drain); <0 = content moved down (wheel-up drain, #438).
534
+ // The capture window is the viewport-edge rows about to scroll out
535
+ // (top edge when content moves up, bottom edge when it moves down),
536
+ // and the shift re-anchors the endpoints by the same amount in the
537
+ // OPPOSITE direction so they track the text, not the screen.
538
+ const rows = Math.abs(delta);
539
+ const up = delta > 0;
540
+ const firstRow = up ? viewportTop : viewportBottom - rows + 1;
541
+ const lastRow = up ? viewportTop + rows - 1 : viewportBottom;
542
+ const side = up ? 'above' : 'below';
543
+ const shift = up ? -rows : rows;
531
544
  // captureScrolledRows and shift* are a pair: capture grabs rows about
532
545
  // to scroll off, shift moves the selection endpoint so the same rows
533
546
  // won't intersect again next frame. Capturing without shifting leaves
@@ -537,9 +550,9 @@ export default class Ink {
537
550
  // each shift branch so the pairing can't be broken by a new guard.
538
551
  if (this.selection.isDragging) {
539
552
  if (hasSelection(this.selection)) {
540
- captureScrolledRows(this.selection, this.frontFrame.screen, viewportTop, viewportTop + delta - 1, 'above');
553
+ captureScrolledRows(this.selection, this.frontFrame.screen, firstRow, lastRow, side);
541
554
  }
542
- shiftAnchor(this.selection, -delta, viewportTop, viewportBottom);
555
+ shiftAnchor(this.selection, shift, viewportTop, viewportBottom);
543
556
  }
544
557
  else if (
545
558
  // Flag-3 guard: the anchor check above only proves ONE endpoint is
@@ -556,14 +569,16 @@ export default class Ink {
556
569
  // is correct there even when focus is in the footer).
557
570
  !this.selection.focus || this.selection.focus.row >= viewportTop && this.selection.focus.row <= viewportBottom) {
558
571
  if (hasSelection(this.selection)) {
559
- captureScrolledRows(this.selection, this.frontFrame.screen, viewportTop, viewportTop + delta - 1, 'above');
572
+ captureScrolledRows(this.selection, this.frontFrame.screen, firstRow, lastRow, side);
560
573
  }
561
- const cleared = shiftSelectionForFollow(this.selection, -delta, viewportTop, viewportBottom);
562
- // Auto-clear (both ends overshot minRow) must notify React-land
563
- // so useHasSelection re-renders and the footer copy/escape hint
564
- // disappears. notifySelectionChange() would recurse into onRender;
565
- // fire the listeners directly — they schedule a React update for
566
- // LATER, they don't re-enter this frame.
574
+ const cleared = shiftSelectionForFollow(this.selection, shift, viewportTop, viewportBottom);
575
+ // Auto-clear (both ends overshot an edge — off the top via
576
+ // follow/wheel-down, off the bottom via wheel-up) must notify
577
+ // React-land so useHasSelection re-renders and the footer
578
+ // copy/escape hint disappears. notifySelectionChange() would
579
+ // recurse into onRender; fire the listeners directly — they
580
+ // schedule a React update for LATER, they don't re-enter this
581
+ // frame.
567
582
  if (cleared)
568
583
  for (const cb of this.selectionListeners)
569
584
  cb();
@@ -47,10 +47,13 @@ export type FollowScroll = {
47
47
  viewportBottom: number;
48
48
  };
49
49
  /**
50
- * Read and clear the follow-scroll event recorded this frame.
51
- * @returns the follow-scroll delta and viewport bounds, or null.
50
+ * Read and clear the follow-scroll events recorded this frame. At most one
51
+ * per ScrollBox (a box that follows AND drains reports only the follow —
52
+ * the follow branch clears pendingScrollDelta before the drain runs);
53
+ * several boxes may each report when they scroll in the same frame.
54
+ * @returns this frame's follow-scroll events; empty when none.
52
55
  */
53
- export declare function consumeFollowScroll(): FollowScroll | null;
56
+ export declare function consumeFollowScroll(): FollowScroll[];
54
57
  /**
55
58
  * Build a mapping from each character position in the plain text to its segment index.
56
59
  * Returns an array where charToSegment[i] is the segment index for character i.
@@ -1 +1 @@
1
- {"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAK1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAqBxC,6CAA6C;AAC7C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAOD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAWvE,qFAAqF;AACrF,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AASD,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,GAAG,IAAI,CAEtD;AAUD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB,CAAA;AAGD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,GAAG,IAAI,CAIzD;AAoFD;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CASlE;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,wBAAwB,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,OAAe,GAC3B,MAAM,CA0GR;AA+DD;;;;;;;;;GASG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAM9B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wBAAwB,CAAC,EAAE,KAAK,CAAA;CACjC,GACA,IAAI,CA62BN;AAyOD,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,CAAA;AAE1D,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAK1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAqBxC,6CAA6C;AAC7C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAOD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAWvE,qFAAqF;AACrF,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AASD,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,GAAG,IAAI,CAEtD;AAgBD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB,CAAA;AAGD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CAIpD;AAoFD;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CASlE;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,wBAAwB,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,OAAe,GAC3B,MAAM,CA0GR;AA+DD;;;;;;;;;GASG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAM9B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wBAAwB,CAAC,EAAE,KAAK,CAAA;CACjC,GACA,IAAI,CAo4BN;AAyOD,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,CAAA;AAE1D,eAAe,kBAAkB,CAAA"}