@askdkc/dsh-cli 0.13.1 → 0.13.3

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 (28) hide show
  1. package/bin/dsh-tui.js +2 -2
  2. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  3. package/lib/types/dsh-adapter/bundled-presets.js +9 -0
  4. package/lib/types/dsh-adapter/index.d.ts +1 -1
  5. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  6. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  7. package/lib/types/dsh-adapter/plugin.js +3 -1
  8. package/lib/types/dsh-adapter/recap.d.ts.map +1 -1
  9. package/lib/types/dsh-adapter/recap.js +5 -1
  10. package/lib/types/dsh-adapter/response-language.d.ts +6 -0
  11. package/lib/types/dsh-adapter/response-language.d.ts.map +1 -0
  12. package/lib/types/dsh-adapter/response-language.js +11 -0
  13. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  14. package/lib/types/dsh-adapter/sideQuestion.js +3 -0
  15. package/lib/types/i18n.d.ts +5 -6
  16. package/lib/types/i18n.d.ts.map +1 -1
  17. package/lib/types/i18n.js +6 -7
  18. package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.js +16 -3
  19. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.d.ts +1 -0
  20. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.js +7 -2
  21. package/node_modules/dsh-working-activity/lib/types/index.js +4 -6
  22. package/node_modules/dsh-working-activity/lib/types/lang.d.ts +10 -8
  23. package/node_modules/dsh-working-activity/lib/types/lang.js +11 -12
  24. package/node_modules/dsh-working-activity/src/index.ts +4 -6
  25. package/node_modules/dsh-working-activity/src/lang.ts +12 -13
  26. package/package.json +3 -2
  27. package/presets/liangshen/agent.cordis.yml +2 -1
  28. package/presets/response-language.txt +5 -0
package/bin/dsh-tui.js CHANGED
@@ -25,7 +25,7 @@
25
25
  * 可用。shellQuote 等小工具在此内联。
26
26
  *
27
27
  * 面向用户的消息走 MSG 双语表:与 TUI 的语言契约一致——
28
- * `DSH_TUI_LANG` 显式指定时从其值,否则默认中文(同 src/i18n.ts 的缺省)。
28
+ * `DSH_TUI_LANG` 显式指定时从其值,否则默认英文(同 src/i18n.ts 的缺省)。
29
29
  */
30
30
  import { spawn, spawnSync } from 'node:child_process'
31
31
  import { existsSync, readFileSync, readdirSync, realpathSync, rmSync } from 'node:fs'
@@ -133,7 +133,7 @@ const isVersionNewer = (a, b) => {
133
133
  return false
134
134
  }
135
135
 
