dsh-think-translate 1.0.11 → 1.0.12

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 (2) hide show
  1. package/lib/client.js +56 -2
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -517,8 +517,29 @@ window.__ModuleLoader__.load({
517
517
  class XBoundary extends Component {
518
518
  constructor(p) { super(p); this.state = { err: null }; }
519
519
  static getDerivedStateFromError(e) { return { err: e }; }
520
+ componentDidCatch(err) {
521
+ // The boundary only surfaces the message inline; log the full
522
+ // error so the next crash is pinpointable from the browser
523
+ // console (2026-09-03).
524
+ try {
525
+ if (typeof console !== "undefined" && console.error) {
526
+ console.error("[xlate] render error:", err && err.stack ? err.stack : err);
527
+ }
528
+ } catch (e) {}
529
+ }
520
530
  render() {
521
531
  if (this.state.err) {
532
+ var fb = this.props.fallback;
533
+ if (fb !== null && fb !== undefined) {
534
+ // Caller-supplied original-content fallback: a crashed
535
+ // block must show its original text, never blank the
536
+ // answer (2026-09-03: a 0.1.2-alpha renderer threw while
537
+ // composing an answer and the whole answer was replaced
538
+ // by the bare "[xlate] ..." line).
539
+ return createElement("div", null,
540
+ createElement("div", { className: "xl-warn" }, "[xlate] " + String(this.state.err && this.state.err.message ? this.state.err.message : this.state.err)),
541
+ fb);
542
+ }
522
543
  return createElement("div", { className: "xl-err" }, "[xlate] " + String(this.state.err && this.state.err.message ? this.state.err.message : this.state.err));
523
544
  }
524
545
  return this.props.children;
@@ -806,7 +827,7 @@ window.__ModuleLoader__.load({
806
827
  var block = blocks[i];
807
828
  if (!block) continue;
808
829
  if (block.kind === "text") {
809
- rendered.push(createElement(TextBlock, { key: "t" + i, text: block.text, streaming: streaming }));
830
+ rendered.push(createElement(TextBlockSafe, { key: "t" + i, text: block.text, streaming: streaming }));
810
831
  } else if (block.kind === "reasoning") {
811
832
  rendered.push(createElement(ThinkRow, { key: "r" + i, text: block.text, running: streaming && i === last, eager: eager }));
812
833
  } else if (block.kind === "image") {
@@ -825,6 +846,39 @@ window.__ModuleLoader__.load({
825
846
  interrupted ? createElement("span", { className: "xl-warn" }, (props.t && props.t("message.stopped")) || tt.stopped) : null);
826
847
  }
827
848
 
849
+ function originalBlocksText(blocks) {
850
+ var parts = [];
851
+ for (var i = 0; i < blocks.length; i++) {
852
+ var b = blocks[i];
853
+ if (!b) continue;
854
+ if ((b.kind === "text" || b.kind === "reasoning") && typeof b.text === "string" && b.text.trim()) parts.push(b.text);
855
+ }
856
+ return parts;
857
+ }
858
+ // Per-text-block fuse: the official MarkdownText path stays the normal
859
+ // renderer for streaming and settled text alike. If it throws for a
860
+ // specific block, only that block degrades to its ORIGINAL text through
861
+ // the crash-proof Markdownish renderer (plus a one-line warning) instead
862
+ // of the whole answer being replaced by the [xlate] error line.
863
+ function TextBlockSafe(props) {
864
+ return createElement(XBoundary,
865
+ { fallback: createElement(Markdownish, { text: props.text }) },
866
+ createElement(TextBlock, props));
867
+ }
868
+ // Whole-assistant fuse: if scaffolding above the block loop throws
869
+ // (hooks, turn-data, image loader...), fall back to the original prose
870
+ // of every text/reasoning block so the answer never vanishes.
871
+ function AssistantViewSafe(props) {
872
+ var fb = null;
873
+ try {
874
+ var node = props && props.node;
875
+ var blocks = node && node.data && Array.isArray(node.data.blocks) ? node.data.blocks : [];
876
+ var parts = originalBlocksText(blocks);
877
+ if (parts.length) fb = createElement("div", null, createElement(Markdownish, { text: parts.join("\n\n") }));
878
+ } catch (e) { fb = null; }
879
+ return createElement(XBoundary, { fallback: fb }, createElement(AssistantView, props));
880
+ }
881
+
828
882
  function planSummaryOf(todos) {
829
883
  var done = 0, active = null, extra = 0;
830
884
  for (var i = 0; i < todos.length; i++) {
@@ -1287,7 +1341,7 @@ window.__ModuleLoader__.load({
1287
1341
  // shows untranslated (2026-08-24).
1288
1342
  { name: "conversation.chat.node", key: "assistant-step", locale: "conversation", priority: -1 },
1289
1343
  function (props) {
1290
- return createElement(XBoundary, null, createElement(AssistantView, props));
1344
+ return createElement(AssistantViewSafe, props);
1291
1345
  });
1292
1346
  diag.slots.conversation = "registered";
1293
1347
  return d;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-think-translate",
3
3
  "description": "Display-layer translation for the DSH web app: thinking chain, task cards, and optional answer text, in 8 target languages (local Ollama / Google / Bing, fail-open)",
4
- "version": "1.0.11",
4
+ "version": "1.0.12",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {