reasonix 0.34.1 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dashboard/app.css +16 -14
  2. package/dashboard/dist/app.js +35 -15
  3. package/dashboard/dist/app.js.map +1 -1
  4. package/dist/cli/{chat-TD6GR3QK.js → chat-AB5D7I3V.js} +9 -9
  5. package/dist/cli/{chunk-EINEIIIW.js → chunk-GPHBJWCV.js} +278 -91
  6. package/dist/cli/chunk-GPHBJWCV.js.map +1 -0
  7. package/dist/cli/{chunk-F3ILWP2L.js → chunk-IDP65VCC.js} +2 -2
  8. package/dist/cli/{chunk-OERAGRJX.js → chunk-JJTOZPM3.js} +2 -2
  9. package/dist/cli/{chunk-U3V2ZQ5J.js → chunk-KJQIA4US.js} +6 -2
  10. package/dist/cli/chunk-KJQIA4US.js.map +1 -0
  11. package/dist/cli/{chunk-LNTORE5K.js → chunk-N2IC4XDL.js} +149 -35
  12. package/dist/cli/chunk-N2IC4XDL.js.map +1 -0
  13. package/dist/cli/{chunk-SA4UGZPG.js → chunk-RJ5GUVS2.js} +6 -1
  14. package/dist/cli/chunk-RJ5GUVS2.js.map +1 -0
  15. package/dist/cli/{chunk-Q36KBLSU.js → chunk-SN7YH6FC.js} +125 -1
  16. package/dist/cli/chunk-SN7YH6FC.js.map +1 -0
  17. package/dist/cli/{chunk-6TMHAK5D.js → chunk-ZU45XW3P.js} +2 -2
  18. package/dist/cli/code-XBEFHXVM.js +433 -0
  19. package/dist/cli/code-XBEFHXVM.js.map +1 -0
  20. package/dist/cli/{doctor-YASM64X6.js → doctor-A565GMWD.js} +4 -4
  21. package/dist/cli/index.js +15 -15
  22. package/dist/cli/{prompt-V47QKSAR.js → prompt-YEKXMNNV.js} +3 -3
  23. package/dist/cli/{replay-JEDLU7F2.js → replay-P2WC5N5X.js} +2 -2
  24. package/dist/cli/replay-P2WC5N5X.js.map +1 -0
  25. package/dist/cli/{run-NHD2RSTD.js → run-QBWJETS3.js} +6 -6
  26. package/dist/cli/{server-MC4A4WAJ.js → server-SMLVXIW4.js} +5 -5
  27. package/dist/cli/{sessions-ZHWJEW4L.js → sessions-55RIZVWG.js} +6 -6
  28. package/dist/cli/{setup-DK43MT47.js → setup-QXMONZ4P.js} +2 -2
  29. package/dist/cli/{version-O362UKPM.js → version-Q2HA3AAC.js} +6 -6
  30. package/dist/index.d.ts +5 -0
  31. package/dist/index.js +273 -31
  32. package/dist/index.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/cli/chunk-EINEIIIW.js.map +0 -1
  35. package/dist/cli/chunk-LNTORE5K.js.map +0 -1
  36. package/dist/cli/chunk-Q36KBLSU.js.map +0 -1
  37. package/dist/cli/chunk-SA4UGZPG.js.map +0 -1
  38. package/dist/cli/chunk-U3V2ZQ5J.js.map +0 -1
  39. package/dist/cli/code-TGUOQBRJ.js +0 -153
  40. package/dist/cli/code-TGUOQBRJ.js.map +0 -1
  41. package/dist/cli/replay-JEDLU7F2.js.map +0 -1
  42. /package/dist/cli/{chat-TD6GR3QK.js.map → chat-AB5D7I3V.js.map} +0 -0
  43. /package/dist/cli/{chunk-F3ILWP2L.js.map → chunk-IDP65VCC.js.map} +0 -0
  44. /package/dist/cli/{chunk-OERAGRJX.js.map → chunk-JJTOZPM3.js.map} +0 -0
  45. /package/dist/cli/{chunk-6TMHAK5D.js.map → chunk-ZU45XW3P.js.map} +0 -0
  46. /package/dist/cli/{doctor-YASM64X6.js.map → doctor-A565GMWD.js.map} +0 -0
  47. /package/dist/cli/{prompt-V47QKSAR.js.map → prompt-YEKXMNNV.js.map} +0 -0
  48. /package/dist/cli/{run-NHD2RSTD.js.map → run-QBWJETS3.js.map} +0 -0
  49. /package/dist/cli/{server-MC4A4WAJ.js.map → server-SMLVXIW4.js.map} +0 -0
  50. /package/dist/cli/{sessions-ZHWJEW4L.js.map → sessions-55RIZVWG.js.map} +0 -0
  51. /package/dist/cli/{setup-DK43MT47.js.map → setup-QXMONZ4P.js.map} +0 -0
  52. /package/dist/cli/{version-O362UKPM.js.map → version-Q2HA3AAC.js.map} +0 -0
