reasonix 0.47.0 → 0.47.1

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 (108) hide show
  1. package/dist/cli/{acp-QK3DMC53.js → acp-GEOAKSTU.js} +21 -49
  2. package/dist/cli/acp-GEOAKSTU.js.map +1 -0
  3. package/dist/cli/{chat-VV5UWY4V.js → chat-YTPATMMG.js} +23 -23
  4. package/dist/cli/{chunk-FDKOUJKZ.js → chunk-2XY77LW7.js} +7 -7
  5. package/dist/cli/{chunk-QVDWH2A2.js → chunk-4MFCAZ2W.js} +3 -3
  6. package/dist/cli/{chunk-24A7FHGJ.js → chunk-6CRPCJAU.js} +14 -1
  7. package/dist/cli/chunk-6CRPCJAU.js.map +1 -0
  8. package/dist/cli/{chunk-VKYSZKH2.js → chunk-6QC5RQLE.js} +2 -2
  9. package/dist/cli/chunk-BQ6HC66J.js +530 -0
  10. package/dist/cli/chunk-BQ6HC66J.js.map +1 -0
  11. package/dist/cli/{chunk-OJVITDGB.js → chunk-CCJAP7G3.js} +2 -2
  12. package/dist/cli/{chunk-R6GQKKBW.js → chunk-CNG32VAB.js} +2 -2
  13. package/dist/cli/{chunk-QVUFWDD2.js → chunk-DN4B5S6Y.js} +2 -2
  14. package/dist/cli/{chunk-LBLR4CUZ.js → chunk-DQ6K5ZQ7.js} +2 -2
  15. package/dist/cli/{chunk-VNQGCA3Q.js → chunk-DWPAKZTY.js} +14 -3
  16. package/dist/cli/chunk-DWPAKZTY.js.map +1 -0
  17. package/dist/cli/{chunk-BWYVFFKR.js → chunk-GH7DC2Y5.js} +2 -2
  18. package/dist/cli/{chunk-BYYVYJDX.js → chunk-HUILPCYX.js} +3 -3
  19. package/dist/cli/{chunk-ICAFSZHS.js → chunk-JBH5RM7X.js} +174 -65
  20. package/dist/cli/chunk-JBH5RM7X.js.map +1 -0
  21. package/dist/cli/{chunk-K6GUKSXH.js → chunk-KVZZ5U75.js} +2 -2
  22. package/dist/cli/{chunk-WF7TPVZM.js → chunk-KYQVQ5X4.js} +84 -9
  23. package/dist/cli/chunk-KYQVQ5X4.js.map +1 -0
  24. package/dist/cli/{chunk-KDRUEXII.js → chunk-NRQ5UP5T.js} +20 -6
  25. package/dist/cli/chunk-NRQ5UP5T.js.map +1 -0
  26. package/dist/cli/{chunk-VJMBISEI.js → chunk-QCFLPSPH.js} +2 -2
  27. package/dist/cli/{chunk-YDPLF7XR.js → chunk-T5A7EY6B.js} +2 -2
  28. package/dist/cli/{chunk-VMUUFWFF.js → chunk-TDHXB2ER.js} +2 -2
  29. package/dist/cli/{chunk-GDKB2PPK.js → chunk-TRSAHHCL.js} +107 -11
  30. package/dist/cli/chunk-TRSAHHCL.js.map +1 -0
  31. package/dist/cli/{chunk-6J6BSUCR.js → chunk-TRWHTFG7.js} +2 -2
  32. package/dist/cli/{chunk-VC2CQA5D.js → chunk-XD6P7AFH.js} +26 -29
  33. package/dist/cli/chunk-XD6P7AFH.js.map +1 -0
  34. package/dist/cli/{chunk-ICSYGIPN.js → chunk-XMHP7BEE.js} +421 -80
  35. package/dist/cli/chunk-XMHP7BEE.js.map +1 -0
  36. package/dist/cli/{chunk-COWPEX54.js → chunk-YFP3MYMY.js} +5 -5
  37. package/dist/cli/{chunk-CI2PF5QX.js → chunk-ZXSCAODE.js} +8 -8
  38. package/dist/cli/{chunk-CI2PF5QX.js.map → chunk-ZXSCAODE.js.map} +1 -1
  39. package/dist/cli/{code-C24TUAE5.js → code-Q4NRVEDG.js} +29 -27
  40. package/dist/cli/code-Q4NRVEDG.js.map +1 -0
  41. package/dist/cli/{commands-RR3GIYOK.js → commands-4CDI4GFM.js} +4 -4
  42. package/dist/cli/{commit-FSHPIINM.js → commit-GW7LDQP5.js} +3 -3
  43. package/dist/cli/{desktop-7NCHPEFB.js → desktop-EG6P5SF2.js} +80 -22
  44. package/dist/cli/desktop-EG6P5SF2.js.map +1 -0
  45. package/dist/cli/{diff-RAAHHLHV.js → diff-VI2YX4FN.js} +8 -8
  46. package/dist/cli/{doctor-PKVQIXRT.js → doctor-CQTTZP27.js} +8 -8
  47. package/dist/cli/index.js +45 -37
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/{mcp-CRJ26PP4.js → mcp-J2UCD4RZ.js} +2 -2
  50. package/dist/cli/{mcp-browse-QPAOWZOP.js → mcp-browse-GSX34JEK.js} +2 -2
  51. package/dist/cli/{mcp-inspect-CVCLABRS.js → mcp-inspect-RRFYF4ZV.js} +2 -2
  52. package/dist/cli/{prompt-SKYXERSI.js → prompt-5TQPIVHV.js} +3 -3
  53. package/dist/cli/{replay-KPDW2ZMJ.js → replay-MJCEMODU.js} +8 -8
  54. package/dist/cli/{run-WIKDIXTG.js → run-P4D5VDYE.js} +13 -13
  55. package/dist/cli/{server-P6V2G3P6.js → server-C25JNNZV.js} +11 -11
  56. package/dist/cli/{sessions-2NULRMSA.js → sessions-QIONZJQ6.js} +12 -12
  57. package/dist/cli/{setup-Y5WDBQFL.js → setup-NLQ6G5G4.js} +6 -6
  58. package/dist/cli/setup-NLQ6G5G4.js.map +1 -0
  59. package/dist/cli/{stats-T7BL2YOR.js → stats-DFZEXHP4.js} +6 -6
  60. package/dist/cli/{version-3KWDNWLN.js → version-GR3X3MPI.js} +12 -12
  61. package/dist/index.d.ts +40 -48
  62. package/dist/index.js +286 -237
  63. package/dist/index.js.map +1 -1
  64. package/package.json +3 -1
  65. package/dist/cli/acp-QK3DMC53.js.map +0 -1
  66. package/dist/cli/chunk-24A7FHGJ.js.map +0 -1
  67. package/dist/cli/chunk-GDKB2PPK.js.map +0 -1
  68. package/dist/cli/chunk-ICAFSZHS.js.map +0 -1
  69. package/dist/cli/chunk-ICSYGIPN.js.map +0 -1
  70. package/dist/cli/chunk-KDRUEXII.js.map +0 -1
  71. package/dist/cli/chunk-UDVFBEXC.js +0 -642
  72. package/dist/cli/chunk-UDVFBEXC.js.map +0 -1
  73. package/dist/cli/chunk-VC2CQA5D.js.map +0 -1
  74. package/dist/cli/chunk-VNQGCA3Q.js.map +0 -1
  75. package/dist/cli/chunk-WF7TPVZM.js.map +0 -1
  76. package/dist/cli/code-C24TUAE5.js.map +0 -1
  77. package/dist/cli/desktop-7NCHPEFB.js.map +0 -1
  78. package/dist/cli/setup-Y5WDBQFL.js.map +0 -1
  79. /package/dist/cli/{chat-VV5UWY4V.js.map → chat-YTPATMMG.js.map} +0 -0
  80. /package/dist/cli/{chunk-FDKOUJKZ.js.map → chunk-2XY77LW7.js.map} +0 -0
  81. /package/dist/cli/{chunk-QVDWH2A2.js.map → chunk-4MFCAZ2W.js.map} +0 -0
  82. /package/dist/cli/{chunk-VKYSZKH2.js.map → chunk-6QC5RQLE.js.map} +0 -0
  83. /package/dist/cli/{chunk-OJVITDGB.js.map → chunk-CCJAP7G3.js.map} +0 -0
  84. /package/dist/cli/{chunk-R6GQKKBW.js.map → chunk-CNG32VAB.js.map} +0 -0
  85. /package/dist/cli/{chunk-QVUFWDD2.js.map → chunk-DN4B5S6Y.js.map} +0 -0
  86. /package/dist/cli/{chunk-LBLR4CUZ.js.map → chunk-DQ6K5ZQ7.js.map} +0 -0
  87. /package/dist/cli/{chunk-BWYVFFKR.js.map → chunk-GH7DC2Y5.js.map} +0 -0
  88. /package/dist/cli/{chunk-BYYVYJDX.js.map → chunk-HUILPCYX.js.map} +0 -0
  89. /package/dist/cli/{chunk-K6GUKSXH.js.map → chunk-KVZZ5U75.js.map} +0 -0
  90. /package/dist/cli/{chunk-VJMBISEI.js.map → chunk-QCFLPSPH.js.map} +0 -0
  91. /package/dist/cli/{chunk-YDPLF7XR.js.map → chunk-T5A7EY6B.js.map} +0 -0
  92. /package/dist/cli/{chunk-VMUUFWFF.js.map → chunk-TDHXB2ER.js.map} +0 -0
  93. /package/dist/cli/{chunk-6J6BSUCR.js.map → chunk-TRWHTFG7.js.map} +0 -0
  94. /package/dist/cli/{chunk-COWPEX54.js.map → chunk-YFP3MYMY.js.map} +0 -0
  95. /package/dist/cli/{commands-RR3GIYOK.js.map → commands-4CDI4GFM.js.map} +0 -0
  96. /package/dist/cli/{commit-FSHPIINM.js.map → commit-GW7LDQP5.js.map} +0 -0
  97. /package/dist/cli/{diff-RAAHHLHV.js.map → diff-VI2YX4FN.js.map} +0 -0
  98. /package/dist/cli/{doctor-PKVQIXRT.js.map → doctor-CQTTZP27.js.map} +0 -0
  99. /package/dist/cli/{mcp-CRJ26PP4.js.map → mcp-J2UCD4RZ.js.map} +0 -0
  100. /package/dist/cli/{mcp-browse-QPAOWZOP.js.map → mcp-browse-GSX34JEK.js.map} +0 -0
  101. /package/dist/cli/{mcp-inspect-CVCLABRS.js.map → mcp-inspect-RRFYF4ZV.js.map} +0 -0
  102. /package/dist/cli/{prompt-SKYXERSI.js.map → prompt-5TQPIVHV.js.map} +0 -0
  103. /package/dist/cli/{replay-KPDW2ZMJ.js.map → replay-MJCEMODU.js.map} +0 -0
  104. /package/dist/cli/{run-WIKDIXTG.js.map → run-P4D5VDYE.js.map} +0 -0
  105. /package/dist/cli/{server-P6V2G3P6.js.map → server-C25JNNZV.js.map} +0 -0
  106. /package/dist/cli/{sessions-2NULRMSA.js.map → sessions-QIONZJQ6.js.map} +0 -0
  107. /package/dist/cli/{stats-T7BL2YOR.js.map → stats-DFZEXHP4.js.map} +0 -0
  108. /package/dist/cli/{version-3KWDNWLN.js.map → version-GR3X3MPI.js.map} +0 -0
@@ -9,17 +9,17 @@ import {
9
9
  } from "./chunk-JMBMLOBP.js";
10
10
  import {
11
11
  createMcpRuntime
12
- } from "./chunk-COWPEX54.js";
12
+ } from "./chunk-YFP3MYMY.js";
13
13
  import {
14
14
  Eventizer,
15
15
  autoResolveVerdict,
16
16
  registerSkillTools,
17
17
  shouldAutoResolveCheckpoint
18
- } from "./chunk-CI2PF5QX.js";
18
+ } from "./chunk-ZXSCAODE.js";
19
19
  import {
20
20
  formatMcpLifecycleEvent,
21
21
  formatMcpSlowToast
22
- } from "./chunk-LBLR4CUZ.js";
22
+ } from "./chunk-DQ6K5ZQ7.js";
23
23
  import {
24
24
  buildTransportFromSpec
25
25
  } from "./chunk-EQATK2L2.js";
@@ -53,19 +53,19 @@ import {
53
53
  toWholeFileEditBlock,
54
54
  walkFilesStream,
55
55
  webFetch
56
- } from "./chunk-ICAFSZHS.js";
56
+ } from "./chunk-JBH5RM7X.js";
57
57
  import {
58
58
  openTranscriptFile,
59
59
  recordFromLoopEvent,
60
60
  writeRecord
61
- } from "./chunk-BYYVYJDX.js";
61
+ } from "./chunk-HUILPCYX.js";
62
62
  import {
63
63
  McpClient
64
64
  } from "./chunk-HIYTRCSW.js";
65
65
  import {
66
66
  MemoryStore,
67
67
  effectivePriority
68
- } from "./chunk-UDVFBEXC.js";
68
+ } from "./chunk-BQ6HC66J.js";
69
69
  import {
70
70
  wrapper_default
71
71
  } from "./chunk-FEZK652I.js";
@@ -73,7 +73,7 @@ import {
73
73
  KeystrokeProvider,
74
74
  SingleSelect,
75
75
  useKeystroke
76
- } from "./chunk-6J6BSUCR.js";
76
+ } from "./chunk-TRWHTFG7.js";
77
77
  import {
78
78
  COLOR,
79
79
  GLYPH,
@@ -81,7 +81,7 @@ import {
81
81
  ThemeProvider,
82
82
  useColor,
83
83
  useThemeTokens
84
- } from "./chunk-OJVITDGB.js";
84
+ } from "./chunk-CCJAP7G3.js";
85
85
  import {
86
86
  Box_default,
87
87
  Text,
@@ -101,20 +101,20 @@ import {
101
101
  } from "./chunk-LGEKVMMV.js";
102
102
  import {
103
103
  runDoctorChecks
104
- } from "./chunk-FDKOUJKZ.js";
104
+ } from "./chunk-2XY77LW7.js";
105
105
  import {
106
106
  countTokensBounded
107
107
  } from "./chunk-6OWJV3YW.js";
108
108
  import {
109
109
  DeepSeekClient,
110
110
  pickPrimaryBalance
111
- } from "./chunk-VNQGCA3Q.js";
111
+ } from "./chunk-DWPAKZTY.js";
112
112
  import {
113
113
  loadDotenv
114
114
  } from "./chunk-2UQP6H6T.js";
