opencode-landstrip 0.14.1 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tui.ts +17 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-landstrip",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Landlock-based sandboxing for opencode with landstrip",
5
5
  "keywords": [
6
6
  "landlock",
package/tui.ts CHANGED
@@ -64,7 +64,7 @@ function sandboxSummary(baseDirectory: string, optionOverrides: SandboxConfigOve
64
64
  `allow write: ${list(config.filesystem.allowWrite)}`,
65
65
  `deny write: ${list(config.filesystem.denyWrite)}`,
66
66
  '',
67
- 'esc or any key to close',
67
+ 'Press esc or enter to close',
68
68
  ].join('\n');
69
69
  }
70
70
 
@@ -118,7 +118,10 @@ const tui: TuiPlugin = async (api, options, meta) => {
118
118
  activeId = undefined;
119
119
  api.ui.dialog.clear();
120
120
  }
121
- pump();
121
+ // Defer: `clear()` above tears the dialog down by calling its `onClose`,
122
+ // and the host pops the stack asynchronously. Opening the next dialog
123
+ // synchronously here would race that teardown and get wiped.
124
+ queueMicrotask(pump);
122
125
  }
123
126
 
124
127
  async function replyPermission(
@@ -212,9 +215,11 @@ const tui: TuiPlugin = async (api, options, meta) => {
212
215
  () => {
213
216
  // Dialog dismissed (esc) without a choice: drop our hold so the next
214
217
  // pending permission can surface, but leave it unresolved upstream.
218
+ // The host pops the dialog itself; calling `clear()` here would re-enter
219
+ // this `onClose` (clear() invokes every entry's onClose) and loop until
220
+ // the stack overflows. Defer `pump()` so the pop settles first.
215
221
  if (activeId === permission.id) activeId = undefined;
216
- api.ui.dialog.clear();
217
- pump();
222
+ queueMicrotask(pump);
218
223
  },
219
224
  );
220
225
  }
@@ -233,14 +238,14 @@ const tui: TuiPlugin = async (api, options, meta) => {
233
238
  const directory = api.state.path.directory || process.cwd();
234
239
  const message = sandboxSummary(directory, optionOverrides);
235
240
 
236
- api.ui.dialog.replace(
237
- () =>
238
- api.ui.DialogAlert({
239
- title: 'Sandbox Configuration',
240
- message,
241
- onConfirm: () => api.ui.dialog.clear(),
242
- }),
243
- () => api.ui.dialog.clear(),
241
+ // No `onConfirm`/`onClose` that call `clear()`: the host already pops the
242
+ // dialog on enter/esc/click, and its `clear()` re-invokes every entry's
243
+ // `onClose`, so a `clear()` in there recurses forever and freezes the TUI.
244
+ api.ui.dialog.replace(() =>
245
+ api.ui.DialogAlert({
246
+ title: 'Sandbox Configuration',
247
+ message,
248
+ }),
244
249
  );
245
250
  };
246
251