136
- const lang = process.env.DSH_TUI_LANG === 'en' ? 'en' : 'zh'
136
+ const lang = process.env.DSH_TUI_LANG === 'zh' ? 'zh' : 'en'
137
137
  const MSG = {
138
138
  noDsh: {
139
139
  en: '[dsh-cli] dsh CLI not found. Install it or set DSH_TUI_DSH_ROOT to a built Harness checkout:\n npm install -g @deepseek-ai/dsh',
@@ -1 +1 @@
1
- {"version":3,"file":"bundled-presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/bundled-presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AA4BlD;qFACqF;AACrF,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCxE"}
1
+ {"version":3,"file":"bundled-presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/bundled-presets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAoClD;qFACqF;AACrF,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCxE"}
@@ -1,3 +1,4 @@
1
+ import { RESPONSE_LANGUAGE_POLICY } from './response-language.js';
1
2
  import { readFileSync } from 'node:fs';
2
3
  import { createRequire } from 'node:module';
3
4
  import { join } from 'node:path';
@@ -13,6 +14,14 @@ function readPresetPatch(path) {
13
14
  const row = patches[0]?.insert?.[0];
14
15
  if (row?.name === '@deepseek-ai/dsh-agent-preset'
15
16
  && typeof row.config?.id === 'string' && Array.isArray(row.config.plugins)) {
17
+ // Only adapt our bundled complete persona; profile-owned declarations bypass this reader.
18
+ if (row.config.id === 'minimal') {
19
+ const persona = row.config.plugins.find((plugin) => plugin.id === 'persona');
20
+ if (persona?.config?.complete !== true || typeof persona.config.prefix !== 'string') {
21
+ throw new Error('dsh-tui: bundled Minimal complete persona is missing');
22
+ }
23
+ persona.config.prefix += `\n\n${RESPONSE_LANGUAGE_POLICY}`;
24
+ }
16
25
  return row.config;
17
26
  }
18
27
  }
@@ -73,7 +73,7 @@ export interface Config {
73
73
  * override DSH_TUI_DISABLE_TERMINAL_IMAGES can always force previews off. */
74
74
  terminalImages?: boolean;
75
75
  /** UI language: `en` / `zh`. When absent, the `DSH_TUI_LANG` env var wins,
76
- * then the `/lang` choice persisted in `~/.dsh-tui/lang.json`, then `zh`. */
76
+ * then the `/lang` choice persisted in `~/.dsh-tui/lang.json`, then the locale, falling back to `en`. */
77
77
  lang?: string;
78
78
  /** Agent preset id new sessions compose from (standard/ptc/minimal/
79
79
  * cordis/… when the roster is mounted). When absent, the `/preset` choice
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+D,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAuDtH,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAgCjE;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAcxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAE,OAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAq+CzH;AAmMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf;AA4HD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIrE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+D,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAuDtH,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAgCjE;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAcxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAE,OAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAs+CzH;AAmMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf;AA4HD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIrE"}
@@ -1,3 +1,4 @@
1
+ import { registerResponseLanguage } from './response-language.js';
1
2
  import { randomUUID } from 'node:crypto';
2
3
  import React from 'react';
3
4
  import { SessionId } from '@deepseek-ai/dsh-session';
@@ -186,11 +187,12 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
186
187
  }
187
188
  // Validate settings before creating an agent or taking over the terminal.
188
189
  const tuiSettingsNs = resolveSettingsNamespace(configOwner, Config);
190
+ registerResponseLanguage(ctx);
189
191
  await registerBundledPresets(ctx);
190
192
  // UI language resolution: DSH_TUI_LANG env var wins, then the
191
193
  // active profile `dsh-tui.lang` configuration (applied once the settings
192
194
  // namespace registers below), then cordis.yml `lang`, then the
193
- // persisted `/lang` choice, then `zh`. Must settle before the first
195
+ // persisted `/lang` choice, then the locale, falling back to `en`. Must settle before the first
194
196
  // render so every module resolves strings in the same language.
195
197
  const envLang = process.env.DSH_TUI_LANG;
196
198
  setLang(isLang(envLang) ? envLang : isLang(config.lang) ? config.lang : resolveStartupLang());
@@ -1 +1 @@
1
- {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/recap.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAkBtC;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkCjG;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAyBnF"}
1
+ {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/recap.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAkBtC;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAmCjG;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAyBnF"}
@@ -1,3 +1,4 @@
1
+ import { RESPONSE_LANGUAGE_POLICY } from './response-language.js';
1
2
  /** Max chars of recent activity fed to the recap call. */
2
3
  export const RECAP_RECENT_CHARS = 6000;
3
4
  /** How many exchanges (user + assistant) the recap looks back. */
@@ -32,6 +33,8 @@ export function collectRecentActivity(events, limitChars) {
32
33
  const record = event;
33
34
  if (record['type'] === 'user/message') {
34
35
  const data = record['data'];
36
+ if (data?.['source']?.kind !== 'user')
37
+ continue;
35
38
  const text = textOfContent(data?.['content']);
36
39
  if (text !== undefined)
37
40
  entries.push({ role: 'user', text });
@@ -70,7 +73,8 @@ export function collectRecentActivity(events, limitChars) {
70
73
  */
71
74
  export function wrapRecapPrompt(activity) {
72
75
  return `Create a compact session recap from the activity excerpt below.
73
- Use the user's language and describe the work and its current outcome accurately.
76
+ ${RESPONSE_LANGUAGE_POLICY}
77
+ Determine the language from the latest user-authored request in the excerpt and any explicit continuing user preference. Assistant replies and this wrapper are not language signals. Describe the work and its current outcome accurately.
74
78
  Return one JSON object with two string fields:
75
79
  - "title": a descriptive title of about 2-6 words.
76
80
  - "summary": one line of about 10-20 words covering the most recent progress.
@@ -0,0 +1,6 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ /** One packaged policy for ordinary, complete-persona and auxiliary requests. */
3
+ export declare const RESPONSE_LANGUAGE_POLICY: string;
4
+ /** Register independently of the replaceable deployment persona. */
5
+ export declare function registerResponseLanguage(ctx: Context): void;
6
+ //# sourceMappingURL=response-language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-language.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/response-language.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,QAAmF,CAAA;AAExH,oEAAoE;AACpE,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAI3D"}
@@ -0,0 +1,11 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { packagedPresetRoot } from './packaged-presets.js';
4
+ /** One packaged policy for ordinary, complete-persona and auxiliary requests. */
5
+ export const RESPONSE_LANGUAGE_POLICY = readFileSync(join(packagedPresetRoot(), 'response-language.txt'), 'utf8').trim();
6
+ /** Register independently of the replaceable deployment persona. */
7
+ export function registerResponseLanguage(ctx) {
8
+ ctx.inject(['systemPrompt'], ready => {
9
+ ready.systemPrompt.section({ name: 'dsh-cli:response-language', order: 10300, text: RESPONSE_LANGUAGE_POLICY, interpolate: false });
10
+ });
11
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"sideQuestion.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/sideQuestion.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,yEAAyE;IACzE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,aAAa,CAAC,WAAW,CAAC,CAAA;IACvD,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,yEAAyE;IACzE,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuB/B"}
1
+ {"version":3,"file":"sideQuestion.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/sideQuestion.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,yEAAyE;IACzE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,aAAa,CAAC,WAAW,CAAC,CAAA;IACvD,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,yEAAyE;IACzE,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuB/B"}
@@ -1,3 +1,4 @@
1
+ import { RESPONSE_LANGUAGE_POLICY } from './response-language.js';
1
2
  /**
2
3
  * Side Question (`/btw`): a single-turn call without tools, replaying the
3
4
  * live session's derived history (prompt-cache reuse, compaction-style
@@ -13,6 +14,8 @@ import { BlockAssembler } from '@deepseek-ai/dsh-llm';
13
14
  */
14
15
  export function wrapSideQuestion(question) {
15
16
  return `<side-question-context>
17
+ ${RESPONSE_LANGUAGE_POLICY}
18
+ Determine the request language from the question after this wrapper, not from this wrapper.
16
19
  Give one concise answer to the question below using the conversation already provided.
17
20
  This auxiliary call runs alongside the main session. The main task continues independently;
18
21
  do not describe it as interrupted, resumed, or as work performed by this call.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * dsh-tui localization — UI strings for Chinese (`zh`, the default) and
2
+ * dsh-tui localization — UI strings for Chinese (`zh`) and
3
3
  * English (`en`).
4
4
  *
5
5
  * Resolution order mirrors the `/theme` mechanism (see themePrefs.ts):
@@ -8,7 +8,7 @@
8
8
  * 2. `lang` cordis.yml config key (see Config in index.ts)
9
9
  * 3. the persisted `/lang` choice in `~/.dsh-tui/lang.json`
10
10
  * 4. the OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`)
11
- * 5. `zh` (the original hard-coded language)
11
+ * 5. `en` (the fallback language)
12
12
  *
13
13
  * `/lang` switches at runtime and hot-swaps the whole UI. The dictionary is
14
14
  * a flat key → per-language text map; `t(key, params)` substitutes
@@ -4434,16 +4434,15 @@ export declare function writeLangPref(lang: Lang, dir?: string): boolean;
4434
4434
  * user must not get a Chinese UI. The POSIX/C locale means "no locale
4435
4435
  * selected" and conventionally maps to English — importantly it is what
4436
4436
  * CI runners (LANG=C.UTF-8) report, so tests asserting English UI copy
4437
- * stay deterministic. Only an ABSENT locale (typical on Windows, where
4438
- * these POSIX vars don't exist and imply nothing about the user) keeps
4439
- * the zh default.
4437
+ * stay deterministic. An absent locale (typical on Windows) also uses
4438
+ * the English fallback.
4440
4439
  */
4441
4440
  export declare function detectLocaleLang(): Lang;
4442
4441
  /**
4443
4442
  * Resolve the startup language: `DSH_TUI_LANG` when it holds a valid value
4444
4443
  * (pinned at process start — the repro/verify scripts rely on this for
4445
4444
  * deterministic UI copy), else the persisted `/lang` choice, else the OS
4446
- * locale guess, else `zh` (the original hard-coded language). The
4445
+ * locale guess, else `en` (the fallback language). The
4447
4446
  * cordis.yml `lang` precedence lives in plugin.apply.
4448
4447
  */
4449
4448
  export declare function resolveStartupLang(): Lang;
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
package/lib/types/i18n.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * dsh-tui localization — UI strings for Chinese (`zh`, the default) and
2
+ * dsh-tui localization — UI strings for Chinese (`zh`) and
3
3
  * English (`en`).
4
4
  *
5
5
  * Resolution order mirrors the `/theme` mechanism (see themePrefs.ts):
@@ -8,7 +8,7 @@
8
8
  * 2. `lang` cordis.yml config key (see Config in index.ts)
9
9
  * 3. the persisted `/lang` choice in `~/.dsh-tui/lang.json`
10
10
  * 4. the OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`)
11
- * 5. `zh` (the original hard-coded language)
11
+ * 5. `en` (the fallback language)
12
12
  *
13
13
  * `/lang` switches at runtime and hot-swaps the whole UI. The dictionary is
14
14
  * a flat key → per-language text map; `t(key, params)` substitutes
@@ -1474,9 +1474,8 @@ export function writeLangPref(lang, dir = PREFS_DIR) {
1474
1474
  * user must not get a Chinese UI. The POSIX/C locale means "no locale
1475
1475
  * selected" and conventionally maps to English — importantly it is what
1476
1476
  * CI runners (LANG=C.UTF-8) report, so tests asserting English UI copy
1477
- * stay deterministic. Only an ABSENT locale (typical on Windows, where
1478
- * these POSIX vars don't exist and imply nothing about the user) keeps
1479
- * the zh default.
1477
+ * stay deterministic. An absent locale (typical on Windows) also uses
1478
+ * the English fallback.
1480
1479
  */
1481
1480
  export function detectLocaleLang() {
1482
1481
  // `||` (not `??`): an EMPTY locale variable means "unset" and must fall
@@ -1487,14 +1486,14 @@ export function detectLocaleLang() {
1487
1486
  '';
1488
1487
  const locale = raw.split('.')[0]?.toLowerCase() ?? '';
1489
1488
  if (locale === '')
1490
- return 'zh';
1489
+ return 'en';
1491
1490
  return locale.startsWith('zh') ? 'zh' : 'en';
1492
1491
  }
1493
1492
  /**
1494
1493
  * Resolve the startup language: `DSH_TUI_LANG` when it holds a valid value
1495
1494
  * (pinned at process start — the repro/verify scripts rely on this for
1496
1495
  * deterministic UI copy), else the persisted `/lang` choice, else the OS
1497
- * locale guess, else `zh` (the original hard-coded language). The
1496
+ * locale guess, else `en` (the fallback language). The
1498
1497
  * cordis.yml `lang` precedence lives in plugin.apply.
1499
1498
  */
1500
1499
  export function resolveStartupLang() {
@@ -1,10 +1,12 @@
1
1
  /** Convert DSH conversation blocks into low-level SDK prompts without an agent loop. */
2
2
  import { LlmError, projectToolUpdates, fileHandleText } from '@deepseek-ai/dsh-llm';
3
3
  import { projectReplay, requireReplaySignature } from './opencode-replay.js';
4
+ import { createHash } from 'node:crypto';
4
5
  export async function encodePrompt(options, model, attachments, warn) {
5
6
  const prompt = [];
6
7
  const names = new Map();
7
8
  const callIds = new Map();
9
+ const wireIds = new Set();
8
10
  if (options.system)
9
11
  prompt.push({ role: 'system', content: options.system });
10
12
  const projection = projectToolUpdates(options.messages, options.tools, undefined, options.toolHistory);
@@ -61,14 +63,24 @@ export async function encodePrompt(options, model, attachments, warn) {
61
63
  else if (block.type === 'file')
62
64
  content.push({ type: 'text', text: fileHandleText(block.attachment, attachments?.()?.fileHostPath(block.attachment)) });
63
65
  else if (block.type === 'reasoning' && message.role === 'assistant') {
66
+ if (replay.foreign)
67
+ continue;
64
68
  requireReplaySignature(block, model.protocol, providerOptions);
65
69
  content.push({ type: 'reasoning', text: block.text, providerOptions });
66
70
  }
67
71
  else if (block.type === 'tool-call' && message.role === 'assistant') {
68
- if (model.protocol === 'responses' && block.id.includes('|') && !replay.callIds.has(block.id))
72
+ // Foreign pi Responses ids contain an opaque item suffix. Give the
73
+ // call/result pair a portable id without restoring that foreign item.
74
+ if (replay.foreign && model.protocol === 'responses' && block.id.includes('|'))
75
+ callIds.set(block.id, `dsh_${createHash('sha256').update(block.id).digest('hex').slice(0, 48)}`);
76
+ if (model.protocol === 'responses' && block.id.includes('|') && !callIds.has(block.id))
69
77
  throw new LlmError('Cannot restore legacy Responses tool call pairing', 'INVALID_REPLAY_STATE');
70
78
  if (names.has(block.id))
71
79
  throw new LlmError('Duplicate stored tool call id', 'INVALID_REPLAY_STATE');
80
+ const wireId = callIds.get(block.id) ?? block.id;
81
+ if (wireIds.has(wireId))
82
+ throw new LlmError('Duplicate wire tool call id', 'INVALID_REPLAY_STATE');
83
+ wireIds.add(wireId);
72
84
  if (model.protocol === 'google' && model.reasoning && !providerOptions?.google?.thoughtSignature && !message.content.slice(0, index).some(part => part.type === 'tool-call'))
73
85
  throw new LlmError('Cannot replay Google tool call without its verified thought signature', 'INVALID_REPLAY_STATE');
74
86
  names.set(block.id, block.name);
@@ -79,7 +91,7 @@ export async function encodePrompt(options, model, attachments, warn) {
79
91
  catch {
80
92
  throw new LlmError('Stored tool arguments are not valid JSON', 'INVALID_REPLAY_STATE');
81
93
  }
82
- content.push({ type: 'tool-call', toolCallId: callIds.get(block.id) ?? block.id, toolName: block.name, input, providerOptions });
94
+ content.push({ type: 'tool-call', toolCallId: wireId, toolName: block.name, input, providerOptions });
83
95
  }
84
96
  else if (block.type === 'image') {
85
97
  if (message.role === 'assistant')
@@ -87,7 +99,8 @@ export async function encodePrompt(options, model, attachments, warn) {
87
99
  content.push(await imagePart(block));
88
100
  }
89
101
  }
90
- prompt.push({ role: message.role, content });
102
+ if (content.length || !replay.foreign)
103
+ prompt.push({ role: message.role, content });
91
104
  }
92
105
  return prompt;
93
106
  }
@@ -8,6 +8,7 @@ export interface ReplayProjection {
8
8
  blocks: (SharedV4ProviderOptions | undefined)[];
9
9
  callIds: Map<string, string>;
10
10
  trusted: boolean;
11
+ foreign: boolean;
11
12
  }
12
13
  /** Validate the entire aligned envelope before restoring any signature or item id. */
13
14
  export declare function projectReplay(source: unknown, content: readonly ContentBlock[], model: OpenCodeModel, route: string, warn?: (reason: string) => void): ReplayProjection;
@@ -33,9 +33,14 @@ function completeResponseSignatures(blocks, content) {
33
33
  const APIS = { messages: 'anthropic-messages', responses: 'openai-responses', chat: 'openai-completions', google: 'google-generative-ai' };
34
34
  /** Validate the entire aligned envelope before restoring any signature or item id. */
35
35
  export function projectReplay(source, content, model, route, warn) {
36
- const empty = () => ({ blocks: content.map(() => undefined), callIds: new Map(), trusted: false });
37
36
  const message = record(source);
38
37
  const envelope = record(message?.replayState);
38
+ // A model switch deliberately discards provider-specific replay data. It is
39
+ // distinct from a damaged native envelope, whose signature checks still apply.
40
+ const foreign = typeof message?.provider === 'string' && !!message.provider && typeof message.model === 'string' && !!message.model && (message.provider !== route || message.model !== model.id);
41
+ const empty = () => ({ blocks: content.map(() => undefined), callIds: new Map(), trusted: false, foreign });
42
+ if (foreign)
43
+ return empty();
39
44
  if (!envelope) {
40
45
  if (message?.replayState !== undefined)
41
46
  warn?.('OpenCode history: malformed replay envelope; retaining message content');
@@ -122,7 +127,7 @@ export function projectReplay(source, content, model, route, warn) {
122
127
  });
123
128
  if (model.protocol === 'responses')
124
129
  completeResponseSignatures(blocks, content);
125
- return { blocks, callIds, trusted: true };
130
+ return { blocks, callIds, trusted: true, foreign: false };
126
131
  }
127
132
  catch (error) {
128
133
  warn?.(`OpenCode history: ${error instanceof Error ? error.message : 'invalid replay'}; retaining message content`);
@@ -22,7 +22,7 @@ import { ActivityTracker } from './status.js';
22
22
  import { feedStreamFrame } from './compat/assistant-stream.js';
23
23
  import { createActivityProjection, ACTIVITY_PROJECTION_KEY } from './projection.js';
24
24
  import { registerActivityEventType } from './registration.js';
25
- import { langNow, setLangOverride, t } from './lang.js';
25
+ import { NARRATE_INSTRUCTION, langNow, setLangOverride } from './lang.js';
26
26
  import { DEFAULT_PRESET } from './frames.js';
27
27
  import { featureOn } from './config.js';
28
28
  export const name = 'working-activity';
@@ -100,16 +100,14 @@ export function apply(ctx, config = {}) {
100
100
  const prompt = ctx.get('tuiPrompt', false);
101
101
  const promptHandle = prompt?.register('activity', undefined);
102
102
  // The `⏵` self-narration contract rides the stable system-prompt sections:
103
- // injected when the systemPrompt service is composed (agent assemblies
104
- // always mount it), removed with this fiber. The text is resolved at every
105
- // assembly in the live language, so a `/lang` switch applies to the next
106
- // turn without rebuilding the agent.
103
+ // injected when the systemPrompt service is composed and removed with this
104
+ // fiber. Model instructions stay in English independently of UI settings.
107
105
  if (resolved.narrate) {
108
106
  ctx.inject(['systemPrompt'], (promptCtx) => {
109
107
  promptCtx.systemPrompt.section({
110
108
  name: 'working-activity:narrate',
111
109
  order: 60,
112
- text: () => t('narrate-instruction'),
110
+ text: NARRATE_INSTRUCTION,
113
111
  });
114
112
  });
115
113
  }
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * The plugin follows the dsh-tui UI language without importing it: the same
5
5
  * chain dsh-tui resolves (`DSH_TUI_LANG` env → `~/.dsh-tui/lang.json` → OS
6
- * locale → zh) is read here directly, so a `/lang en|zh` switch (or the
7
- * /settings language pick) hot-swaps this plugin's narration and status-line
8
- * copy on the next render tick.
6
+ * locale → en) is read here directly, so a `/lang en|zh` switch (or the
7
+ * /settings language pick) hot-swaps rendered status-line copy. Model-facing
8
+ * narration instructions are locale-independent.
9
9
  *
10
10
  * Resolution order:
11
11
  * 1. `setLangOverride()` — a plugin-level `lang: zh|en` config key
@@ -15,7 +15,7 @@
15
15
  * so the per-tick status render never re-reads an unchanged file.
16
16
  * 4. OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`); POSIX/C means
17
17
  * "no locale selected" and maps to English.
18
- * 5. `zh` — the original hard-coded language.
18
+ * 5. `en` — the fallback for unsupported or absent locales.
19
19
  *
20
20
  * The dictionary is a flat key → per-language string map; `t(key, params)`
21
21
  * substitutes `{{name}}` placeholders. Missing keys render the key itself so
@@ -31,10 +31,12 @@ export declare function withProgressLang<T>(lang: Lang, render: () => T): T;
31
31
  export declare function terminalProgressLang(): Lang;
32
32
  /** Detect only confident language signals in user-authored prose. */
33
33
  export declare function detectInputLanguage(input: string): Lang | undefined;
34
+ /** Model instructions never inherit the interface or terminal language. */
35
+ export declare const NARRATE_INSTRUCTION = "[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: \u23F5 a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one \u23F5 line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: \u23F5 Fixing the login page styles, \u23F5 Investigating the error, \u23F5 Running validation for the patch. Update it when the task changes. Write the status description in the same response language chosen for the user request; use English when unclear.";
34
36
  declare const dict: {
35
37
  readonly 'narrate-instruction': {
36
- readonly zh: "[状态栏] 你有一个状态栏展示给用户。【必须】在每个步骤/子任务开始时(不只是调用工具前),在回复正文的最前面单独写一行:⏵ 你在做的具体事情(不超过20字),然后换行继续正常回复。整轮回复只写一行 ⏵,不要重复。信息为主——让人一眼知道你在干什么,风格自然、可以带点俏皮。例:⏵ 修复登录页样式、⏵ 查一下报错原因、⏵ 给补丁跑个验证。切换任务时必须更新。";
37
- readonly en: "[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes.";
38
+ readonly zh: "[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes. Write the status description in the same response language chosen for the user request; use English when unclear.";
39
+ readonly en: "[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes. Write the status description in the same response language chosen for the user request; use English when unclear.";
38
40
  };
39
41
  /** Plain (non-playful) phase labels. */
40
42
  readonly 'waiting-label': {
@@ -132,9 +134,9 @@ export declare function readLangFile(nowMs?: number): Lang | undefined;
132
134
  export declare function invalidateLangCache(): void;
133
135
  /**
134
136
  * Guess the language from the OS locale (`LC_ALL`, `LC_MESSAGES`, `LANG`),
135
- * defaulting to `zh`. POSIX/C means "no locale selected" and conventionally
137
+ * defaulting to `en`. POSIX/C means "no locale selected" and conventionally
136
138
  * maps to English (what CI runners report). An absent locale variable
137
- * (typical on Windows) defaults to `zh`.
139
+ * (typical on Windows) defaults to `en`.
138
140
  */
139
141
  export declare function detectLocaleLang(): Lang;
140
142
  export {};
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * The plugin follows the dsh-tui UI language without importing it: the same
5
5
  * chain dsh-tui resolves (`DSH_TUI_LANG` env → `~/.dsh-tui/lang.json` → OS
6
- * locale → zh) is read here directly, so a `/lang en|zh` switch (or the
7
- * /settings language pick) hot-swaps this plugin's narration and status-line
8
- * copy on the next render tick.
6
+ * locale → en) is read here directly, so a `/lang en|zh` switch (or the
7
+ * /settings language pick) hot-swaps rendered status-line copy. Model-facing
8
+ * narration instructions are locale-independent.
9
9
  *
10
10
  * Resolution order:
11
11
  * 1. `setLangOverride()` — a plugin-level `lang: zh|en` config key
@@ -15,7 +15,7 @@
15
15
  * so the per-tick status render never re-reads an unchanged file.
16
16
  * 4. OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`); POSIX/C means
17
17
  * "no locale selected" and maps to English.
18
- * 5. `zh` — the original hard-coded language.
18
+ * 5. `en` — the fallback for unsupported or absent locales.
19
19
  *
20
20
  * The dictionary is a flat key → per-language string map; `t(key, params)`
21
21
  * substitutes `{{name}}` placeholders. Missing keys render the key itself so
@@ -62,12 +62,11 @@ export function detectInputLanguage(input) {
62
62
  }
63
63
  /** The dsh-tui prefs file this plugin mirrors (shared language contract). */
64
64
  const LANG_FILE = join(homedir(), '.dsh-tui', 'lang.json');
65
+ /** Model instructions never inherit the interface or terminal language. */
66
+ export const NARRATE_INSTRUCTION = '[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes. Write the status description in the same response language chosen for the user request; use English when unclear.';
65
67
  const dict = {
66
- // ── ⏵ self-narration contract (system prompt, /lang aware) ──────────
67
- 'narrate-instruction': {
68
- zh: '[状态栏] 你有一个状态栏展示给用户。【必须】在每个步骤/子任务开始时(不只是调用工具前),在回复正文的最前面单独写一行:⏵ 你在做的具体事情(不超过20字),然后换行继续正常回复。整轮回复只写一行 ⏵,不要重复。信息为主——让人一眼知道你在干什么,风格自然、可以带点俏皮。例:⏵ 修复登录页样式、⏵ 查一下报错原因、⏵ 给补丁跑个验证。切换任务时必须更新。',
69
- en: '[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes.',
70
- },
68
+ // Retain the existing translation key without localizing model instructions.
69
+ 'narrate-instruction': { zh: NARRATE_INSTRUCTION, en: NARRATE_INSTRUCTION },
71
70
  // ── status-line structural copy ─────────────────────────────────────
72
71
  /** Plain (non-playful) phase labels. */
73
72
  'waiting-label': { zh: '等待模型响应', en: 'Waiting for model', ja: 'モデルの応答待ち' },
@@ -189,9 +188,9 @@ let cachedLang;
189
188
  let lastProbeAt = 0;
190
189
  /**
191
190
  * Guess the language from the OS locale (`LC_ALL`, `LC_MESSAGES`, `LANG`),
192
- * defaulting to `zh`. POSIX/C means "no locale selected" and conventionally
191
+ * defaulting to `en`. POSIX/C means "no locale selected" and conventionally
193
192
  * maps to English (what CI runners report). An absent locale variable
194
- * (typical on Windows) defaults to `zh`.
193
+ * (typical on Windows) defaults to `en`.
195
194
  */
196
195
  export function detectLocaleLang() {
197
196
  const raw = process.env.LC_ALL ||
@@ -205,5 +204,5 @@ export function detectLocaleLang() {
205
204
  return 'en';
206
205
  if (locale === 'c' || locale === 'posix')
207
206
  return 'en';
208
- return 'zh';
207
+ return 'en';
209
208
  }
@@ -30,7 +30,7 @@ import type { TrackerConfig } from './status.js'
30
30
  import { feedStreamFrame } from './compat/assistant-stream.js'
31
31
  import { createActivityProjection, ACTIVITY_PROJECTION_KEY } from './projection.js'
32
32
  import { registerActivityEventType } from './registration.js'
33
- import { langNow, setLangOverride, t } from './lang.js'
33
+ import { NARRATE_INSTRUCTION, langNow, setLangOverride, t } from './lang.js'
34
34
  import { DEFAULT_PRESET } from './frames.js'
35
35
  import { featureOn, type FeatureFlag } from './config.js'
36
36
  import type { ActivityState } from './status.js'
@@ -211,16 +211,14 @@ export function apply(ctx: Context, config: Config = {}): void {
211
211
  const promptHandle = prompt?.register('activity', undefined)
212
212
 
213
213
  // The `⏵` self-narration contract rides the stable system-prompt sections:
214
- // injected when the systemPrompt service is composed (agent assemblies
215
- // always mount it), removed with this fiber. The text is resolved at every
216
- // assembly in the live language, so a `/lang` switch applies to the next
217
- // turn without rebuilding the agent.
214
+ // injected when the systemPrompt service is composed and removed with this
215
+ // fiber. Model instructions stay in English independently of UI settings.
218
216
  if (resolved.narrate) {
219
217
  ctx.inject(['systemPrompt'], (promptCtx) => {
220
218
  promptCtx.systemPrompt.section({
221
219
  name: 'working-activity:narrate',
222
220
  order: 60,
223
- text: () => t('narrate-instruction'),
221
+ text: NARRATE_INSTRUCTION,
224
222
  })
225
223
  })
226
224
  }
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * The plugin follows the dsh-tui UI language without importing it: the same
5
5
  * chain dsh-tui resolves (`DSH_TUI_LANG` env → `~/.dsh-tui/lang.json` → OS
6
- * locale → zh) is read here directly, so a `/lang en|zh` switch (or the
7
- * /settings language pick) hot-swaps this plugin's narration and status-line
8
- * copy on the next render tick.
6
+ * locale → en) is read here directly, so a `/lang en|zh` switch (or the
7
+ * /settings language pick) hot-swaps rendered status-line copy. Model-facing
8
+ * narration instructions are locale-independent.
9
9
  *
10
10
  * Resolution order:
11
11
  * 1. `setLangOverride()` — a plugin-level `lang: zh|en` config key
@@ -15,7 +15,7 @@
15
15
  * so the per-tick status render never re-reads an unchanged file.
16
16
  * 4. OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`); POSIX/C means
17
17
  * "no locale selected" and maps to English.
18
- * 5. `zh` — the original hard-coded language.
18
+ * 5. `en` — the fallback for unsupported or absent locales.
19
19
  *
20
20
  * The dictionary is a flat key → per-language string map; `t(key, params)`
21
21
  * substitutes `{{name}}` placeholders. Missing keys render the key itself so
@@ -67,13 +67,12 @@ export function detectInputLanguage(input: string): Lang | undefined {
67
67
  /** The dsh-tui prefs file this plugin mirrors (shared language contract). */
68
68
  const LANG_FILE = join(homedir(), '.dsh-tui', 'lang.json')
69
69
 
70
- const dict = {
71
- // ── ⏵ self-narration contract (system prompt, /lang aware) ──────────
72
- 'narrate-instruction': {
73
- zh: '[状态栏] 你有一个状态栏展示给用户。【必须】在每个步骤/子任务开始时(不只是调用工具前),在回复正文的最前面单独写一行:⏵ 你在做的具体事情(不超过20字),然后换行继续正常回复。整轮回复只写一行 ⏵,不要重复。信息为主——让人一眼知道你在干什么,风格自然、可以带点俏皮。例:⏵ 修复登录页样式、⏵ 查一下报错原因、⏵ 给补丁跑个验证。切换任务时必须更新。',
74
- en: '[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes.',
75
- },
70
+ /** Model instructions never inherit the interface or terminal language. */
71
+ export const NARRATE_INSTRUCTION = '[Status line] You have a status line visible to the user. [Required] At the start of each step or subtask (not only before tool calls), write exactly one standalone line at the very beginning of your response: ⏵ a concrete description of what you are doing (20 words max), then continue with the normal response on the next line. Write only one ⏵ line per response and do not repeat it. Prioritize information so the user can understand the current work at a glance; keep the style natural and optionally playful. Examples: ⏵ Fixing the login page styles, ⏵ Investigating the error, ⏵ Running validation for the patch. Update it when the task changes. Write the status description in the same response language chosen for the user request; use English when unclear.'
76
72
 
73
+ const dict = {
74
+ // Retain the existing translation key without localizing model instructions.
75
+ 'narrate-instruction': { zh: NARRATE_INSTRUCTION, en: NARRATE_INSTRUCTION },
77
76
  // ── status-line structural copy ─────────────────────────────────────
78
77
  /** Plain (non-playful) phase labels. */
79
78
  'waiting-label': { zh: '等待模型响应', en: 'Waiting for model', ja: 'モデルの応答待ち' },
@@ -203,9 +202,9 @@ let lastProbeAt = 0
203
202
 
204
203
  /**
205
204
  * Guess the language from the OS locale (`LC_ALL`, `LC_MESSAGES`, `LANG`),
206
- * defaulting to `zh`. POSIX/C means "no locale selected" and conventionally
205
+ * defaulting to `en`. POSIX/C means "no locale selected" and conventionally
207
206
  * maps to English (what CI runners report). An absent locale variable
208
- * (typical on Windows) defaults to `zh`.
207
+ * (typical on Windows) defaults to `en`.
209
208
  */
210
209
  export function detectLocaleLang(): Lang {
211
210
  const raw =
@@ -217,5 +216,5 @@ export function detectLocaleLang(): Lang {
217
216
  if (locale.startsWith('zh')) return 'zh'
218
217
  if (locale.startsWith('en')) return 'en'
219
218
  if (locale === 'c' || locale === 'posix') return 'en'
220
- return 'zh'
219
+ return 'en'
221
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askdkc/dsh-cli",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
4
4
  "description": "Interactive terminal interface for DeepSeek Harness agents, sessions and tools.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -128,7 +128,7 @@
128
128
  "tui": "node --import tsx/esm scripts/run.ts",
129
129
  "smoke": "node --import tsx/esm scripts/smoke.tsx",
130
130
  "verify:build": "node scripts/run-verify-build.mjs",
131
- "verify:build:inner": "npm run verify:boundary && npm run verify:contract && npm run verify:herdr && npm run verify:manifest-deps && npm run verify:patch-surface && npm run verify:web-coexistence && npm run verify:plugin-spec && npm run verify:plugin-grants && npm run verify:plugin-storage && npm run verify:plugin-messages && npm run verify:plugin-ledger && npm run verify:plugin-commands && npm run verify:plugin-negotiation && npm run verify:plugin-lifecycle && npm run verify:runtime-themes && npm run verify:packaged-presets && npm run verify:history-search && npm run verify:initial-prompt && npm run verify:minimal-preset-tools && npm run verify:liangshen-bootstrap && npm run verify:inject-channel && npm run verify:wheel-selection && npm run verify:win32-protocol && npm run verify:selection-resize && npm run verify:selection-stale-guard && npm run verify:liangshen-instruction-hint && npm run verify:pointer-events && npm run verify:terminal-images && npm run verify:overlay-occlusion && npm run verify:transcript-images && npm run verify:image-preview && npm run verify:backdrop-dim && npm run verify:composer-image-tokens && npm run verify:image-downsample && npm run verify:chat-overlay && npm run verify:i18n && npm run verify:approval-visibility && npm run verify:adapter-skeleton && npm run verify:adapter-ports && npm run verify:adapter-effect-class && npm run verify:adapter-shadow && npm run verify:adapter-descriptor && npm run verify:adapter-upstream-driver && npm run verify:adapter-kernel-runtime && npm run verify:adapter-live-probes && npm run verify:adapter-slices && npm run verify:adapter-channel && npm run verify:binding-transaction && npm run verify:session-extraction && npm run verify:rewind-edit && npm run verify:model-mode-workspace-extraction && npm run verify:model-lifecycle-fences && npm run verify:reports-metadata && npm run verify:background-extraction && npm run verify:plugin-catalog-extraction && npm run verify:session-reset && npm run verify:channel-ui && npm run verify:adapter-detection && npm run verify:adapter-replay-harness && npm run verify:adapter-channel-conformance && npm run verify:protocol-single-source && npm run verify:compat-removal && npm run verify:terminal-images-sixel && npm run verify:sixel-transcript && npm run verify:migrate-sessions && npm run verify:fixed-window && npm run verify:source-hygiene && npm run verify:renderer-primitives && npm run verify:product-migration && npm run verify:spinner-identity && npm run verify:table-layout && npm run verify:mermaid-diagram && npm run verify:btw && npm run verify:session-mounts && npm run verify:progress-language",
131
+ "verify:build:inner": "npm run verify:boundary && npm run verify:contract && npm run verify:herdr && npm run verify:manifest-deps && npm run verify:patch-surface && npm run verify:web-coexistence && npm run verify:plugin-spec && npm run verify:plugin-grants && npm run verify:plugin-storage && npm run verify:plugin-messages && npm run verify:plugin-ledger && npm run verify:plugin-commands && npm run verify:plugin-negotiation && npm run verify:plugin-lifecycle && npm run verify:runtime-themes && npm run verify:packaged-presets && npm run verify:history-search && npm run verify:initial-prompt && npm run verify:minimal-preset-tools && npm run verify:liangshen-bootstrap && npm run verify:inject-channel && npm run verify:wheel-selection && npm run verify:win32-protocol && npm run verify:selection-resize && npm run verify:selection-stale-guard && npm run verify:liangshen-instruction-hint && npm run verify:pointer-events && npm run verify:terminal-images && npm run verify:overlay-occlusion && npm run verify:transcript-images && npm run verify:image-preview && npm run verify:backdrop-dim && npm run verify:composer-image-tokens && npm run verify:image-downsample && npm run verify:chat-overlay && npm run verify:i18n && npm run verify:approval-visibility && npm run verify:adapter-skeleton && npm run verify:adapter-ports && npm run verify:adapter-effect-class && npm run verify:adapter-shadow && npm run verify:adapter-descriptor && npm run verify:adapter-upstream-driver && npm run verify:adapter-kernel-runtime && npm run verify:adapter-live-probes && npm run verify:adapter-slices && npm run verify:adapter-channel && npm run verify:binding-transaction && npm run verify:session-extraction && npm run verify:rewind-edit && npm run verify:model-mode-workspace-extraction && npm run verify:model-lifecycle-fences && npm run verify:reports-metadata && npm run verify:background-extraction && npm run verify:plugin-catalog-extraction && npm run verify:session-reset && npm run verify:channel-ui && npm run verify:adapter-detection && npm run verify:adapter-replay-harness && npm run verify:adapter-channel-conformance && npm run verify:protocol-single-source && npm run verify:compat-removal && npm run verify:terminal-images-sixel && npm run verify:sixel-transcript && npm run verify:migrate-sessions && npm run verify:fixed-window && npm run verify:source-hygiene && npm run verify:renderer-primitives && npm run verify:product-migration && npm run verify:spinner-identity && npm run verify:table-layout && npm run verify:mermaid-diagram && npm run verify:btw && npm run verify:session-mounts && npm run verify:progress-language && npm run verify:response-language",
132
132
  "verify:boundary": "node --import tsx/esm scripts/verify-adapter-boundary.ts",
133
133
  "verify:i18n": "node --import tsx/esm scripts/verify-i18n.ts",
134
134
  "verify:contract": "node --import tsx/esm scripts/verify-upstream-contract.ts",
@@ -230,6 +230,7 @@
230
230
  "verify:activity-store": "node --import tsx/esm scripts/verify-activity-store.ts",
231
231
  "verify:activity-store-render": "node --import tsx/esm scripts/verify-activity-store-render.tsx",
232
232
  "verify:activity-ownership": "node --import tsx/esm scripts/verify-activity-ownership.ts",
233
+ "verify:response-language": "node --import tsx/esm scripts/verify-response-language.mjs",
233
234
  "verify:progress-language": "node --import tsx/esm scripts/verify-progress-language.mjs",
234
235
  "verify:opencode-profile": "node scripts/verify-opencode-profile.mjs",
235
236
  "verify:upstream-source": "node scripts/verify-upstream-source.mjs"
@@ -76,7 +76,8 @@
76
76
  config: !!js >-
77
77
  (() => {
78
78
  const shared = { complete: true, includeRuntimeContext: false }
79
- const persona = 'You are a helpful software engineer assistant.'
79
+ const policy = process.getBuiltinModule('node:fs').readFileSync(new URL('../response-language.txt', ctx.baseUrl), 'utf8').trim()
80
+ const persona = 'You are a helpful software engineer assistant.\n\n' + policy
80
81
  try {
81
82
  const require = process.getBuiltinModule('node:module').createRequire(ctx.baseUrl)
82
83
  const fs = process.getBuiltinModule('node:fs')
@@ -0,0 +1,5 @@
1
+ Response language policy:
2
+ Use, in order: (1) the user's explicit language request for this task; (2) an explicit continuing language preference from the same conversation; (3) the clearly identifiable language of the current user-authored request; otherwise English.
3
+ If the language is unclear, respond in English. Ask for clarification in English only when the task itself needs clarification. Ambiguous short text such as "chinn korone" or "OK", identifiers, numbers, and code alone do not establish a language. Do not carry forward a previously inferred language when the current request is unclear. Recognizable languages, including Japanese and Chinese, remain supported; Latin script alone does not mean English.
4
+ Apply this rule to prose, progress narration, and every user-facing question header, question, option label, and option description.
5
+ Do not infer the response language from UI settings, OS locale, instruction prose, wrappers, quoted text, attachments, files, tool output, or prior assistant replies. These are not user language preferences. An explicit user language instruction still applies. For delegated work, follow the originating user's language request rather than the language of the generated delegation wrapper.