115
115
  import {
116
116
  renderDashboard
117
- } from "./chunk-QVDWH2A2.js";
117
+ } from "./chunk-4MFCAZ2W.js";
118
118
  import {
119
119
  MANUAL_UPDATE_COMMANDS,
120
120
  planUpdate
@@ -140,7 +140,7 @@ import {
140
140
  restoreCheckpoint,
141
141
  savePlanState,
142
142
  suggestSlashCommands
143
- } from "./chunk-WF7TPVZM.js";
143
+ } from "./chunk-KYQVQ5X4.js";
144
144
  import {
145
145
  eventLogPath,
146
146
  openEventSink
@@ -153,10 +153,12 @@ import {
153
153
  } from "./chunk-XJXDHAES.js";
154
154
  import {
155
155
  BUILTIN_ALLOWLIST,
156
+ derivePrefix,
156
157
  formatCommandResult,
157
158
  pauseGate,
158
- runCommand
159
- } from "./chunk-GDKB2PPK.js";
159
+ runCommand,
160
+ tildeify
161
+ } from "./chunk-TRSAHHCL.js";
160
162
  import {
161
163
  PROJECT_MEMORY_FILE,
162
164
  SkillStore,
@@ -171,7 +173,7 @@ import {
171
173
  loadHooks,
172
174
  projectSettingsPath,
173
175
  runHooks
174
- } from "./chunk-BWYVFFKR.js";
176
+ } from "./chunk-GH7DC2Y5.js";
175
177
  import {
176
178
  deleteSession,
177
179
  detectGitBranch,
@@ -194,12 +196,12 @@ import {
194
196
  appendUsage,
195
197
  defaultUsageLogPath,
196
198
  readUsageLog
197
- } from "./chunk-QVUFWDD2.js";
199
+ } from "./chunk-DN4B5S6Y.js";
198
200
  import {
199
201
  DEEPSEEK_CONTEXT_TOKENS,
200
202
  DEFAULT_CONTEXT_TOKENS,
201
203
  pricingFor
202
- } from "./chunk-VJMBISEI.js";
204
+ } from "./chunk-QCFLPSPH.js";
203
205
  import {
204
206
  getLanguage,
205
207
  getSupportedLanguages,
@@ -208,7 +210,7 @@ import {
208
210
  setLanguage,
209
211
  t,
210
212
  tObj
211
- } from "./chunk-KDRUEXII.js";
213
+ } from "./chunk-NRQ5UP5T.js";
212
214
  import {
213
215
  CARD,
214
216
  FG,
@@ -231,6 +233,7 @@ import {
231
233
  loadApiKey,
232
234
  loadBaseUrl,
233
235
  loadEditMode,
236
+ loadEngineeringLifecycleMode,
234
237
  loadProjectShellAllowed,
235
238
  loadQQConfig,
236
239
  loadRateLimit,
@@ -263,7 +266,7 @@ import {
263
266
  webSearchEndpoint,
264
267
  webSearchEngine,
265
268
  writeConfig
266
- } from "./chunk-24A7FHGJ.js";
269
+ } from "./chunk-6CRPCJAU.js";
267
270
  import {
268
271
  VERSION,
269
272
  compareVersions,
@@ -44813,6 +44816,285 @@ import { statSync as statSync2 } from "fs";
44813
44816
  import { relative as relative2, resolve as resolve3 } from "path";
44814
44817
  var import_react92 = __toESM(require_react(), 1);
44815
44818
 
44819
+ // src/code/lifecycle.ts
44820
+ var SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
44821
+ "read_file",
44822
+ "list_directory",
44823
+ "directory_tree",
44824
+ "search_files",
44825
+ "search_content",
44826
+ "glob",
44827
+ "get_file_info",
44828
+ "semantic_search",
44829
+ "web_search",
44830
+ "web_fetch",
44831
+ "recall_memory",
44832
+ "todo_write",
44833
+ "ask_choice",
44834
+ "submit_plan",
44835
+ "mark_step_complete",
44836
+ "revise_plan",
44837
+ "job_output",
44838
+ "wait_for_job",
44839
+ "list_jobs"
44840
+ ]);
44841
+ var HIGH_RISK_TOOL_NAMES = /* @__PURE__ */ new Set([
44842
+ "multi_edit",
44843
+ "move_file",
44844
+ "delete_file",
44845
+ "delete_directory",
44846
+ "copy_file",
44847
+ "create_directory",
44848
+ "run_background",
44849
+ "stop_job"
44850
+ ]);
44851
+ var MUTATION_TOOL_NAMES = /* @__PURE__ */ new Set([
44852
+ "edit_file",
44853
+ "write_file",
44854
+ "multi_edit",
44855
+ "move_file",
44856
+ "delete_file",
44857
+ "delete_directory",
44858
+ "copy_file",
44859
+ "create_directory",
44860
+ "run_background",
44861
+ "stop_job"
44862
+ ]);
44863
+ function isHighRiskLifecycleToolCall(name, args) {
44864
+ if (HIGH_RISK_TOOL_NAMES.has(name)) return true;
44865
+ if (SAFE_TOOL_NAMES.has(name)) return false;
44866
+ if (name === "write_file") {
44867
+ const path = typeof args.path === "string" ? args.path : "";
44868
+ return isPackageOrConfigPath(path);
44869
+ }
44870
+ if (name === "edit_file") {
44871
+ const path = typeof args.path === "string" ? args.path : "";
44872
+ return isPackageOrConfigPath(path);
44873
+ }
44874
+ if (name === "run_command") {
44875
+ const command = typeof args.command === "string" ? args.command : "";
44876
+ return isHighRiskCommand(command);
44877
+ }
44878
+ return false;
44879
+ }
44880
+ function isLifecycleMutationToolCall(name, args) {
44881
+ if (MUTATION_TOOL_NAMES.has(name)) return true;
44882
+ if (name === "run_command") {
44883
+ const command = typeof args.command === "string" ? args.command : "";
44884
+ return isHighRiskCommand(command);
44885
+ }
44886
+ return false;
44887
+ }
44888
+ var EngineeringLifecycleRuntime = class {
44889
+ _mode;
44890
+ _state = "idle";
44891
+ _planSteps = [];
44892
+ _completedStepIds = /* @__PURE__ */ new Set();
44893
+ _mutatedSinceLastStep = false;
44894
+ constructor(opts = {}) {
44895
+ this._mode = opts.mode ?? "off";
44896
+ if (this._mode === "strict") this._state = "armed";
44897
+ }
44898
+ get mode() {
44899
+ return this._mode;
44900
+ }
44901
+ setMode(mode2) {
44902
+ this._mode = mode2;
44903
+ if (mode2 === "off") {
44904
+ this.reset();
44905
+ return;
44906
+ }
44907
+ if (mode2 === "strict" && this._state === "idle") this._state = "armed";
44908
+ }
44909
+ observeUserPrompt(_text) {
44910
+ if (this._mode === "off") return;
44911
+ if (this._state === "complete" || this._state === "cancelled") {
44912
+ this.reset();
44913
+ }
44914
+ if (this._state === "idle") this._state = "armed";
44915
+ }
44916
+ recordPlanProposed(steps) {
44917
+ if (this._mode === "off") return;
44918
+ this._state = "planning";
44919
+ this._planSteps = [...steps ?? []];
44920
+ this._completedStepIds.clear();
44921
+ this._mutatedSinceLastStep = false;
44922
+ }
44923
+ recordPlanApproved(steps) {
44924
+ if (this._mode === "off") return;
44925
+ this._state = "approved";
44926
+ this._planSteps = [...steps ?? this._planSteps];
44927
+ this._completedStepIds.clear();
44928
+ this._mutatedSinceLastStep = false;
44929
+ }
44930
+ recordStepCompleted(stepId) {
44931
+ if (!stepId) return;
44932
+ this._completedStepIds.add(stepId);
44933
+ this._mutatedSinceLastStep = false;
44934
+ if (this._planSteps.length > 0 && this._completedStepIds.size >= this._planSteps.length) {
44935
+ this._state = "complete";
44936
+ } else if (this._state !== "idle" && this._state !== "cancelled") {
44937
+ this._state = "executing";
44938
+ }
44939
+ }
44940
+ recordToolResult(name, args, result) {
44941
+ if (this._mode === "off") return;
44942
+ if (!isLifecycleMutationToolCall(name, args)) return;
44943
+ if (!toolResultLooksSuccessful(result)) return;
44944
+ if (this._state === "approved" || this._state === "executing") {
44945
+ this._state = "executing";
44946
+ this._mutatedSinceLastStep = true;
44947
+ }
44948
+ }
44949
+ cancel() {
44950
+ this._state = "cancelled";
44951
+ this._planSteps = [];
44952
+ this._completedStepIds.clear();
44953
+ this._mutatedSinceLastStep = false;
44954
+ }
44955
+ reset() {
44956
+ this._state = this._mode === "strict" ? "armed" : "idle";
44957
+ this._planSteps = [];
44958
+ this._completedStepIds.clear();
44959
+ this._mutatedSinceLastStep = false;
44960
+ }
44961
+ guardToolCall = (name, args) => {
44962
+ if (this._mode === "off") return null;
44963
+ if (name === "mark_step_complete") return this.guardStepCompletion(args);
44964
+ if (!isHighRiskLifecycleToolCall(name, args)) return null;
44965
+ if (this._state !== "approved" && this._state !== "executing") {
44966
+ return JSON.stringify({
44967
+ error: `${name}: blocked by Engineering Lifecycle \u2014 high-risk engineering work requires an approved structured plan first. Explore with read-only tools, call ask_choice for real forks, then call submit_plan with concrete steps.`,
44968
+ rejectedReason: "engineering-lifecycle",
44969
+ state: this._state
44970
+ });
44971
+ }
44972
+ this._state = "executing";
44973
+ return null;
44974
+ };
44975
+ snapshot() {
44976
+ return {
44977
+ mode: this._mode,
44978
+ state: this._state,
44979
+ planSteps: [...this._planSteps],
44980
+ completedStepIds: [...this._completedStepIds],
44981
+ mutatedSinceLastStep: this._mutatedSinceLastStep
44982
+ };
44983
+ }
44984
+ guardStepCompletion(args) {
44985
+ const stepId = typeof args.stepId === "string" ? args.stepId.trim() : "";
44986
+ const step = this._planSteps.find((s) => s.id === stepId);
44987
+ const evidence = Array.isArray(args.evidence) ? args.evidence : [];
44988
+ const evidenceRequired = this._mutatedSinceLastStep || step?.risk === "med" || step?.risk === "high" || (step?.verification?.length ?? 0) > 0;
44989
+ if (evidenceRequired && evidence.length === 0) {
44990
+ return JSON.stringify({
44991
+ error: "mark_step_complete: evidence required by Engineering Lifecycle \u2014 include verification, diff, checkpoint, or manual evidence before completing this step.",
44992
+ rejectedReason: "engineering-lifecycle-evidence",
44993
+ stepId
44994
+ });
44995
+ }
44996
+ return null;
44997
+ }
44998
+ };
44999
+ function toolResultLooksSuccessful(result) {
45000
+ const text = result.trim();
45001
+ if (!text) return false;
45002
+ try {
45003
+ const parsed = JSON.parse(text);
45004
+ if (parsed && typeof parsed === "object" && "error" in parsed) return false;
45005
+ } catch {
45006
+ }
45007
+ if (/\b0\/\d+\s+applied\b/i.test(text)) return false;
45008
+ return !/(user rejected|rejected this edit|discarded|unavailable in plan mode|interceptor failed|\berror\b|failed)/i.test(
45009
+ text
45010
+ );
45011
+ }
45012
+ function isPackageOrConfigPath(path) {
45013
+ const normalized = path.replaceAll("\\", "/").toLowerCase();
45014
+ return /(^|\/)package(-lock)?\.json$/.test(normalized) || /(^|\/)pnpm-lock\.yaml$/.test(normalized) || /(^|\/)yarn\.lock$/.test(normalized) || /(^|\/)tsconfig[^/]*\.json$/.test(normalized) || /(^|\/)vitest\.config\./.test(normalized) || /(^|\/)biome\.json$/.test(normalized) || normalized.startsWith(".github/workflows/");
45015
+ }
45016
+ function isHighRiskCommand(command) {
45017
+ const tokens = shellTokens(command);
45018
+ for (let i = 0; i < tokens.length; i++) {
45019
+ const token = tokens[i]?.toLowerCase();
45020
+ if (!token || !isCommandPosition(tokens, i)) continue;
45021
+ if ((token === "npm" || token === "pnpm" || token === "yarn") && isPackageMutation(tokens[i + 1])) {
45022
+ return true;
45023
+ }
45024
+ if (token === "git" && isHighRiskGitCommand(tokens.slice(i + 1))) return true;
45025
+ if (token === "rm" || token === "mv" || token === "cp") return true;
45026
+ }
45027
+ return false;
45028
+ }
45029
+ function shellTokens(command) {
45030
+ const out = [];
45031
+ let current = "";
45032
+ let quote = null;
45033
+ for (let i = 0; i < command.length; i++) {
45034
+ const ch = command[i] ?? "";
45035
+ if (quote) {
45036
+ if (ch === quote) quote = null;
45037
+ else current += ch;
45038
+ continue;
45039
+ }
45040
+ if (ch === "'" || ch === '"') {
45041
+ quote = ch;
45042
+ continue;
45043
+ }
45044
+ if (/\s/.test(ch)) {
45045
+ if (current) {
45046
+ out.push(current);
45047
+ current = "";
45048
+ }
45049
+ continue;
45050
+ }
45051
+ if (ch === ";" || ch === "|" || ch === "&") {
45052
+ if (current) {
45053
+ out.push(current);
45054
+ current = "";
45055
+ }
45056
+ const next = command[i + 1];
45057
+ if ((ch === "|" || ch === "&") && next === ch) {
45058
+ out.push(`${ch}${next}`);
45059
+ i++;
45060
+ } else {
45061
+ out.push(ch);
45062
+ }
45063
+ continue;
45064
+ }
45065
+ current += ch;
45066
+ }
45067
+ if (current) out.push(current);
45068
+ return out;
45069
+ }
45070
+ function isCommandPosition(tokens, index) {
45071
+ if (index === 0) return true;
45072
+ const previous = tokens[index - 1];
45073
+ return previous === ";" || previous === "|" || previous === "&&" || previous === "||";
45074
+ }
45075
+ function isPackageMutation(token) {
45076
+ const normalized = token?.toLowerCase();
45077
+ return normalized === "install" || normalized === "add" || normalized === "remove" || normalized === "update";
45078
+ }
45079
+ function isHighRiskGitCommand(args) {
45080
+ const subcommandIndex = args.findIndex((arg) => arg && !arg.startsWith("-"));
45081
+ const subcommand = args[subcommandIndex]?.toLowerCase();
45082
+ if (!subcommand) return false;
45083
+ if (subcommand === "push" || subcommand === "reset" || subcommand === "clean" || subcommand === "switch") {
45084
+ return true;
45085
+ }
45086
+ if (subcommand !== "checkout") return false;
45087
+ const checkoutArgs = args.slice(subcommandIndex + 1);
45088
+ if (checkoutArgs[0] === "--") return false;
45089
+ if (checkoutArgs.some((arg) => arg === "-b" || arg === "-B" || arg === "--orphan")) return true;
45090
+ const positional = checkoutArgs.filter((arg) => arg && !arg.startsWith("-"));
45091
+ if (positional.length === 0) return false;
45092
+ return !positional.every(looksLikePathCheckout);
45093
+ }
45094
+ function looksLikePathCheckout(arg) {
45095
+ return arg.includes("/") || arg.includes("\\") || arg.includes(".");
45096
+ }
45097
+
44816
45098
  // src/code/pending-edits.ts
