reasonix 0.12.13 → 0.12.14

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.
package/dist/cli/index.js CHANGED
@@ -2816,6 +2816,7 @@ var CacheFirstLoop = class {
2816
2816
  return;
2817
2817
  }
2818
2818
  }
2819
+ let workspaceSwitchPending = false;
2819
2820
  for (const call of repairedCalls) {
2820
2821
  const name = call.function?.name ?? "";
2821
2822
  const args = call.function?.arguments ?? "{}";
@@ -2838,7 +2839,11 @@ var CacheFirstLoop = class {
2838
2839
  });
2839
2840
  for (const w of hookWarnings(preReport.outcomes, this._turn)) yield w;
2840
2841
  let result;
2841
- if (preReport.blocked) {
2842
+ if (workspaceSwitchPending) {
2843
+ result = JSON.stringify({
2844
+ error: `${name}: deferred because change_workspace in the same batch is awaiting the user's approval. Re-issue this call on your next turn \u2014 the sandbox root may have changed.`
2845
+ });
2846
+ } else if (preReport.blocked) {
2842
2847
  const blocking = preReport.outcomes[preReport.outcomes.length - 1];
2843
2848
  const reason = (blocking?.stderr || blocking?.stdout || "blocked by PreToolUse hook").trim();
2844
2849
  result = `[hook block] ${blocking?.hook.command ?? "<unknown>"}
@@ -2848,6 +2853,9 @@ ${reason}`;
2848
2853
  signal,
2849
2854
  maxResultTokens: DEFAULT_MAX_RESULT_TOKENS
2850
2855
  });