@@ -34,7 +34,7 @@ import {
34
34
  toWholeFileEditBlock,
35
35
  walkFilesStream,
36
36
  webFetch
37
- } from "./chunk-LNTORE5K.js";
37
+ } from "./chunk-N2IC4XDL.js";
38
38
  import {
39
39
  McpClient,
40
40
  SseTransport,
@@ -50,7 +50,7 @@ import {
50
50
  } from "./chunk-XHQIK7B6.js";
51
51
  import {
52
52
  MemoryStore
53
- } from "./chunk-6TMHAK5D.js";
53
+ } from "./chunk-ZU45XW3P.js";
54
54
  import {
55
55
  KeystrokeProvider,
56
56
  SingleSelect,
@@ -71,7 +71,7 @@ import {
71
71
  } from "./chunk-MHDNZXJJ.js";
72
72
  import {
73
73
  runDoctorChecks
74
- } from "./chunk-F3ILWP2L.js";
74
+ } from "./chunk-IDP65VCC.js";
75
75
  import {
76
76
  countTokens
77
77
  } from "./chunk-DAEAAVDF.js";
@@ -97,7 +97,7 @@ import {
97
97
  resolveSlashAlias,
98
98
  savePlanState,
99
99
  suggestSlashCommands
100
- } from "./chunk-SA4UGZPG.js";
100
+ } from "./chunk-RJ5GUVS2.js";
101
101
  import {
102
102
  eventLogPath,
103
103
  openEventSink
@@ -119,7 +119,7 @@ import {
119
119
  SkillStore,
120
120
  memoryEnabled,
121
121
  readProjectMemory
122
- } from "./chunk-U3V2ZQ5J.js";
122
+ } from "./chunk-KJQIA4US.js";
123
123
  import {
124
124
  HOOK_EVENTS,
125
125
  formatHookOutcomeMessage,
@@ -127,7 +127,7 @@ import {
127
127
  loadHooks,
128
128
  projectSettingsPath,
129
129
  runHooks
130
- } from "./chunk-OERAGRJX.js";
130
+ } from "./chunk-JJTOZPM3.js";
131
131
  import {
132
132
  VERSION,
133
133
  compareVersions,
@@ -154,7 +154,7 @@ import {
154
154
  setLanguage,
155
155
  t,
156
156
  tObj
157
- } from "./chunk-Q36KBLSU.js";
157
+ } from "./chunk-SN7YH6FC.js";
158
158
  import {
159
159
  addProjectShellAllowed,
160
160
  clearProjectShellAllowed,
@@ -2376,7 +2376,12 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
2376
2376
  const doneCount = statusList.filter((s) => s === "done").length;
2377
2377
  const pct = Math.round(doneCount / total * 100);
2378
2378
  const showProgress = doneCount > 0;
2379
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Box12, null, /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, showProgress ? `${doneCount}/${total} done (${pct}%) \xB7 ${total} step${total === 1 ? "" : "s"}` : `${total} step${total === 1 ? "" : "s"}`)), /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, steps.map((step, i) => {
2379
+ return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Box12, null, /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, showProgress ? t(
2380
+ total === 1 ? "planFlow.stepList.counterDoneSingular" : "planFlow.stepList.counterDone",
2381
+ { done: doneCount, total, pct }
2382
+ ) : t(total === 1 ? "planFlow.stepList.counterSingular" : "planFlow.stepList.counter", {
2383
+ total
2384
+ }))), /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, steps.map((step, i) => {
2380
2385
  const status2 = statusList[i];
2381
2386
  const isLast = i === total - 1;
2382
2387
  const isCur = focusStepId === step.id;
@@ -2413,25 +2418,25 @@ function PlanCheckpointConfirmInner({
2413
2418
  const isLast = total > 0 && completed >= total;
2414
2419
  const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
2415
2420
  const subtitle = counter ? `${counter} \xB7 ${label}` : label;
2416
- return /* @__PURE__ */ React16.createElement(ApprovalCard, { tone: "ok", glyph: "\u26C1", title: "Checkpoint \u2014 step done", metaRight: subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ React16.createElement(Box13, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React16.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React16.createElement(
2421
+ return /* @__PURE__ */ React16.createElement(ApprovalCard, { tone: "ok", glyph: "\u26C1", title: t("planFlow.checkpoint.title"), metaRight: subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ React16.createElement(Box13, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React16.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React16.createElement(
2417
2422
  SingleSelect,
2418
2423
  {
2419
2424
  initialValue: isLast ? "stop" : "continue",
2420
2425
  items: [
2421
2426
  {
2422
2427
  value: "continue",
2423
- label: "Continue \u2014 run the next step",
2424
- hint: "Model resumes with the next step."
2428
+ label: t("planFlow.checkpoint.continue"),
2429
+ hint: t("planFlow.checkpoint.continueHint")
2425
2430
  },
2426
2431
  {
2427
2432
  value: "revise",
2428
- label: "Revise \u2014 give feedback before the next step",
2429
- hint: "Stay paused, type guidance; model adjusts the remaining plan."
2433
+ label: t("planFlow.checkpoint.revise"),
2434
+ hint: t("planFlow.checkpoint.reviseHint")
2430
2435
  },
2431
2436
  {
2432
2437
  value: "stop",
2433
- label: "Stop \u2014 end the plan here",
2434
- hint: "Model summarizes what was done and ends."
2438
+ label: t("planFlow.checkpoint.stop"),
2439
+ hint: t("planFlow.checkpoint.stopHint")
2435
2440
  }
2436
2441
  ],
2437
2442
  onSubmit: (v) => onChoose(v),
@@ -4886,53 +4891,89 @@ function SpanText({
4886
4891
  );
4887
4892
  }
4888
4893
 
4894
+ // src/cli/ui/plan-open-questions.ts
4895
+ var HEADER_RE = /^(#{1,6})\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear|待确认|开放问题|风险|未知|假设|不确定)(?:[\s::/、,,].*)?$/im;
4896
+ function extractOpenQuestionsSection(plan2) {
4897
+ const lines = plan2.split("\n");
4898
+ let startIdx = -1;
4899
+ let startLevel = 0;
4900
+ for (let i = 0; i < lines.length; i++) {
4901
+ const line = lines[i] ?? "";
4902
+ const m = line.match(HEADER_RE);
4903
+ if (m) {
4904
+ startIdx = i;
4905
+ startLevel = (m[1] ?? "#").length;
4906
+ break;
4907
+ }
4908
+ }
4909
+ if (startIdx === -1) return null;
4910
+ let endIdx = lines.length;
4911
+ for (let j = startIdx + 1; j < lines.length; j++) {
4912
+ const line = lines[j] ?? "";
4913
+ const lh = line.match(/^(#{1,6})\s+\S/);
4914
+ if (lh && (lh[1] ?? "").length <= startLevel) {
4915
+ endIdx = j;
4916
+ break;
4917
+ }
4918
+ }
4919
+ const block2 = lines.slice(startIdx, endIdx).join("\n").replace(/\s+$/g, "");
4920
+ return block2.length > 0 ? block2 : null;
4921
+ }
4922
+
4889
4923
  // src/cli/ui/PlanConfirm.tsx
4890
4924
  var PLAN_BODY_PREVIEW_LINES = 24;
4891
4925
  function PlanConfirmInner({ plan: plan2, steps, onChoose }) {
4892
4926
  const stepRows = steps?.length ?? 0;
4893
4927
  const hasSteps = stepRows > 0;
4928
+ const openQuestions = extractOpenQuestionsSection(plan2);
4894
4929
  const planLines = plan2.split("\n");
4895
4930
  const truncatedBody = planLines.length > PLAN_BODY_PREVIEW_LINES;
4896
4931
  const previewBody = truncatedBody ? planLines.slice(0, PLAN_BODY_PREVIEW_LINES).join("\n") : plan2;
4897
4932
  const previewRows = truncatedBody ? PLAN_BODY_PREVIEW_LINES : Math.min(planLines.length, PLAN_BODY_PREVIEW_LINES);
4898
4933
  const reservedFor = hasSteps ? stepRows : previewRows;
4899
- useReserveRows("modal", { min: 10, max: Math.max(16, reservedFor + 14) });
4900
- const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
4934
+ const oqRows = openQuestions ? openQuestions.split("\n").length : 0;
4935
+ useReserveRows("modal", { min: 10, max: Math.max(16, reservedFor + oqRows + 14) });
4936
+ const refineLabel = t("planFlow.picker.refine");
4937
+ const bannerTemplate = t("planFlow.openQuestionsBanner");
4938
+ const [bannerBefore, bannerAfter] = bannerTemplate.split("{refine}");
4901
4939
  return /* @__PURE__ */ React18.createElement(
4902
4940
  ApprovalCard,
4903
4941
  {
4904
4942
  tone: "accent",
4905
4943
  glyph: "\u229E",
4906
- title: "Approve plan",
4907
- metaRight: "awaiting",
4944
+ title: t("planFlow.approveCardTitle"),
4945
+ metaRight: t("planFlow.approveCardMetaRight"),
4908
4946
  metaRightColor: CARD.plan.color
4909
4947
  },
4910
- hasOpenQuestions ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1 }, /* @__PURE__ */ React18.createElement(Text15, { color: TONE.warn }, "\u25B2 the plan flags open questions or risks \u2014 pick ", /* @__PURE__ */ React18.createElement(Text15, { bold: true }, "refine"), " to write concrete answers before the model moves on.")) : null,
4911
- hasSteps ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(PlanStepList, { steps })) : plan2.trim().length > 0 ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(MarkdownView, { text: previewBody }), truncatedBody ? /* @__PURE__ */ React18.createElement(Text15, { color: FG.faint }, `\u2026 ${planLines.length - PLAN_BODY_PREVIEW_LINES} more line${planLines.length - PLAN_BODY_PREVIEW_LINES === 1 ? "" : "s"} above in scrollback`) : null) : null,
4948
+ openQuestions ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(Text15, { color: TONE.warn }, bannerBefore ?? "", /* @__PURE__ */ React18.createElement(Text15, { bold: true }, refineLabel), bannerAfter ?? ""), /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(Text15, { color: TONE.warn, bold: true }, t("planFlow.openQuestionsHeader")), /* @__PURE__ */ React18.createElement(MarkdownView, { text: openQuestions }))) : null,
4949
+ hasSteps ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(PlanStepList, { steps })) : plan2.trim().length > 0 ? /* @__PURE__ */ React18.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React18.createElement(MarkdownView, { text: previewBody }), truncatedBody ? /* @__PURE__ */ React18.createElement(Text15, { color: FG.faint }, t(
4950
+ planLines.length - PLAN_BODY_PREVIEW_LINES === 1 ? "planFlow.truncatedBodyMore" : "planFlow.truncatedBodyMorePlural",
4951
+ { n: planLines.length - PLAN_BODY_PREVIEW_LINES }
4952
+ )) : null) : null,
4912
4953
  /* @__PURE__ */ React18.createElement(
4913
4954
  SingleSelect,
4914
4955
  {
4915
- initialValue: hasOpenQuestions ? "refine" : "approve",
4956
+ initialValue: openQuestions ? "refine" : "approve",
4916
4957
  items: [
4917
4958
  {
4918
4959
  value: "approve",
4919
- label: "accept",
4920
- hint: "run it now, in order"
4960
+ label: t("planFlow.picker.accept"),
4961
+ hint: t("planFlow.picker.acceptHint")
4921
4962
  },
4922
4963
  {
4923
4964
  value: "refine",
4924
- label: "refine",
4925
- hint: "give the agent more guidance, draft a new plan"
4965
+ label: refineLabel,
4966
+ hint: t("planFlow.picker.refineHint")
4926
4967
  },
4927
4968
  {
4928
4969
  value: "revise",
4929
- label: "revise",
4930
- hint: "edit the plan inline before running (skip / reorder steps)"
4970
+ label: t("planFlow.picker.revise"),
4971
+ hint: t("planFlow.picker.reviseHint")
4931
4972
  },
4932
4973
  {
4933
4974
  value: "cancel",
4934
- label: "reject",
4935
- hint: "discard, agent will retry from scratch"
4975
+ label: t("planFlow.picker.reject"),
4976
+ hint: t("planFlow.picker.rejectHint")
4936
4977
  }
4937
4978
  ],
4938
4979
  onSubmit: (v) => onChoose(v),
@@ -4974,49 +5015,25 @@ function useElapsedSeconds() {
4974
5015
  }
4975
5016
 
4976
5017
  // src/cli/ui/PlanRefineInput.tsx
4977
- var MODES = {
4978
- approve: {
4979
- title: "approving \u2014 any last instructions?",
4980
- glyph: "\u25C7",
4981
- tone: "user",
4982
- cursorColor: CARD.user.color,
4983
- hint: "Answer questions the plan raised, add constraints, or just press Enter to approve as-is.",
4984
- blankHint: " (Enter with blank = approve without extra instructions.)"
4985
- },
4986
- refine: {
4987
- title: "refining \u2014 what should the model change?",
4988
- glyph: "\u270E",
4989
- tone: "warn",
4990
- cursorColor: CARD.warn.color,
4991
- hint: "Describe what's wrong or missing, or answer questions the plan raised.",
4992
- blankHint: " (Enter with blank = ask the model to list concrete questions.)"
4993
- },
4994
- reject: {
4995
- title: "rejecting \u2014 tell the model why (optional)",
4996
- glyph: "\u2717",
4997
- tone: "error",
4998
- cursorColor: CARD.error.color,
4999
- hint: "Say what the model got wrong about your goal, or what you actually want instead.",
5000
- blankHint: " (Enter with blank = cancel without explanation; the model will ask what you want.)"
5001
- },
5002
- "checkpoint-revise": {
5003
- title: "revising \u2014 what should change before the next step?",
5004
- glyph: "\u270E",
5005
- tone: "warn",
5006
- cursorColor: CARD.warn.color,
5007
- hint: "Scope change, skip steps, alternative approach \u2014 the model adjusts the remaining plan.",
5008
- blankHint: " (Enter with blank = continue with the current plan.)"
5009
- },
5010
- "choice-custom": {
5011
- title: "custom answer \u2014 type whatever fits",
5012
- glyph: "\u2325",
5013
- tone: "accent",
5014
- cursorColor: CARD.plan.color,
5015
- hint: "Free-form reply. The model reads it verbatim and proceeds \u2014 no need to match the listed options.",
5016
- blankHint: " (Enter with blank = ask the model what you actually want.)"
5017
- }
5018
+ var MODE_VISUALS = {
5019
+ approve: { glyph: "\u25C7", tone: "user", cursorColor: CARD.user.color },
5020
+ refine: { glyph: "\u270E", tone: "warn", cursorColor: CARD.warn.color },
5021
+ reject: { glyph: "\u2717", tone: "error", cursorColor: CARD.error.color },
5022
+ "checkpoint-revise": { glyph: "\u270E", tone: "warn", cursorColor: CARD.warn.color },
5023
+ "choice-custom": { glyph: "\u2325", tone: "accent", cursorColor: CARD.plan.color }
5018
5024
  };
5019
- function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
5025
+ function modeMeta(mode2) {
5026
+ const v = MODE_VISUALS[mode2];
5027
+ return {
5028
+ title: t(`planFlow.modes.${mode2}.title`),
5029
+ hint: t(`planFlow.modes.${mode2}.hint`),
5030
+ blankHint: t(`planFlow.modes.${mode2}.blankHint`),
5031
+ glyph: v.glyph,
5032
+ tone: v.tone,
5033
+ cursorColor: v.cursorColor
5034
+ };
5035
+ }
5036
+ function PlanRefineInput({ mode: mode2, questions, onSubmit, onCancel }) {
5020
5037
  const [value, setValue] = useState9("");
5021
5038
  useKeystroke((ev) => {
5022
5039
  if (ev.paste) {
@@ -5041,15 +5058,17 @@ function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
5041
5058
  });
5042
5059
  const tick = useTick();
5043
5060
  const cursorOn = Math.floor(tick / 4) % 2 === 0;
5044
- const meta = MODES[mode2];
5061
+ const meta = modeMeta(mode2);
5062
+ const showQuestions = mode2 === "refine" && !!questions && questions.trim().length > 0;
5045
5063
  return /* @__PURE__ */ React20.createElement(
5046
5064
  ApprovalCard,
5047
5065
  {
5048
5066
  tone: meta.tone,
5049
5067
  glyph: meta.glyph,
5050
5068
  title: meta.title,
5051
- footerHint: "\u23CE send \xB7 esc return to picker"
5069
+ footerHint: t("planFlow.refineFooter")
5052
5070
  },
5071
+ showQuestions ? /* @__PURE__ */ React20.createElement(Box16, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(Text16, { color: TONE.warn, bold: true }, t("planFlow.refineQuestionsHeading")), /* @__PURE__ */ React20.createElement(MarkdownView, { text: questions })) : null,
5053
5072
  /* @__PURE__ */ React20.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text16, { color: FG.sub }, meta.hint, value === "" ? meta.blankHint : "")),
5054
5073
  /* @__PURE__ */ React20.createElement(Box16, null, /* @__PURE__ */ React20.createElement(Text16, { color: meta.cursorColor, bold: true }, "\u203A "), /* @__PURE__ */ React20.createElement(Text16, null, value), /* @__PURE__ */ React20.createElement(Text16, { color: meta.cursorColor, bold: true }, cursorOn ? "\u258D" : " "))
5055
5074
  );
@@ -8842,6 +8861,7 @@ function ToolCard({ card }) {
8842
8861
  const cols = stdout?.columns ?? 80;
8843
8862
  const lineCells = Math.max(20, cols - 4);
8844
8863
  const argsLabel = formatArgsSummary(card.args);
8864
+ const subagentMarkdown = unwrapSubagentMarkdown(card);
8845
8865
  const allLines = card.output.length > 0 ? card.output.split("\n") : [];
8846
8866
  const tail = tailLinesFor(card.name);
8847
8867
  const truncated = allLines.length > tail;
@@ -8850,7 +8870,7 @@ function ToolCard({ card }) {
8850
8870
  const status2 = toolStatus(card);
8851
8871
  const headColor = headerColorFor(status2);
8852
8872
  const errColor = card.exitCode && card.exitCode !== 0 ? TONE.err : FG.sub;
8853
- const showBody = !card.rejected && visible.length > 0;
8873
+ const showBody = !card.rejected && (subagentMarkdown !== null || visible.length > 0);
8854
8874
  const meta = [];
8855
8875
  if (card.retry) {
8856
8876
  meta.push({ text: `\u21BB ${card.retry.attempt}/${card.retry.max}`, color: TONE.warn });
@@ -8869,7 +8889,7 @@ function ToolCard({ card }) {
8869
8889
  meta: meta.length > 0 ? meta : void 0,
8870
8890
  right: status2 === "running" ? /* @__PURE__ */ React48.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.brand, bold: true }) : void 0
8871
8891
  }
8872
- ), showBody && /* @__PURE__ */ React48.createElement(React48.Fragment, null, hidden > 0 ? /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `\u22EE ${hidden} earlier line${hidden === 1 ? "" : "s"} (use /tool to read full)`) : null, visible.map((line, i) => /* @__PURE__ */ React48.createElement(
8892
+ ), showBody && (subagentMarkdown !== null ? /* @__PURE__ */ React48.createElement(Markdown, { text: subagentMarkdown, width: lineCells }) : /* @__PURE__ */ React48.createElement(React48.Fragment, null, hidden > 0 ? /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `\u22EE ${hidden} earlier line${hidden === 1 ? "" : "s"} (use /tool to read full)`) : null, visible.map((line, i) => /* @__PURE__ */ React48.createElement(
8873
8893
  Text42,
8874
8894
  {
8875
8895
  key: `${card.id}:${hidden + i}`,
@@ -8877,7 +8897,21 @@ function ToolCard({ card }) {
8877
8897
  dimColor: !card.exitCode || card.exitCode === 0
8878
8898
  },
8879
8899
  clipToCells(line, lineCells) || " "
8880
- ))));
8900
+ )))));
8901
+ }
8902
+ function unwrapSubagentMarkdown(card) {
8903
+ if (card.name !== "spawn_subagent") return null;
8904
+ if (card.output.length === 0) return null;
8905
+ try {
8906
+ const parsed = JSON.parse(card.output);
8907
+ if (!parsed || typeof parsed !== "object") return null;
8908
+ const obj = parsed;
8909
+ if (obj.success !== true) return null;
8910
+ if (typeof obj.output !== "string") return null;
8911
+ return obj.output;
8912
+ } catch {
8913
+ return null;
8914
+ }
8881
8915
  }
8882
8916
  function toolStatus(card) {
8883
8917
  if (card.rejected) return "rejected";
@@ -9320,6 +9354,8 @@ function Countdown({ endsAt, color = TONE.brand }) {
9320
9354
  var RULE_PAD = 4;
9321
9355
  var RULE_MIN = 20;
9322
9356
  var WALLET_MIN_COLS = 90;
9357
+ var VERSION_MIN_COLS = 70;
9358
+ var FEEDBACK_HINT_MIN_COLS = 100;
9323
9359
  function StatusRow() {
9324
9360
  const status2 = useAgentState((s) => s.status);
9325
9361
  const session = useAgentState((s) => s.session);
@@ -9337,7 +9373,7 @@ function StatusRow() {
9337
9373
  balance: status2.balance,
9338
9374
  currency: status2.balanceCurrency
9339
9375
  }
9340
- )));
9376
+ ), cols >= VERSION_MIN_COLS && /* @__PURE__ */ React56.createElement(React56.Fragment, null, /* @__PURE__ */ React56.createElement(Sep, null), /* @__PURE__ */ React56.createElement(Text49, { color: FG.faint }, `v${VERSION}`), cols >= FEEDBACK_HINT_MIN_COLS && /* @__PURE__ */ React56.createElement(React56.Fragment, null, /* @__PURE__ */ React56.createElement(Text49, { color: FG.faint }, " \xB7 "), /* @__PURE__ */ React56.createElement(Text49, { color: FG.meta }, "\u2691 "), /* @__PURE__ */ React56.createElement(Text49, { color: FG.sub }, "/feedback")))));
9341
9377
  }
9342
9378
  function WalletPill({
9343
9379
  sessionCostUsd,
@@ -10931,6 +10967,32 @@ var handlers10 = {
10931
10967
  budget
10932
10968
  };
10933
10969
 
10970
+ // src/cli/ui/slash/handlers/observability.ts
10971
+ import { release } from "os";
10972
+
10973
+ // src/cli/ui/clipboard.ts
10974
+ import { mkdtempSync, writeFileSync as writeFileSync4 } from "fs";
10975
+ import { tmpdir } from "os";
10976
+ import { join as join6 } from "path";
10977
+ var OSC_52_LIMIT = 75e3;
10978
+ function writeClipboard(text) {
10979
+ const dir = mkdtempSync(join6(tmpdir(), "reasonix-clip-"));
10980
+ const filePath = join6(dir, "clip.txt");
10981
+ let osc52 = false;
10982
+ if (text.length <= OSC_52_LIMIT) {
10983
+ const b64 = Buffer.from(text, "utf8").toString("base64");
10984
+ process.stdout.write(`\x1B]52;c;${b64}\x1B\\`);
10985
+ osc52 = true;
10986
+ }
10987
+ let writtenPath = null;
10988
+ try {
10989
+ writeFileSync4(filePath, text, "utf8");
10990
+ writtenPath = filePath;
10991
+ } catch {
10992
+ }
10993
+ return { osc52, filePath: writtenPath, size: text.length };
10994
+ }
10995
+
10934
10996
  // src/cli/ui/ctx-breakdown.tsx
10935
10997
  import { Box as Box48, Text as Text51 } from "ink";
10936
10998
  import React59 from "react";
@@ -10975,6 +11037,90 @@ function computeCtxBreakdown(loop2) {
10975
11037
  };
10976
11038
  }
10977
11039
 
11040
+ // src/cli/ui/feedback.ts
11041
+ var FEEDBACK_ISSUE_BASE = "https://github.com/esengine/DeepSeek-Reasonix/issues/new";
11042
+ var FEEDBACK_BODY_QUERY_LIMIT = 6e3;
11043
+ function buildFeedbackIssueUrl(diagnostic) {
11044
+ const trimmed = diagnostic.length > FEEDBACK_BODY_QUERY_LIMIT ? diagnostic.slice(0, FEEDBACK_BODY_QUERY_LIMIT) : diagnostic;
11045
+ return `${FEEDBACK_ISSUE_BASE}?body=${encodeURIComponent(trimmed)}`;
11046
+ }
11047
+ function buildFeedbackDiagnostic(input) {
11048
+ const lines = [];
11049
+ lines.push(`**Reasonix**: ${formatVersion(input.version, input.latestVersion)}`);
11050
+ lines.push(`**Platform**: ${input.platform} (${input.osRelease})`);
11051
+ lines.push(`**Terminal**: ${formatTerminal(input)}`);
11052
+ if (typeof input.cols === "number" && typeof input.rows === "number") {
11053
+ lines.push(`**Size**: ${input.cols}\xD7${input.rows}`);
11054
+ }
11055
+ lines.push(`**Node**: ${input.nodeVersion}`);
11056
+ lines.push(`**Locale**: ${input.locale}`);
11057
+ if (input.theme) lines.push(`**Theme**: ${input.theme}`);
11058
+ lines.push(`**Model**: ${formatModel(input.model, input.reasoningEffort)}`);
11059
+ const modeLine = formatMode(input.editMode, input.planMode);
11060
+ if (modeLine) lines.push(`**Mode**: ${modeLine}`);
11061
+ if (typeof input.mcpServerCount === "number") {
11062
+ lines.push(`**MCP**: ${input.mcpServerCount} server(s)`);
11063
+ }
11064
+ if (input.sessionId) lines.push(`**Session**: ${input.sessionId}`);
11065
+ lines.push("", "<!-- describe what you were doing when this happened -->", "");
11066
+ return lines.join("\n");
11067
+ }
11068
+ function formatVersion(installed, latest) {
11069
+ if (!latest) return installed;
11070
+ if (latest === installed) return `${installed} (latest)`;
11071
+ return `${installed} (latest: ${latest})`;
11072
+ }
11073
+ function formatModel(model2, effort) {
11074
+ return effort ? `${model2} \xB7 effort=${effort}` : model2;
11075
+ }
11076
+ function formatMode(editMode, planMode) {
11077
+ const parts = [];
11078
+ if (editMode) parts.push(`edit=${editMode}`);
11079
+ parts.push(`plan=${planMode ? "on" : "off"}`);
11080
+ return parts.join(" \xB7 ");
11081
+ }
11082
+ function formatTerminal(input) {
11083
+ const head = input.termProgram ?? "(unknown)";
11084
+ const env = [];
11085
+ if (input.termProgram) env.push(`TERM_PROGRAM=${input.termProgram}`);
11086
+ if (input.term) env.push(`TERM=${input.term}`);
11087
+ if (input.colorTerm) env.push(`COLORTERM=${input.colorTerm}`);
11088
+ if (input.inWindowsTerminal) env.push("WT_SESSION=set");
11089
+ if (input.inTmux) env.push("TMUX=set");
11090
+ if (input.inSsh) env.push("SSH_TTY=set");
11091
+ if (input.wslDistro) env.push(`WSL=${input.wslDistro}`);
11092
+ if (env.length === 0) return head;
11093
+ return `${head} (${env.join(", ")})`;
11094
+ }
11095
+
11096
+ // src/cli/ui/open-url.ts
11097
+ import { spawn } from "child_process";
11098
+ import { platform } from "os";
11099
+ function openUrl(url) {
11100
+ if (process.env.CI) return { opened: false, reason: "ci" };
11101
+ if (process.env.REASONIX_NO_OPEN) return { opened: false, reason: "disabled" };
11102
+ const os = platform();
11103
+ let cmd;
11104
+ let args;
11105
+ if (os === "win32") {
11106
+ cmd = "cmd";
11107
+ args = ["/c", "start", "", url];
11108
+ } else if (os === "darwin") {
11109
+ cmd = "open";
11110
+ args = [url];
11111
+ } else {
11112
+ cmd = "xdg-open";
11113
+ args = [url];
11114
+ }
11115
+ try {
11116
+ const child = spawn(cmd, args, { detached: true, stdio: "ignore" });
11117
+ child.unref();
11118
+ return { opened: true };
11119
+ } catch {
11120
+ return { opened: false, reason: "spawn-failed" };
11121
+ }
11122
+ }
11123
+
10978
11124
  // src/cli/ui/slash/handlers/observability.ts
10979
11125
  var context = (_args, loop2) => {
10980
11126
  const breakdown = computeCtxBreakdown(loop2);
@@ -11004,11 +11150,11 @@ var status = (_args, loop2, ctx) => {
11004
11150
  }) : t("handlers.observability.statusCtxNone");
11005
11151
  const cost2 = summary.totalCostUsd;
11006
11152
  const cacheLine = summary.turns > 3 ? (() => {
11007
- const cachePct = Math.round(summary.cacheHitRatio * 100);
11153
+ const cachePct = summary.cacheHitRatio * 100;
11008
11154
  return t("handlers.observability.statusCost", {
11009
11155
  cost: cost2.toFixed(4),
11010
11156
  bar: renderTinyBar(cachePct, 12),
11011
- pct: cachePct,
11157
+ pct: cachePct.toFixed(1),
11012
11158
  turns: summary.turns
11013
11159
  });
11014
11160
  })() : t("handlers.observability.statusCostCold", {
@@ -11147,11 +11293,48 @@ function estimateCost(userText, loop2) {
11147
11293
  ];
11148
11294
  return { info: lines.join("\n") };
11149
11295
  }
11296
+ var feedback = (_args, loop2, ctx) => {
11297
+ const themeName = resolveThemePreference(loadTheme(), process.env.REASONIX_THEME);
11298
+ const diagnostic = buildFeedbackDiagnostic({
11299
+ version: VERSION,
11300
+ latestVersion: ctx.latestVersion ?? void 0,
11301
+ platform: process.platform,
11302
+ osRelease: release(),
11303
+ termProgram: process.env.TERM_PROGRAM,
11304
+ term: process.env.TERM,
11305
+ colorTerm: process.env.COLORTERM,
11306
+ inWindowsTerminal: !!process.env.WT_SESSION,
11307
+ inTmux: !!process.env.TMUX,
11308
+ inSsh: !!process.env.SSH_TTY,
11309
+ wslDistro: process.env.WSL_DISTRO_NAME,
11310
+ cols: process.stdout.columns,
11311
+ rows: process.stdout.rows,
11312
+ nodeVersion: process.version,
11313
+ locale: getLanguage(),
11314
+ theme: themeName,
11315
+ model: loop2.model,
11316
+ reasoningEffort: loop2.reasoningEffort,
11317
+ editMode: ctx.editMode,
11318
+ planMode: ctx.planMode,
11319
+ mcpServerCount: ctx.mcpServers?.length ?? ctx.mcpSpecs?.length,
11320
+ sessionId: ctx.sessionId
11321
+ });
11322
+ writeClipboard(diagnostic);
11323
+ const url = buildFeedbackIssueUrl(diagnostic);
11324
+ const opened = openUrl(url);
11325
+ const lines = [
11326
+ opened.opened ? "\u25B8 issue page opened with the diagnostic block pre-filled. Just describe what you were doing and submit." : `\u25B8 couldn't open the browser (${opened.reason ?? "unknown"}). Diagnostic info is on your clipboard; open this URL manually: ${url}`,
11327
+ "",
11328
+ diagnostic
11329
+ ];
11330
+ return { info: lines.join("\n") };
11331
+ };
11150
11332
  var handlers11 = {
11151
11333
  context,
11152
11334
  status,
11153
11335
  compact,
11154
- cost
11336
+ cost,
11337
+ feedback
11155
11338
  };
11156
11339
 
11157
11340
  // src/cli/ui/slash/handlers/permissions.ts
@@ -13250,7 +13433,7 @@ function AppInner({
13250
13433
  if (dashboardRef.current) return dashboardRef.current.url;
13251
13434
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
13252
13435
  const startup = (async () => {
13253
- const { startDashboardServer } = await import("./server-MC4A4WAJ.js");
13436
+ const { startDashboardServer } = await import("./server-SMLVXIW4.js");
13254
13437
  const handle = await startDashboardServer({
13255
13438
  mode: "attached",
13256
13439
  configPath: defaultConfigPath(),
@@ -13685,6 +13868,7 @@ function AppInner({
13685
13868
  startDashboard,
13686
13869
  stopDashboard,
13687
13870
  getDashboardUrl,
13871
+ sessionId: session,
13688
13872
  jobs: codeMode?.jobs,
13689
13873
  postInfo: (text2) => log.pushInfo(text2),
13690
13874
  postDoctor: (checks) => log.showDoctor(checks),
@@ -14151,7 +14335,8 @@ function AppInner({
14151
14335
  }
14152
14336
  if (choice === "refine" || choice === "approve") {
14153
14337
  if (pendingPlan) {
14154
- setStagedInput({ plan: pendingPlan, mode: choice });
14338
+ const questions = extractOpenQuestionsSection(pendingPlan) ?? void 0;
14339
+ setStagedInput({ plan: pendingPlan, mode: choice, questions });
14155
14340
  setPendingPlan(null);
14156
14341
  } else if (choice === "approve") {
14157
14342
  setStagedInput({ plan: "", mode: "approve" });
@@ -14166,7 +14351,8 @@ function AppInner({
14166
14351
  return;
14167
14352
  }
14168
14353
  if (pendingPlan) {
14169
- setStagedInput({ plan: pendingPlan, mode: "reject" });
14354
+ const questions = extractOpenQuestionsSection(pendingPlan) ?? void 0;
14355
+ setStagedInput({ plan: pendingPlan, mode: "reject", questions });
14170
14356
  setPendingPlan(null);
14171
14357
  }
14172
14358
  },
@@ -14181,7 +14367,7 @@ function AppInner({
14181
14367
  []
14182
14368
  );
14183
14369
  const handleStagedInputSubmit = useCallback11(
14184
- async (feedback, override) => {
14370
+ async (feedback2, override) => {
14185
14371
  const staged = override ?? stagedInput;
14186
14372
  if (override) {
14187
14373
  setPendingPlan(null);
@@ -14189,7 +14375,7 @@ function AppInner({
14189
14375
  setStagedInput(null);
14190
14376
  }
14191
14377
  if (!staged) return;
14192
- const trimmed = feedback.trim();
14378
+ const trimmed = feedback2.trim();
14193
14379
  let synthetic;
14194
14380
  let marker;
14195
14381
  if (staged.mode === "approve") {
@@ -14249,8 +14435,8 @@ ${trimmed}
14249
14435
  Stay in plan mode \u2014 address the feedback (explore more if needed), then submit an improved submit_plan call. Don't propose a near-identical plan unless you explain why the feedback doesn't apply.`;
14250
14436
  marker = `\u25B8 refining \u2014 ${trimmed.length > 50 ? `${trimmed.slice(0, 50)}\u2026` : trimmed}`;
14251
14437
  } else {
14252
- synthetic = "The plan needs refinement, but the user didn't give specifics. Ask them one or two concrete questions \u2014 scope, approach, file boundaries, or the risks you flagged \u2014 then wait for their answer before submitting an updated plan.";
14253
- marker = "\u25B8 refining \u2014 asking the model to clarify";
14438
+ synthetic = "The plan needs refinement. The user saw your open questions / risks block and chose not to answer specifics. Pick the safest default for each open question, call those defaults out explicitly in the new plan, and submit the refined submit_plan. Do not re-ask \u2014 the user already saw the questions.";
14439
+ marker = "\u25B8 refining \u2014 using safe defaults";
14254
14440
  }
14255
14441
  }
14256
14442
  const gateId = pendingGateIdRef.current;
@@ -14453,12 +14639,12 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14453
14639
  []
14454
14640
  );
14455
14641
  const handleCheckpointReviseSubmit = useCallback11(
14456
- (feedback, snapOverride) => {
14642
+ (feedback2, snapOverride) => {
14457
14643
  const snap = snapOverride;
14458
14644
  setStagedCheckpointRevise(null);
14459
14645
  if (!snap) return;
14460
14646
  const label = snap.title ? `${snap.stepId} \xB7 ${snap.title}` : snap.stepId;
14461
- const trimmed = feedback.trim();
14647
+ const trimmed = feedback2.trim();
14462
14648
  const gid = pendingGateIdRef.current;
14463
14649
  if (gid !== null) {
14464
14650
  pauseGate.resolve(
@@ -14558,6 +14744,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14558
14744
  PlanRefineInput,
14559
14745
  {
14560
14746
  mode: stagedInput.mode,
14747
+ questions: stagedInput.questions,
14561
14748
  onSubmit: handleStagedInputSubmit,
14562
14749
  onCancel: handleStagedInputCancel
14563
14750
  }
@@ -15287,4 +15474,4 @@ async function chatCommand(opts) {
15287
15474
  export {
15288
15475
  chatCommand
15289
15476
  };
15290
- //# sourceMappingURL=chunk-EINEIIIW.js.map
15477
+ //# sourceMappingURL=chunk-GPHBJWCV.js.map