44817
45099
  import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
44818
45100
  import { dirname as dirname2, join as join2 } from "path";
@@ -46308,7 +46590,7 @@ function EntryRow({ entry, isSelected }) {
46308
46590
  const cursor = isSelected ? `${GLYPH.cur} ` : " ";
46309
46591
  const labelColor = entry.isDir ? color.accent : color.primary;
46310
46592
  const labelText = entry.isDir ? `${entry.label}/` : entry.label;
46311
- return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, /* @__PURE__ */ import_react8.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected }, cursor), /* @__PURE__ */ import_react8.default.createElement(Text, { color: labelColor, bold: isSelected }, labelText.padEnd(20)), entry.dirSuffix ? /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, ` ${entry.dirSuffix}`) : null);
46593
+ return /* @__PURE__ */ import_react8.default.createElement(Box_default, { backgroundColor: isSelected ? SURFACE.bgElev : void 0 }, /* @__PURE__ */ import_react8.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected }, cursor), /* @__PURE__ */ import_react8.default.createElement(Text, { color: labelColor, bold: isSelected }, labelText.padEnd(20)), entry.dirSuffix ? /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, ` ${entry.dirSuffix}`) : null);
46312
46594
  }
46313
46595
  function FooterRow({ isBrowse, hasFolder }) {
46314
46596
  const hintKey = isBrowse && hasFolder ? "atMentions.footerBrowse" : "atMentions.footerInsert";
@@ -47302,7 +47584,7 @@ function ArgRow({
47302
47584
  isDir
47303
47585
  }) {
47304
47586
  const color = useColor();
47305
- return /* @__PURE__ */ import_react10.default.createElement(Box_default, null, /* @__PURE__ */ import_react10.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ import_react10.default.createElement(Text, { color: isSelected ? color.user : color.info, bold: isSelected, dimColor: !isSelected }, value), isDir ? /* @__PURE__ */ import_react10.default.createElement(Text, { dimColor: true }, "/") : null);
47587
+ return /* @__PURE__ */ import_react10.default.createElement(Box_default, { backgroundColor: isSelected ? SURFACE.bgElev : void 0 }, /* @__PURE__ */ import_react10.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ import_react10.default.createElement(Text, { color: isSelected ? color.user : color.info, bold: isSelected, dimColor: !isSelected }, value), isDir ? /* @__PURE__ */ import_react10.default.createElement(Text, { dimColor: true }, "/") : null);
47306
47588
  }
47307
47589
 
47308
47590
  // src/cli/ui/SlashSuggestions.tsx
@@ -47411,7 +47693,22 @@ function SuggestionRow({
47411
47693
  const reservedCells = 2 + COMMAND_NAME_CELLS + ARGS_CELLS + 2 + 2;
47412
47694
  const summaryBudget = Math.max(8, columns - reservedCells);
47413
47695
  const summaryText = truncateCells(`${summary}${aliasHint}`, summaryBudget);
47414
- return /* @__PURE__ */ import_react11.default.createElement(Box_default, { flexDirection: "row", flexWrap: "nowrap", flexShrink: 0, height: 1, minHeight: 1 }, /* @__PURE__ */ import_react11.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected, wrap: "truncate" }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ import_react11.default.createElement(Text, { color: color.accent, bold: isSelected, wrap: "truncate" }, padOrTrim(name, COMMAND_NAME_CELLS)), /* @__PURE__ */ import_react11.default.createElement(Text, { dimColor: true, wrap: "truncate" }, padOrTrim(argsSuffix, ARGS_CELLS)), /* @__PURE__ */ import_react11.default.createElement(Text, { wrap: "truncate" }, " "), /* @__PURE__ */ import_react11.default.createElement(Text, { color: isSelected ? color.user : color.info, dimColor: !isSelected, wrap: "truncate" }, summaryText));
47696
+ return /* @__PURE__ */ import_react11.default.createElement(
47697
+ Box_default,
47698
+ {
47699
+ flexDirection: "row",
47700
+ flexWrap: "nowrap",
47701
+ flexShrink: 0,
47702
+ height: 1,
47703
+ minHeight: 1,
47704
+ backgroundColor: isSelected ? SURFACE.bgElev : void 0
47705
+ },
47706
+ /* @__PURE__ */ import_react11.default.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected, wrap: "truncate" }, isSelected ? `${GLYPH.cur} ` : " "),
47707
+ /* @__PURE__ */ import_react11.default.createElement(Text, { color: color.accent, bold: isSelected, wrap: "truncate" }, padOrTrim(name, COMMAND_NAME_CELLS)),
47708
+ /* @__PURE__ */ import_react11.default.createElement(Text, { dimColor: true, wrap: "truncate" }, padOrTrim(argsSuffix, ARGS_CELLS)),
47709
+ /* @__PURE__ */ import_react11.default.createElement(Text, { wrap: "truncate" }, " "),
47710
+ /* @__PURE__ */ import_react11.default.createElement(Text, { color: isSelected ? color.user : color.info, dimColor: !isSelected, wrap: "truncate" }, summaryText)
47711
+ );
47415
47712
  }