2856
+ if (name === "change_workspace" && result.includes('"WorkspaceConfirmationError:')) {
2857
+ workspaceSwitchPending = true;
2858
+ }
2851
2859
  const postReport = await runHooks({
2852
2860
  hooks: this.hooks,
2853
2861
  payload: {
@@ -7509,7 +7517,7 @@ import React27, { useState as useState12 } from "react";
7509
7517
 
7510
7518
  // src/cli/ui/App.tsx
7511
7519
  import * as pathMod7 from "path";
7512
- import { Box as Box22, Static, Text as Text20, useApp, useStdout as useStdout8 } from "ink";
7520
+ import { Box as Box22, Static, Text as Text20, useStdout as useStdout8 } from "ink";
7513
7521
  import React24, { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef6, useState as useState10 } from "react";
7514
7522
 
7515
7523
  // src/code/pending-edits.ts
@@ -8559,6 +8567,42 @@ async function handleModal(method, rest, body, ctx) {
8559
8567
  ctx.resolveEditReview(choice);
8560
8568
  return { status: 200, body: { resolved: true } };
8561
8569
  }
8570
+ if (kind === "workspace") {
8571
+ if (!ctx.resolveWorkspaceConfirm) {
8572
+ return { status: 503, body: { error: "workspace modal resolution not wired" } };
8573
+ }
8574
+ if (choice !== "switch" && choice !== "deny") {
8575
+ return { status: 400, body: { error: "workspace choice must be switch / deny" } };
8576
+ }
8577
+ ctx.resolveWorkspaceConfirm(choice);
8578
+ return { status: 200, body: { resolved: true } };
8579
+ }
8580
+ if (kind === "checkpoint") {
8581
+ if (!ctx.resolveCheckpointConfirm) {
8582
+ return { status: 503, body: { error: "checkpoint modal resolution not wired" } };
8583
+ }
8584
+ if (choice !== "continue" && choice !== "revise" && choice !== "stop") {
8585
+ return {
8586
+ status: 400,
8587
+ body: { error: "checkpoint choice must be continue / revise / stop" }
8588
+ };
8589
+ }
8590
+ ctx.resolveCheckpointConfirm(
8591
+ choice,
8592
+ typeof text === "string" && text.trim() ? text : void 0
8593
+ );
8594
+ return { status: 200, body: { resolved: true } };
8595
+ }
8596
+ if (kind === "revision") {
8597
+ if (!ctx.resolveReviseConfirm) {
8598
+ return { status: 503, body: { error: "revision modal resolution not wired" } };
8599
+ }
8600
+ if (choice !== "accept" && choice !== "reject") {
8601
+ return { status: 400, body: { error: "revision choice must be accept / reject" } };
8602
+ }
8603
+ ctx.resolveReviseConfirm(choice);
8604
+ return { status: 200, body: { resolved: true } };
8605
+ }
8562
8606
  return { status: 400, body: { error: `unknown modal kind: ${String(kind)}` } };
8563
8607
  }
8564
8608
  return { status: 405, body: { error: `method ${method} not supported on this path` } };
@@ -17249,7 +17293,6 @@ function App({
17249
17293
  codeMode,
17250
17294
  noDashboard
17251
17295
  }) {
17252
- const { exit: exit2 } = useApp();
17253
17296
  const [historical, setHistorical] = useState10([]);
17254
17297
  const [streaming, setStreaming] = useState10(null);
17255
17298
  const [input, setInput] = useState10("");
@@ -17606,6 +17649,52 @@ function App({
17606
17649
  broadcastDashboardEvent({ kind: "modal-down", modalKind: "edit-review" });
17607
17650
  };
17608
17651
  }, [pendingEditReview, broadcastDashboardEvent]);
17652
+ useEffect6(() => {
17653
+ if (!pendingWorkspace) return;
17654
+ broadcastDashboardEvent({
17655
+ kind: "modal-up",
17656
+ modal: { kind: "workspace", path: pendingWorkspace.path }
17657
+ });
17658
+ return () => {
17659
+ broadcastDashboardEvent({ kind: "modal-down", modalKind: "workspace" });
17660
+ };
17661
+ }, [pendingWorkspace, broadcastDashboardEvent]);
17662
+ useEffect6(() => {
17663
+ if (!pendingCheckpoint) return;
17664
+ broadcastDashboardEvent({
17665
+ kind: "modal-up",
17666
+ modal: {
17667
+ kind: "checkpoint",
17668
+ stepId: pendingCheckpoint.stepId,
17669
+ title: pendingCheckpoint.title,
17670
+ completed: pendingCheckpoint.completed,
17671
+ total: pendingCheckpoint.total
17672
+ }
17673
+ });
17674
+ return () => {
17675
+ broadcastDashboardEvent({ kind: "modal-down", modalKind: "checkpoint" });
17676
+ };
17677
+ }, [pendingCheckpoint, broadcastDashboardEvent]);
17678
+ useEffect6(() => {
17679
+ if (!pendingRevision) return;
17680
+ broadcastDashboardEvent({
17681
+ kind: "modal-up",
17682
+ modal: {
17683
+ kind: "revision",
17684
+ reason: pendingRevision.reason,
17685
+ remainingSteps: pendingRevision.remainingSteps.map((s) => ({
17686
+ id: s.id,
17687
+ title: s.title,
17688
+ action: s.action,
17689
+ ...s.risk ? { risk: s.risk } : {}
17690
+ })),
17691
+ ...pendingRevision.summary ? { summary: pendingRevision.summary } : {}
17692
+ }
17693
+ });
17694
+ return () => {
17695
+ broadcastDashboardEvent({ kind: "modal-down", modalKind: "revision" });
17696
+ };
17697
+ }, [pendingRevision, broadcastDashboardEvent]);
17609
17698
  const {
17610
17699
  slashMatches,
17611
17700
  slashSelected,
@@ -18174,6 +18263,31 @@ function App({
18174
18263
  remaining: pendingEdits.current.length
18175
18264
  };
18176
18265
  }
18266
+ if (pendingWorkspace) {
18267
+ return { kind: "workspace", path: pendingWorkspace.path };
18268
+ }
18269
+ if (pendingCheckpoint) {
18270
+ return {
18271
+ kind: "checkpoint",
18272
+ stepId: pendingCheckpoint.stepId,
18273
+ title: pendingCheckpoint.title,
18274
+ completed: pendingCheckpoint.completed,
18275
+ total: pendingCheckpoint.total
18276
+ };
18277
+ }
18278
+ if (pendingRevision) {
18279
+ return {
18280
+ kind: "revision",
18281
+ reason: pendingRevision.reason,
18282
+ remainingSteps: pendingRevision.remainingSteps.map((s) => ({
18283
+ id: s.id,
18284
+ title: s.title,
18285
+ action: s.action,
18286
+ ...s.risk ? { risk: s.risk } : {}
18287
+ })),
18288
+ ...pendingRevision.summary ? { summary: pendingRevision.summary } : {}
18289
+ };
18290
+ }
18177
18291
  return null;
18178
18292
  },
18179
18293
  resolveShellConfirm: (choice) => {
@@ -18200,6 +18314,22 @@ function App({
18200
18314
  resolve13(choice);
18201
18315
  }
18202
18316
  },
18317
+ resolveWorkspaceConfirm: (choice) => {
18318
+ handleWorkspaceConfirmRef.current(choice).catch(() => void 0);
18319
+ },
18320
+ resolveCheckpointConfirm: (choice, text) => {
18321
+ if (choice === "revise" && typeof text === "string") {
18322
+ const snap = pendingCheckpoint;
18323
+ setPendingCheckpoint(null);
18324
+ if (!snap) return;
18325
+ handleCheckpointReviseSubmitRef.current(text, snap).catch(() => void 0);
18326
+ return;
18327
+ }
18328
+ handleCheckpointConfirmRef.current(choice).catch(() => void 0);
18329
+ },
18330
+ resolveReviseConfirm: (choice) => {
18331
+ handleReviseConfirmRef.current(choice).catch(() => void 0);
18332
+ },
18203
18333
  // ---------- v0.14 mutation surface ----------
18204
18334
  reloadHooks: () => {
18205
18335
  const fresh = loadHooks({ projectRoot: codeMode ? currentRootDirRef.current : void 0 });
@@ -18220,7 +18350,10 @@ function App({
18220
18350
  togglePlanMode,
18221
18351
  pendingShell,
18222
18352
  pendingChoice,
18223
- pendingEditReview
18353
+ pendingEditReview,
18354
+ pendingWorkspace,
18355
+ pendingCheckpoint,
18356
+ pendingRevision
18224
18357
  ]);
18225
18358
  const stopDashboard = useCallback4(async () => {
18226
18359
  const h = dashboardRef.current;
@@ -18477,8 +18610,7 @@ function App({
18477
18610
  });
18478
18611
  if (result.exit) {
18479
18612
  if (activeLoopRef.current) stopLoop();
18480
- transcriptRef.current?.end();
18481
- exit2();
18613
+ quitProcess();
18482
18614
  return;
18483
18615
  }
18484
18616
  if (result.clear && result.info) {
@@ -19051,7 +19183,7 @@ function App({
19051
19183
  codeShowEdit,
19052
19184
  codeUndo,
19053
19185
  currentRootDir,
19054
- exit2,
19186
+ quitProcess,
19055
19187
  hookList,
19056
19188
  loop2,
19057
19189
  latestVersion,
@@ -19416,8 +19548,8 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
19416
19548
  []
19417
19549
  );
19418
19550
  const handleCheckpointReviseSubmit = useCallback4(
19419
- async (feedback) => {
19420
- const snap = stagedCheckpointRevise;
19551
+ async (feedback, snapOverride) => {
19552
+ const snap = snapOverride ?? stagedCheckpointRevise;
19421
19553
  setStagedCheckpointRevise(null);
19422
19554
  if (!snap) return;
19423
19555
  const label = snap.title ? `${snap.stepId} \xB7 ${snap.title}` : snap.stepId;
@@ -19501,6 +19633,14 @@ If the feedback only tweaks how you execute (extra constraints, style preference
19501
19633
  async (choice) => handleChoiceConfirmRef.current(choice),
19502
19634
  []
19503
19635
  );
19636
+ const handleWorkspaceConfirmRef = useRef6(handleWorkspaceConfirm);
19637
+ useEffect6(() => {
19638
+ handleWorkspaceConfirmRef.current = handleWorkspaceConfirm;
19639
+ }, [handleWorkspaceConfirm]);
19640
+ const handleCheckpointReviseSubmitRef = useRef6(handleCheckpointReviseSubmit);
19641
+ useEffect6(() => {
19642
+ handleCheckpointReviseSubmitRef.current = handleCheckpointReviseSubmit;
19643
+ }, [handleCheckpointReviseSubmit]);
19504
19644
  const handleChoiceCustomSubmit = useCallback4(
19505
19645
  async (answer) => {
19506
19646
  setStagedChoiceCustom(null);
@@ -19798,13 +19938,13 @@ function relativeTime2(date) {
19798
19938
  }
19799
19939
 
19800
19940
  // src/cli/ui/Setup.tsx
19801
- import { Box as Box24, Text as Text22, useApp as useApp2 } from "ink";
19941
+ import { Box as Box24, Text as Text22, useApp } from "ink";
19802
19942
  import TextInput from "ink-text-input";
19803
19943
  import React26, { useState as useState11 } from "react";
19804
19944
  function Setup({ onReady }) {
19805
19945
  const [value, setValue] = useState11("");
19806
19946
  const [error, setError] = useState11(null);
19807
- const { exit: exit2 } = useApp2();
19947
+ const { exit: exit2 } = useApp();
19808
19948
  const handleSubmit2 = (raw) => {
19809
19949
  const trimmed = raw.trim();
19810
19950
  if (trimmed === "/exit" || trimmed === "/quit") {
@@ -20063,7 +20203,7 @@ import { render as render2 } from "ink";
20063
20203
  import React30 from "react";
20064
20204
 
20065
20205
  // src/cli/ui/DiffApp.tsx
20066
- import { Box as Box26, Static as Static2, Text as Text24, useApp as useApp3, useInput } from "ink";
20206
+ import { Box as Box26, Static as Static2, Text as Text24, useApp as useApp2, useInput } from "ink";
20067
20207
  import React29, { useState as useState13 } from "react";
20068
20208
 
20069
20209
  // src/cli/ui/RecordView.tsx
@@ -20105,7 +20245,7 @@ function truncate2(s, max) {
20105
20245
 
20106
20246
  // src/cli/ui/DiffApp.tsx
20107
20247
  function DiffApp({ report }) {
20108
- const { exit: exit2 } = useApp3();
20248
+ const { exit: exit2 } = useApp2();
20109
20249
  const maxIdx = Math.max(0, report.pairs.length - 1);
20110
20250
  const initialIdx = report.firstDivergenceTurn ? report.pairs.findIndex((p) => p.turn === report.firstDivergenceTurn) : 0;
20111
20251
  const [idx, setIdx] = useState13(Math.max(0, initialIdx));
@@ -20548,10 +20688,10 @@ import { render as render3 } from "ink";
20548
20688
  import React32 from "react";
20549
20689
 
20550
20690
  // src/cli/ui/ReplayApp.tsx
20551
- import { Box as Box27, Static as Static3, Text as Text25, useApp as useApp4, useInput as useInput2 } from "ink";
20691
+ import { Box as Box27, Static as Static3, Text as Text25, useApp as useApp3, useInput as useInput2 } from "ink";
20552
20692
  import React31, { useMemo as useMemo4, useState as useState14 } from "react";
20553
20693
  function ReplayApp({ meta, pages }) {
20554
- const { exit: exit2 } = useApp4();
20694
+ const { exit: exit2 } = useApp3();
20555
20695
  const maxIdx = Math.max(0, pages.length - 1);
20556
20696
  const [idx, setIdx] = useState14(maxIdx);
20557
20697
  useInput2((input, key) => {
@@ -20916,12 +21056,12 @@ import { render as render4 } from "ink";
20916
21056
  import React34 from "react";
20917
21057
 
20918
21058
  // src/cli/ui/Wizard.tsx
20919
- import { Box as Box28, Text as Text26, useApp as useApp5, useInput as useInput3 } from "ink";
21059
+ import { Box as Box28, Text as Text26, useApp as useApp4, useInput as useInput3 } from "ink";
20920
21060
  import TextInput2 from "ink-text-input";
20921
21061
  import React33, { useState as useState15 } from "react";
20922
21062
  var CATALOG_BY_NAME = new Map(MCP_CATALOG.map((e) => [e.name, e]));
20923
21063
  function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
20924
- const { exit: exit2 } = useApp5();
21064
+ const { exit: exit2 } = useApp4();
20925
21065
  const [step, setStep] = useState15(existingApiKey ? "preset" : "apiKey");
20926
21066
  const [data, setData] = useState15({
20927
21067
  apiKey: existingApiKey ?? "",