47416
47713
  function padOrTrim(value, cells) {
47417
47714
  const trimmed = truncateCells(value, cells);
@@ -47510,7 +47807,14 @@ var import_react17 = __toESM(require_react(), 1);
47510
47807
 
47511
47808
  // src/cli/ui/ticker.tsx
47512
47809
  var import_react16 = __toESM(require_react(), 1);
47513
- var FAST_TICK_MS = 120;
47810
+
47811
+ // src/cli/ui/terminal-host.ts
47812
+ function isLegacyWindowsConsole(env = process.env) {
47813
+ return process.platform === "win32" && !env.WT_SESSION && !env.TERM_PROGRAM;
47814
+ }
47815
+
47816
+ // src/cli/ui/ticker.tsx
47817
+ var FAST_TICK_MS = isLegacyWindowsConsole() ? 250 : 120;
47514
47818
  var SLOW_TICK_MS = 1e3;
47515
47819
  var TickerActiveContext = (0, import_react16.createContext)(true);
47516
47820
  function TickerProvider({ children, disabled }) {
@@ -49971,17 +50275,7 @@ var FALLBACK_MODELS = [
49971
50275
  ];
49972
50276
 
49973
50277
  // src/cli/ui/PathConfirm.tsx
49974
- import { homedir as homedir3 } from "os";
49975
50278
  var import_react36 = __toESM(require_react(), 1);
49976
- function tildeify(p) {
49977
- const home = homedir3();
49978
- if (!home) return p;
49979
- const normalized = home.replace(/[\\/]+$/, "");
49980
- if (p === normalized) return "~";
49981
- if (p.startsWith(`${normalized}/`)) return `~/${p.slice(normalized.length + 1)}`;
49982
- if (p.startsWith(`${normalized}\\`)) return `~\\${p.slice(normalized.length + 1)}`;
49983
- return p;
49984
- }
49985
50279
  function PathConfirm({
49986
50280
  path,
49987
50281
  intent,
@@ -50156,12 +50450,12 @@ function PlanCheckpointConfirmInner({
50156
50450
  return /* @__PURE__ */ import_react38.default.createElement(ApprovalCard, { tone: "ok", glyph: "\u26C1", title: t("planFlow.checkpoint.title"), metaRight: subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ import_react38.default.createElement(Box_default, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ import_react38.default.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ import_react38.default.createElement(
50157
50451
  SingleSelect,
50158
50452
  {
50159
- initialValue: isLast ? "stop" : "continue",
50453
+ initialValue: "continue",
50160
50454
  items: [
50161
50455
  {
50162
50456
  value: "continue",
50163
- label: t("planFlow.checkpoint.continue"),
50164
- hint: t("planFlow.checkpoint.continueHint")
50457
+ label: t(isLast ? "planFlow.checkpoint.finish" : "planFlow.checkpoint.continue"),
50458
+ hint: t(isLast ? "planFlow.checkpoint.finishHint" : "planFlow.checkpoint.continueHint")
50165
50459
  },
50166
50460
  {
50167
50461
  value: "revise",
@@ -53307,7 +53601,7 @@ function relativeTime2(date) {
53307
53601
  }
53308
53602
 
53309
53603
  // src/cli/ui/ShellConfirm.tsx
53310
- import { homedir as homedir4 } from "os";
53604
+ import { homedir as homedir3 } from "os";
53311
53605
  var import_react45 = __toESM(require_react(), 1);
53312
53606
  var CHROME_ROWS = 18;
53313
53607
  var MIN_COMMAND_LINES = 3;
@@ -53317,7 +53611,7 @@ function clampCommand(command, max) {
53317
53611
  return { preview: lines.slice(0, max).join("\n"), hidden: lines.length - max };
53318
53612
  }
53319
53613
  function tildeify2(path) {
53320
- const home = homedir4();
53614
+ const home = homedir3();
53321
53615
  if (!home) return path;
53322
53616
  const normalized = home.replace(/[\\/]+$/, "");
53323
53617
  if (path === normalized) return "~";
@@ -53424,34 +53718,6 @@ function InfoRows2({
53424
53718
  const labelWidth = Math.max(...rows.map((r) => r.label.length));
53425
53719
  return /* @__PURE__ */ import_react45.default.createElement(Box_default, { flexDirection: "column", marginBottom: 1 }, rows.map((r) => /* @__PURE__ */ import_react45.default.createElement(Box_default, { key: r.label, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react45.default.createElement(Text, { color: FG.faint }, r.label.padEnd(labelWidth)), /* @__PURE__ */ import_react45.default.createElement(Text, { color: FG.body }, r.value))));
53426
53720
  }
53427
- function derivePrefix(command) {
53428
- const tokens = command.trim().split(/\s+/).filter(Boolean);
53429
- if (tokens.length === 0) return "";
53430
- if (tokens.length === 1) return tokens[0];
53431
- const first = tokens[0];
53432
- const TWO_TOKEN_WRAPPERS = /* @__PURE__ */ new Set([
53433
- "npm",
53434
- "npx",
53435
- "pnpm",
53436
- "yarn",
53437
- "bun",
53438
- "git",
53439
- "cargo",
53440
- "go",
53441
- "docker",
53442
- "kubectl",
53443
- "python",
53444
- "python3",
53445
- "deno",
53446
- "pip",
53447
- "pip3",
53448
- "make",
53449
- "rake",
53450
- "bundle",
53451
- "gem"
53452
- ]);
53453
- return TWO_TOKEN_WRAPPERS.has(first) ? `${first} ${tokens[1]}` : first;
53454
- }
53455
53721
 
53456
53722
  // src/cli/ui/ThemePicker.tsx
53457
53723
  var import_react46 = __toESM(require_react(), 1);
@@ -53487,7 +53753,7 @@ function describeTheme(value, currentPreference, activeTheme) {
53487
53753
 
53488
53754
  // src/cli/ui/WelcomeBanner.tsx
53489
53755
  var import_react47 = __toESM(require_react(), 1);
53490
- var HINTS = ["/help", "/init", "/memory", "/cost"];
53756
+ var HINTS = ["/help", "/skill", "/init", "/memory", "/cost"];
53491
53757
  function WelcomeBanner({
53492
53758
  inCodeMode,
53493
53759
  workspaceRoot,
@@ -53969,7 +54235,7 @@ function loopEventToDashboard(ev, ctx) {
53969
54235
 
53970
54236
  // src/cli/ui/hash-memory.ts
53971
54237
  import { closeSync, fstatSync, mkdirSync as mkdirSync4, openSync, readSync, writeSync } from "fs";
53972
- import { homedir as homedir5 } from "os";
54238
+ import { homedir as homedir4 } from "os";
53973
54239
  import { dirname as dirname4, join as join6 } from "path";
53974
54240
  var PROJECT_HEADER = `# Reasonix project memory
53975
54241
 
@@ -54006,7 +54272,7 @@ function appendProjectMemory(rootDir, note) {
54006
54272
  }
54007
54273
  var GLOBAL_MEMORY_DIR = ".reasonix";
54008
54274
  var GLOBAL_MEMORY_FILE = "REASONIX.md";
54009
- function globalMemoryPath(homeDir = homedir5()) {
54275
+ function globalMemoryPath(homeDir = homedir4()) {
54010
54276
  return join6(homeDir, GLOBAL_MEMORY_DIR, GLOBAL_MEMORY_FILE);
54011
54277
  }
54012
54278
  function appendGlobalMemory(note, homeDir) {
@@ -54189,8 +54455,10 @@ function handleToolEvent(ev, ctx) {
54189
54455
  const stepId = parsed.stepId;
54190
54456
  if (parsed.kind === "step_completed" && typeof stepId === "string") {
54191
54457
  ctx.completedStepIdsRef.current.add(stepId);
54458
+ ctx.stepCompletionsRef?.current.set(stepId, parsed);
54192
54459
  ctx.persistPlanState();
54193
54460
  ctx.log.completePlanStep(stepId);
54461
+ ctx.onPlanStepCompleted?.(stepId);
54194
54462
  const total = ctx.planStepsRef.current?.length ?? 0;
54195
54463
  const completed = ctx.completedStepIdsRef.current.size;
54196
54464
  const stepFromPlan = ctx.planStepsRef.current?.find((s) => s.id === stepId);
@@ -56695,6 +56963,11 @@ var help = () => {
56695
56963
  t("handlers.basic.helpShellConsent"),
56696
56964
  t("handlers.basic.helpShellExample"),
56697
56965
  "",
56966
+ t("handlers.basic.helpShellGateTitle"),
56967
+ t("handlers.basic.helpShellGate"),
56968
+ t("handlers.basic.helpShellGateDetail"),
56969
+ t("handlers.basic.helpShellGatePolicy"),
56970
+ "",
56698
56971
  t("handlers.basic.helpMemoryTitle"),
56699
56972
  t("handlers.basic.helpMemoryPin"),
56700
56973
  t("handlers.basic.helpMemoryPinEx"),
@@ -56943,7 +57216,7 @@ var plan = (args, _loop, ctx) => {
56943
57216
  const currentOn = Boolean(ctx.planMode);
56944
57217
  const raw = (args[0] ?? "").toLowerCase();
56945
57218
  let target;
56946
- if (raw === "on" || raw === "true" || raw === "1") target = true;
57219
+ if (raw === "on" || raw === "true" || raw === "1" || raw === "strict") target = true;
56947
57220
  else if (raw === "off" || raw === "false" || raw === "0") target = false;
56948
57221
  else target = !currentOn;
56949
57222
  ctx.setPlanMode(target);
@@ -59709,9 +59982,10 @@ function useSubagent({
59709
59982
  // src/cli/ui/App.tsx
59710
59983
  var FLUSH_INTERVAL_MS = (() => {
59711
59984
  const raw = process.env.REASONIX_FLUSH_MS;
59712
- if (!raw) return 50;
59985
+ const fallback = isLegacyWindowsConsole() ? 150 : 50;
59986
+ if (!raw) return fallback;
59713
59987
  const parsed = Number(raw);
59714
- if (!Number.isFinite(parsed) || parsed < 16 || parsed > 1e3) return 50;
59988
+ if (!Number.isFinite(parsed) || parsed < 16 || parsed > 1e3) return fallback;
59715
59989
  return Math.round(parsed);
59716
59990
  })();
59717
59991
  function HistoryTypingCapture({
@@ -59737,6 +60011,10 @@ function HistoryTypingCapture({
59737
60011
  }, enabled && !pinned);
59738
60012
  return null;
59739
60013
  }
60014
+ function completedCountIncludingStep(completedStepIds, stepId, total) {
60015
+ const completed = completedStepIds.size + (completedStepIds.has(stepId) ? 0 : 1);
60016
+ return total > 0 ? Math.min(completed, total) : completed;
60017
+ }
59740
60018
  function lastMessageContent(entries, role) {
59741
60019
  for (let i = entries.length - 1; i >= 0; i--) {
59742
60020
  const entry = entries[i];
@@ -59913,6 +60191,15 @@ function AppInner({
59913
60191
  model2,
59914
60192
  initialPreset
59915
60193
  );
60194
+ const engineeringLifecycleBaseModeRef = (0, import_react92.useRef)(
60195
+ loadEngineeringLifecycleMode()
60196
+ );
60197
+ const engineeringLifecycleRef = (0, import_react92.useRef)(null);
60198
+ if (engineeringLifecycleRef.current === null) {
60199
+ engineeringLifecycleRef.current = new EngineeringLifecycleRuntime({
60200
+ mode: engineeringLifecycleBaseModeRef.current
60201
+ });
60202
+ }
59916
60203
  const planModeRef = (0, import_react92.useRef)(false);
59917
60204
  const latestVersionRef = (0, import_react92.useRef)(null);
59918
60205
  const [pendingEditReview, setPendingEditReview] = (0, import_react92.useState)(null);
@@ -59986,6 +60273,7 @@ function AppInner({
59986
60273
  const [pendingReplayViewer, setPendingReplayViewer] = (0, import_react92.useState)(null);
59987
60274
  const planStepsRef = (0, import_react92.useRef)(null);
59988
60275
  const completedStepIdsRef = (0, import_react92.useRef)(/* @__PURE__ */ new Set());
60276
+ const stepCompletionsRef = (0, import_react92.useRef)(/* @__PURE__ */ new Map());
59989
60277
  const planBodyRef = (0, import_react92.useRef)(null);
59990
60278
  const planSummaryRef = (0, import_react92.useRef)(null);
59991
60279
  const toolStartedAtRef = (0, import_react92.useRef)(null);
@@ -59999,6 +60287,7 @@ function AppInner({
59999
60287
  const extras = {};
60000
60288
  if (planBodyRef.current) extras.body = planBodyRef.current;
60001
60289
  if (planSummaryRef.current) extras.summary = planSummaryRef.current;
60290
+ if (stepCompletionsRef.current.size > 0) extras.stepCompletions = stepCompletionsRef.current;
60002
60291
  savePlanState(session, steps, completedStepIdsRef.current, extras);
60003
60292
  }, [session]);
60004
60293
  const [summary, setSummary] = (0, import_react92.useState)({
@@ -60537,8 +60826,13 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60537
60826
  if (restoredPlan && restoredPlan.steps.length > 0) {
60538
60827
  planStepsRef.current = restoredPlan.steps;
60539
60828
  completedStepIdsRef.current = new Set(restoredPlan.completedStepIds);
60829
+ stepCompletionsRef.current = new Map(Object.entries(restoredPlan.stepCompletions ?? {}));
60540
60830
  planBodyRef.current = restoredPlan.body ?? null;
60541
60831
  planSummaryRef.current = restoredPlan.summary ?? null;
60832
+ engineeringLifecycleRef.current?.recordPlanApproved(restoredPlan.steps);
60833
+ for (const stepId of restoredPlan.completedStepIds) {
60834
+ engineeringLifecycleRef.current?.recordStepCompleted(stepId);
60835
+ }
60542
60836
  const when = relativeTime(restoredPlan.updatedAt);
60543
60837
  const done = new Set(restoredPlan.completedStepIds);
60544
60838
  const summary2 = restoredPlan.summary ? ` - ${restoredPlan.summary}` : "";
@@ -60705,6 +60999,20 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60705
60999
  }
60706
61000
  }
60707
61001
  });
61002
+ (0, import_react92.useEffect)(() => {
61003
+ if (!tools || !codeMode) return;
61004
+ return tools.addToolInterceptor("engineering-lifecycle", (name, args) => {
61005
+ return engineeringLifecycleRef.current?.guardToolCall(name, args) ?? null;
61006
+ });
61007
+ }, [tools, codeMode]);
61008
+ (0, import_react92.useEffect)(() => {
61009
+ if (!tools || !codeMode) return;
61010
+ tools.setResultAugmenter((name, args, result) => {
61011
+ engineeringLifecycleRef.current?.recordToolResult(name, args, result);
61012
+ return result;
61013
+ });
61014
+ return () => tools.setResultAugmenter(null);
61015
+ }, [tools, codeMode]);
60708
61016
  (0, import_react92.useEffect)(() => {
60709
61017
  if (!tools || !codeMode) return;
60710
61018
  tools.setToolInterceptor(async (name, args) => {
@@ -60791,6 +61099,14 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60791
61099
  (on) => {
60792
61100
  setPlanMode(on);
60793
61101
  tools?.setPlanMode(on);
61102
+ if (on) {
61103
+ engineeringLifecycleRef.current?.setMode("strict");
61104
+ } else {
61105
+ const state = engineeringLifecycleRef.current?.snapshot().state;
61106
+ if (state === void 0 || state === "idle" || state === "complete" || state === "cancelled") {
61107
+ engineeringLifecycleRef.current?.setMode(engineeringLifecycleBaseModeRef.current);
61108
+ }
61109
+ }
60794
61110
  },
60795
61111
  [tools]
60796
61112
  );
@@ -60817,7 +61133,7 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60817
61133
  if (dashboardRef.current) return dashboardRef.current.url;
60818
61134
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
60819
61135
  const startup = (async () => {
60820
- const { startDashboardServer } = await import("./server-P6V2G3P6.js");
61136
+ const { startDashboardServer } = await import("./server-C25JNNZV.js");
60821
61137
  const handle = await startDashboardServer(
60822
61138
  {
60823
61139
  mode: "attached",
@@ -61423,6 +61739,7 @@ ${answer}`, "brand");
61423
61739
  completedStepIdsRef.current.add(stepId);
61424
61740
  persistPlanState();
61425
61741
  log.completePlanStep(stepId);
61742
+ engineeringLifecycleRef.current?.recordStepCompleted(stepId);
61426
61743
  return "ok";
61427
61744
  },
61428
61745
  markAllPlanStepsDone: () => {
@@ -61433,6 +61750,7 @@ ${answer}`, "brand");
61433
61750
  if (completedStepIdsRef.current.has(s.id)) continue;
61434
61751
  completedStepIdsRef.current.add(s.id);
61435
61752
  log.completePlanStep(s.id);
61753
+ engineeringLifecycleRef.current?.recordStepCompleted(s.id);
61436
61754
  added++;
61437
61755
  }
61438
61756
  if (added > 0) persistPlanState();
@@ -61560,6 +61878,16 @@ ${answer}`, "brand");
61560
61878
  }
61561
61879
  if (promptReport.blocked) return;
61562
61880
  }
61881
+ if (codeMode) {
61882
+ const before = engineeringLifecycleRef.current?.snapshot().state;
61883
+ engineeringLifecycleRef.current?.observeUserPrompt(text);
61884
+ const after = engineeringLifecycleRef.current?.snapshot().state;
61885
+ if (before === "idle" && after === "armed") {
61886
+ log.pushInfo(
61887
+ "Engineering lifecycle armed: high-risk mutations now require an approved structured plan."
61888
+ );
61889
+ }
61890
+ }
61563
61891
  pushHistory(text);
61564
61892
  const pasteDisplay = formatLongPaste(text);
61565
61893
  const userId = log.pushUser(pasteDisplay.displayText);
@@ -61750,9 +62078,11 @@ ${answer}`, "brand");
61750
62078
  setPendingChoice,
61751
62079
  planStepsRef,
61752
62080
  completedStepIdsRef,
62081
+ stepCompletionsRef,
61753
62082
  planBodyRef,
61754
62083
  planSummaryRef,
61755
62084
  persistPlanState,
62085
+ onPlanStepCompleted: (stepId) => engineeringLifecycleRef.current?.recordStepCompleted(stepId),
61756
62086
  log,
61757
62087
  session: session ?? null,
61758
62088
  codeModeOn: !!codeMode
@@ -62018,8 +62348,10 @@ ${answer}`, "brand");
62018
62348
  if (staged.mode === "approve") {
62019
62349
  togglePlanMode(false);
62020
62350
  const approvedSteps = planStepsRef.current;
62351
+ engineeringLifecycleRef.current?.recordPlanApproved(approvedSteps ?? []);
62021
62352
  if (approvedSteps && approvedSteps.length > 0) {
62022
62353
  completedStepIdsRef.current = /* @__PURE__ */ new Set();
62354
+ stepCompletionsRef.current = /* @__PURE__ */ new Map();
62023
62355
  log.showPlan({
62024
62356
  title: planSummaryRef.current ?? "plan",
62025
62357
  steps: approvedSteps.map((s) => ({
@@ -62035,9 +62367,11 @@ ${answer}`, "brand");
62035
62367
  } else if (staged.mode === "reject") {
62036
62368
  planStepsRef.current = null;
62037
62369
  completedStepIdsRef.current = /* @__PURE__ */ new Set();
62370
+ stepCompletionsRef.current = /* @__PURE__ */ new Map();
62038
62371
  planBodyRef.current = null;
62039
62372
  planSummaryRef.current = null;
62040
62373
  persistPlanState();
62374
+ engineeringLifecycleRef.current?.cancel();
62041
62375
  togglePlanMode(false);
62042
62376
  agentStore.dispatch({ type: "plan.drop" });
62043
62377
  marker = trimmed ? `plan rejected - ${tail}` : "plan cancelled";
@@ -62140,12 +62474,18 @@ ${answer}`, "brand");
62140
62474
  planStepsRef.current = p.steps ?? null;
62141
62475
  planSummaryRef.current = p.summary ?? null;
62142
62476
  planBodyRef.current = p.plan;
62477
+ stepCompletionsRef.current = /* @__PURE__ */ new Map();
62478
+ engineeringLifecycleRef.current?.recordPlanProposed(p.steps);
62143
62479
  break;
62144
62480
  }
62145
62481
  case "plan_checkpoint": {
62146
62482
  const p = payload;
62147
- const completed = completedStepIdsRef.current.size;
62148
62483
  const total = planStepsRef.current?.length ?? 0;
62484
+ const completed = completedCountIncludingStep(
62485
+ completedStepIdsRef.current,
62486
+ p.stepId,
62487
+ total
62488
+ );
62149
62489
  if (shouldAutoResolveCheckpoint(editModeRef.current)) {
62150
62490
  handleAutoCheckpointContinueRef.current(p.stepId, p.title);
62151
62491
  pauseGate.resolve(request.id, { type: "continue" });
@@ -62261,8 +62601,8 @@ ${answer}`, "brand");
62261
62601
  }
62262
62602
  }
62263
62603
  }
62264
- const completed = completedStepIdsRef.current.size;
62265
62604
  const total = planStepsRef.current?.length ?? 0;
62605
+ const completed = completedCountIncludingStep(completedStepIdsRef.current, stepId, total);
62266
62606
  const label = title2 ? `${stepId} - ${title2}` : stepId;
62267
62607
  const counter = total > 0 ? ` (${completed}/${total})` : "";
62268
62608
  log.pushInfo(t("app.continuingAfter", { label, counter }));
@@ -62353,6 +62693,10 @@ ${answer}`, "brand");
62353
62693
  merged.push(s);
62354
62694
  }
62355
62695
  planStepsRef.current = merged;
62696
+ engineeringLifecycleRef.current?.recordPlanApproved(merged);
62697
+ for (const s of merged) {
62698
+ if (completed.has(s.id)) engineeringLifecycleRef.current?.recordStepCompleted(s.id);
62699
+ }
62356
62700
  persistPlanState();
62357
62701
  agentStore.dispatch({ type: "plan.drop" });
62358
62702
  log.showPlan({
@@ -63069,10 +63413,7 @@ async function chatCommand(opts) {
63069
63413
  );
63070
63414
  if (searchEnabled()) {
63071
63415
  if (!tools) tools = new ToolRegistry();
63072
- registerWebTools(tools, {
63073
- webSearchEngine: webSearchEngine(),
63074
- webSearchEndpoint: webSearchEndpoint()
63075
- });
63416
+ registerWebTools(tools);
63076
63417
  }
63077
63418
  if (!opts.seedTools) {
63078
63419
  if (!tools) tools = new ToolRegistry();
@@ -63153,4 +63494,4 @@ async function chatCommand(opts) {
63153
63494
  export {
63154
63495
  chatCommand
63155
63496
  };
63156
- //# sourceMappingURL=chunk-ICSYGIPN.js.map
63497
+ //# sourceMappingURL=chunk-XMHP7BEE.js.map