@deslop/stash 0.1.1085 → 0.1.1089

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/README.md CHANGED
@@ -1,86 +1,7 @@
1
- # Stash
1
+ # @deslop/stash
2
2
 
3
- A personal inbox for links, written notes, photos and videos on one iPhone, and a CLI that saves to it. One package holds the Effect server for `dev`, the Expo iOS client with a Swift share extension, and the `stash` command.
4
-
5
- ## CLI
6
-
7
- Needs Node 26+ and the tailnet.
3
+ Saves a link or text to the owner's stash server over the tailnet and prints the read, tagged note as Markdown.
8
4
 
9
5
  ```bash
10
6
  vpx @deslop/stash@latest save '<link or text>' [--server <url>]
11
7
  ```
12
-
13
- The CLI saves the entry through the server's RPC, waits until the server has read and tagged it, and prints the note as Markdown on stdout: title, author, link, tags, summary, the AI's notes, topics, words in the images, the source it read and the `[mm:ss]` transcript. Progress goes to stderr. The server defaults to `STASH_SERVER`, then `https://dev.tailnet-8c4c.ts.net:8443`.
14
-
15
- ## Server
16
-
17
- - **Run.** `vp -C apps/stash run preview` builds `dist/server.js` and serves it on `127.0.0.1:5017`; `sudo tailscale serve --bg --https=8443 http://127.0.0.1:5017` publishes it on the tailnet. The tailnet is the only sign-in, so never bind it to `0.0.0.0` on `dev`, which has a public address.
18
- - **Environment.** `~/.deslop/stash.env` holds the variables in [.env.example](.env.example). `ANTHROPIC_API_KEY` turns tagging on; without it a note fails with the reason. Tagging uses `claude-haiku-5-5` at high effort through `@effect/ai-anthropic`. `STASH_DATA_DIR` defaults to `~/.deslop/stash`.
19
- - **Media.** The server runs the `yt-dlp` on `PATH` and downloads the Whisper model into `$XDG_CACHE_HOME/deslop/media` on first use. Published captions win; Whisper `small.en` takes about a quarter of the audio's length, up to two hours of audio. TikTok, X, YouTube and Instagram links go through `yt-dlp`, also when their page could not be read.
20
- - **Proxy.** When `STASH_PROXY` holds an `http://` proxy URL, every request for a source exits through it: `yt-dlp`, pages, APIs, preview images and the reader. Without it, the server reads with its own address. `{session}` in the URL becomes a new random value for each `yt-dlp` run and each request, so a rotating residential proxy keeps one exit address while a run downloads. A request that a site blocks, or that the exit drops, retries twice from new exit addresses. On `dev` it is the owner's [DataImpulse](https://app.dataimpulse.com) residential plan "stash": pay-as-you-go traffic that never expires, with `__sessid.{session}` after the login.
21
- - **Sources.** Web pages become Markdown with their headings, lists and link targets. GitHub repositories give their README, issues and pull requests their comments, X posts their long-form articles, and TikTok photo posts every slide. A page that holds no text, such as a JavaScript app or a PDF, goes to the [Jina Reader](https://jina.ai/reader/), which also takes blocked pages; its bot-check pages count as failures.
22
- - **Storage.** SQLite at `stash.db` in `STASH_DATA_DIR`, one row per note holding its JSON. The notes on `dev` are production data: a change to the note's shape ships with a migration that converts the stored rows, never a reset. Previews and uploaded files sit beside it in `images/` and `files/`.
23
- - **Sync.** `notes.watch` sends every note's list fields once, then only the notes that changed, at most every 400 ms. `notes.get` loads the long texts and `notes.search` searches transcripts and pages on the server.
24
- - **Routes.** The app uses the JSON WebSocket RPC at `/api/rpc` and loads previews from `/api/images/<id>`. The share extension posts `{id, text}` to `/api/capture`. Photos and videos arrive as the raw body of `/api/files/<id>`.
25
- - **Organizer.** Claude reads each entry as a developer would and writes the notes the owner reads instead of the source: a plain title of at most 32 characters, a one-sentence summary, one to three tags, search topics, short Markdown notes of at most 10 lines (facts, steps, bold names and links, with headings only for long sources), and the words in the images. The preview, the photo post's slides and 12 evenly spaced video stills, up to 768 pixels wide, go with it. A short link resolves before saving, so another share of the same post finds the saved note.
26
-
27
- ## iOS client
28
-
29
- - **Capture.** Links, text, photos and videos arrive from the share sheet, which uploads in a background session and closes at once. When the app opens with a new link or image copied, a sheet asks whether to save it; the clipboard is read only after Save, so iOS shows its paste banner only then. The sheet closes as soon as either button is pressed. The pencil writes a note.
30
- - **List.** The layout follows iOS Mail: tag chips filter apart from search, and the bottom bar holds the kind filter, the search field and write. A row shows the title, two lines of summary, the author and the date; a note being read shows its title, a redacted summary and the byline. A long press opens the note in its app, regenerates or deletes it; swipe deletes. Search keeps the last results on screen while the next ones load.
31
- - **Note page.** A reading page like Mail's message: preview, title, author, app and date, the summary, then the AI's notes in the system body font, with headings, bold names and tappable links. Tags follow; the transcript, the source text and the words in the images stay on the server for search and the CLI. The app's logo opens the link; the menu shares, regenerates or deletes. A note the server could not read shows why and a Try Again button.
32
- - **Native module.** `modules/native` checks the clipboard without reading it and adds the bottom-bar search field through `@expo/ui`'s modifier API. The logos come from `@deslop/components-mobile`, which renders svgl's SVGs natively and cuts out their white parts for menu icons.
33
- - **Share extension.** `@bacons/apple-targets` adds `targets/share` at prebuild. It finds the server in the app's `StashServer` Info.plist key and uploads from the App Group `group.<app bundle id>`. A failed background upload is not reported, because the sheet has already closed.
34
- - **Variants.** `APP_VARIANT` from `eas.json` picks `development` for the simulator build, as `stash dev` with the bundle identifier `xyz.mp281x.stash.dev`, or `production`. `APPLE_TEAM_ID` comes from the EAS environment.
35
-
36
- ## Releases
37
-
38
- On main, `deploy.yaml` compares `apps/stash`, `packages` and the lockfile with the commit of the last EAS Update. When they changed, a known native fingerprint ships the JavaScript as a new update; a new one first builds on GitHub's `xcode-27` runner with `eas build --local` and submits to TestFlight. A newer merge cancels the older run, and the next one ships both. Each release is version `0.1.<run>` with build number `<run>`.
39
-
40
- ## Simulator
41
-
42
- The Simulator workflow builds the app for the iOS Simulator once per native fingerprint, as the artifact `stash-simulator-<fingerprint>`; it runs only for a push that changes `apps/stash`, `packages` or the lockfile, so a branch without one reuses the artifact another branch built. The app holds the JavaScript of the commit that built it, so replace its bundle with the branch's own before you install it. `device_open` returns the `agent-device` command and its flags.
43
-
44
- ```bash
45
- run=$(gh api "repos/MP281X/deslop/actions/artifacts?name=stash-simulator-<fingerprint>" --jq '.artifacts[0].workflow_run.id')
46
- gh run download $run --name stash-simulator-<fingerprint> --dir /tmp/stash-sim && tar -xzf /tmp/stash-sim/simulator.tar.gz -C /tmp/stash-sim
47
- APP_VARIANT=development vp -C apps/stash exec expo export:embed --platform ios --dev false --bundle-output /tmp/stash-sim/stashdev.app/main.jsbundle --assets-dest /tmp/stash-sim/stashdev.app
48
- <agent-device> install xyz.mp281x.stash.dev /tmp/stash-sim/stashdev.app <flags>
49
- <agent-device> open xyz.mp281x.stash.dev <flags>
50
- ```
51
-
52
- ## Checks before a build
53
-
54
- ```bash
55
- vp -C apps/stash exec expo config --type public
56
- vp -C apps/stash exec expo prebuild --platform ios --no-install --clean && rm -rf apps/stash/ios
57
- vp -C apps/stash exec expo export --platform ios --output-dir /tmp/stash-export
58
- ```
59
-
60
- A Swift change compiles first in the simulator build on CI.
61
-
62
- <details>
63
- <summary>For agents</summary>
64
-
65
- | Owner | Decision |
66
- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
67
- | Package | Published as `@deslop/stash`; app dependencies are `devDependencies`. ONNX Runtime and sharp stay external through `deps.neverBundle`, because only the server loads them |
68
- | Media | `yt-dlp` stays an external binary because no maintained JavaScript extractor covers its sites. The iOS client never imports `services/media` |
69
- | Transcription | Update Transformers.js, `onnxruntime-common`, `onnxruntime-node` and sharp together |
70
- | Fingerprint | `fingerprint.config.js` adds `targets/share`, whose Swift the Expo fingerprint does not read |
71
- | Toolbar order | `@expo/ui` shows the outermost toolbar's items first, so the list nests one `Toolbar` for write inside the one for the filter, with the search modifier between them; unproven until build |
72
-
73
- | Rejected | Reason |
74
- | --------------------------------------- | --------------------------------------------------------------------------------------------- |
75
- | `expo-sharing` and `expo-share-intent` | Both open the main app to save; sharing from TikTok must not leave TikTok |
76
- | React Native inside the share extension | It costs most of the extension's memory |
77
- | A patch of `@expo/ui` | A patch breaks with each upgrade; the local module uses the public extension API |
78
- | EAS cloud builds from the workflow | The free plan allows 15 iOS builds a month; macOS runners are free for this public repository |
79
- | Binary RPC serialization | It failed to reopen a cancelled watch |
80
- | An app outbox | The extension uploads in a background session, and the app saves through the RPC directly |
81
- | `yt-dlp` and Whisper inside the CLI | API keys and models live on the server, and every analysis stays a note |
82
- | Mozilla Readability for web pages | It needs a DOM library; the cheerio Markdown walker keeps headings and links without one |
83
- | Reddit and Hacker News readers | The owner saves neither |
84
- | `yt-dlp --impersonate chrome` | It changed no result on the 21 probe links |
85
-
86
- </details>
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { $o as match$2, $t as TaggedError, Ad as match$1, An as optional$2, Ao as forEach, As as suspend, Au as some$1, Bl as sync, Bo as interrupt$1, C as runMain, Co as fail$1, D as QuitError, Dc as Clock, Dl as interrupt, Ds as serviceOption, Dt as ArraySchema, E as layer, Ec as round, Ed as isSome, El as failCause$1, Eo as flatMap$1, Fs as timeout, Ft as Error$1, Gc as squash, Gd as withFiber$1, Go as logError, Gs as useSpan, Gt as NonEmptyArray, Ho as isEffect, Hs as uninterruptibleMask, Hu as fail$2, Ic as findError, J as RequestId, Jc as effect, Ji as unwrap, Js as whileLoop, K as layerJson, Kd as assignProperty, Ks as void_, L as option, Lo as gen, Ls as timeoutOrElse, Lt as FalseLiterals, Ml as ConsoleRef, Mn as tag, No as forkIn, Ns as tapCause, Nt as Defect, O as Terminal, Os as succeed$1, Ou as reduce, P as String$7, Pd as some, Pn as toCodecStringTree, Po as forkScoped, Qo as mapError, Qs as withParentSpan, Ro as ignore, Sd as getOrElse, Sf as pipeArguments, Ss as runForkWith, St as HttpClientErrorSchema, T as errorReported, Td as isNone, Tl as fail, Ts as scoped, Tu as match, U as withRunClient, V as Stdio, Vc as interruptors, Vd as Prototype, Vo as interruptible, Vt as Literal, W as RpcSerialization, Xl as taggedEnum, Xo as map$2, Yo as makeSpanScoped, Ys as withFiber, Yu as succeed$2, Z as constPing, Zt as String$6, _l as MinimumLogLevel, _o as context, _t as layerWebSocketConstructorGlobal, ad as empty$1, at as spanAttributes, au as filter$2, b as LogToStderr, ba as getCurrent, bf as identity, bs as retryOrElse, bu as isReadonlyArrayNonEmpty, cd as getOrUndefinedUnsafe, cf as isNotUndefined, cl as addFinalizerExit, co as catchCause, ct as makeCollectorUnsafe, cu as findFirstIndex, dc as isNonEmpty, do as catchFilter, dr as make$2, dt as SocketError, ef as format, en as TrueLiterals, eo as andThen, es as matchCauseEffect, et as exitSchema, fn as decodeUnknownEffect, fr as value, fs as provide$1, ft as SocketErrorReason, gc as replace, gd as filter, gf as constVoid, gs as raceFirst, gt as layerWebSocket, h as NotesError, hd as exists, ho as catchTags, ia as bounded, id as add, if as hasProperty, is as onError, it as isStreamSchema, j as Crypto, jd as none, jn as optionalKey, jo as forever, js as sync$1, k as isQuitError, kd as map$3, kl as isFailure, ko as fnUntraced, kt as BooleanLiterals, ld as getUnsafe, lo as catchCauseIf, ls as orDie, lu as findLast, ma as take, mn as encodeEffect, mo as catchTag, ms as provideService, mt as SocketReadError, nc as min, nd as Reference, no as annotateLogs, nr as empty, nu as empty$2, oa as end, od as get, ol as Scope, oo as cached, or as merge, ot as spanName, pa as shutdownUnsafe, ps as provideContext, pu as getSomes, qo as logInfo, qu as isSuccess, rc as spaced, rd as Service, rr as fromInput, rt as getStreamSchemas, sa as failCause, sl as addFinalizer, sn as Union, so as callback, ss as onInterrupt, st as Collector, su as findFirst, t as RpcContracts, tc as exponential, td as toMillis, tl as provide$2, ua as offerAll, ud as make$3, ui as filter$1, un as decodeSync, ut as Socket, va as makeUnsafe, vf as dual, vi as fromQueue, vs as result, w as errorExitCode, wd as getOrUndefined, wl as die, wu as map$4, xa as interrupt$2, xd as fromUndefinedOr, xf as pipe, xo as ensuring, xu as join, yn as is, yo as delay, zc as hasInterrupts, zi as runHead, zo as ignoreCause } from "./contracts-B0mJTvsC.mjs";
2
+ import { $o as makeSpanScoped, $s as withFiber, $t as String$6, Ad as exists, Ao as flatMap$1, As as serviceOption, Bd as isNone, C as runMain, Cd as getOrUndefinedUnsafe, Co as delay, Ct as HttpClientErrorSchema, D as QuitError, Dc as replace, Do as fail$1, E as layer, Es as runForkWith, Eu as getSomes, F as String$7, Ff as identity, Fn as tag, Fo as forever, Fs as sync$1, Ft as Defect, G as RpcSerialization, Gd as match$1, Go as interruptible, H as Stdio, Hi as runHead, Ho as ignore, Id as fromUndefinedOr, If as pipe, Il as die, Kd as none, Ko as isEffect, Ks as uninterruptibleMask, L as option, Lc as round, Ld as getOrElse, Lf as pipeArguments, Ll as fail, Ln as toCodecStringTree, Lo as forkIn, Ls as tapCause, Lt as Error$1, Lu as map$4, Ms as succeed$1, Nf as dual, Nn as optional$2, No as fnUntraced, Nu as isReadonlyArrayNonEmpty, O as Terminal, Pn as optionalKey, Po as forEach, Ps as suspend, Pu as join, Q as constPing, Qc as interruptors, Qi as unwrap, Ql as sync, Qs as whileLoop, Rc as Clock, Rl as failCause$1, Ro as forkScoped, Ru as match, Sa as makeUnsafe, Sc as isNonEmpty, Sf as isNotUndefined, Sn as is, Ss as result, Su as findLast, T as errorReported, Ta as interrupt$2, Td as make$3, To as ensuring, Uo as ignoreCause, Ut as Literal, Uu as some$1, Vd as isSome, Vl as isFailure, Vo as gen, Vs as timeoutOrElse, Vu as reduce, W as withRunClient, Wd as map$3, Wl as ConsoleRef, Wo as interrupt$1, Xc as hasInterrupts, Xs as void_, Y as RequestId, Yd as some, Yo as logError, Ys as useSpan, Zo as logInfo, _a as shutdownUnsafe, _d as Reference, _n as encodeEffect, _s as provideContext, _t as layerWebSocket, ad as isSuccess, ar as empty, at as isStreamSchema, b as LogToStderr, bd as empty$1, bl as addFinalizerExit, bs as raceFirst, bu as findFirst, ca as bounded, cs as onError, ct as Collector, da as failCause, dc as min, do as callback, ds as onInterrupt, dt as Socket, ed as fail$2, es as map$2, fl as provide$2, fo as catchCause, ft as SocketError, gs as provide$1, h as NotesError, hd as toMillis, hn as decodeUnknownEffect, ho as catchFilter, hr as value, ht as SocketReadError, hu as empty$2, io as andThen, is as matchCauseEffect, it as getStreamSchemas, j as Crypto, jd as filter, jf as constVoid, jt as BooleanLiterals, k as isQuitError, kl as MinimumLogLevel, ks as scoped, kt as ArraySchema, lr as merge, lt as makeCollectorUnsafe, lu as taggedEnum, ma as offerAll, mf as format, mr as make$2, nc as withParentSpan, nf as Prototype, nn as TaggedError, ns as mapError, of as withFiber$1, ol as effect, oo as annotateLogs, or as fromInput, ot as spanAttributes, pc as spaced, pi as filter$1, pn as decodeSync, po as catchCauseIf, ps as orDie, pt as SocketErrorReason, q as layerJson, qc as findError, qt as NonEmptyArray, rl as squash, rn as TrueLiterals, rs as match$2, sc as exponential, sd as succeed$2, sf as assignProperty, st as spanName, t as RpcContracts, tt as exitSchema, ua as end, un as Union, uo as cached, va as take, vd as Service, vf as hasProperty, vl as Scope, vo as catchTag, vs as provideService, vt as layerWebSocketConstructorGlobal, vu as filter$2, w as errorExitCode, wa as getCurrent, wd as getUnsafe, ws as retryOrElse, xd as get, xi as fromQueue, xo as context, xu as findFirstIndex, yd as add, yl as addFinalizer, yo as catchTags, zd as getOrUndefined, zl as interrupt, zs as timeout, zt as FalseLiterals } from "./contracts-CdQiWFv_.mjs";
3
3
  //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/workers/WorkerError.js
4
4
  /**
5
5
  * Worker error reason for failures while spawning or setting up a worker.
@@ -1627,18 +1627,6 @@ const cursorHide = `${ESC}?25l`;
1627
1627
  /**
1628
1628
  * @internal
1629
1629
  */
1630
- const cursorLeft = `${ESC}G`;
1631
- /**
1632
- * @internal
1633
- */
1634
- const cursorSavePosition = `${ESC}s`;
1635
- /**
1636
- * @internal
1637
- */
1638
- const cursorRestorePosition = `${ESC}u`;
1639
- /**
1640
- * @internal
1641
- */
1642
1630
  const eraseLine = `${ESC}2K`;
1643
1631
  /**
1644
1632
  * @internal
@@ -2223,7 +2211,7 @@ const handleConfirmClear = (options) => {
2223
2211
  const figures = yield* getTheme(options);
2224
2212
  const confirmMessage = state.value ? options.placeholder.defaultConfirm : options.placeholder.defaultDeny;
2225
2213
  const promptText = renderPrompt(confirmMessage, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
2226
- return eraseText(promptText, columns) + (eraseLine + cursorLeft);
2214
+ return eraseText(promptText, columns) + (eraseLine + "\x1B[G");
2227
2215
  });
2228
2216
  };
2229
2217
  const renderConfirmNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
@@ -2264,7 +2252,7 @@ const handleDateClear = (options) => {
2264
2252
  return fnUntraced(function* (state, _) {
2265
2253
  const columns = yield* (yield* Terminal).columns;
2266
2254
  const figures = yield* getTheme(options);
2267
- const resetCurrentLine = eraseLine + cursorLeft;
2255
+ const resetCurrentLine = eraseLine + "\x1B[G";
2268
2256
  const parts = reduce(state.dateParts, "", (doc, part) => doc + part.toString());
2269
2257
  const promptText = renderPrompt(parts, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
2270
2258
  const errorText = isSome(state.error) ? match(state.error.value.split(NEWLINE_REGEXP), {
@@ -2280,7 +2268,7 @@ const renderDateError = (state, pointer, theme) => {
2280
2268
  if (isReadonlyArrayNonEmpty(errorLines)) {
2281
2269
  const prefix = annotateSymbol(theme, pointer, theme.errorColor);
2282
2270
  const lines = map$4(errorLines, (str) => annotateErrorLine(theme, str));
2283
- return cursorSavePosition + "\n" + separateSymbol(prefix, lines.join("\n")) + cursorRestorePosition;
2271
+ return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
2284
2272
  }
2285
2273
  }
2286
2274
  return "";
@@ -2707,7 +2695,7 @@ const handleNumberClear = (options) => {
2707
2695
  return fnUntraced(function* (state, _) {
2708
2696
  const columns = yield* (yield* Terminal).columns;
2709
2697
  const figures = yield* getTheme(options);
2710
- const resetCurrentLine = eraseLine + cursorLeft;
2698
+ const resetCurrentLine = eraseLine + "\x1B[G";
2711
2699
  const errorText = renderNumberError(state, figures.pointerSmall, figures, { plain: true });
2712
2700
  const promptText = renderNumberOutput(state, figures.prefix, figures.pointerSmall, options, figures, { plain: true });
2713
2701
  return clearOutputWithError(promptText, columns, errorText) + resetCurrentLine;
@@ -2726,7 +2714,7 @@ const renderNumberError = (state, pointer, theme, renderOptions) => {
2726
2714
  if (renderOptions?.plain === true) return separateSymbol(pointer, errorLines.join("\n"));
2727
2715
  const prefix = annotateSymbol(theme, pointer, theme.errorColor);
2728
2716
  const lines = map$4(errorLines, (str) => annotateErrorLine(theme, str));
2729
- return cursorSavePosition + "\n" + separateSymbol(prefix, lines.join("\n")) + cursorRestorePosition;
2717
+ return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
2730
2718
  }
2731
2719
  });
2732
2720
  return "";
@@ -2951,7 +2939,7 @@ const handleSelectRender = (options) => {
2951
2939
  const handleSelectClear = (options) => fnUntraced(function* (state, _) {
2952
2940
  const columns = yield* (yield* Terminal).columns;
2953
2941
  const figures = yield* getTheme(options);
2954
- const clearPrompt = eraseLine + cursorLeft;
2942
+ const clearPrompt = eraseLine + "\x1B[G";
2955
2943
  const promptText = renderSelectOutput(figures.prefix, figures.pointerSmall, options, figures, { plain: true });
2956
2944
  const choicesText = renderSelectChoices(state, options, figures, { plain: true });
2957
2945
  return eraseText(withSelectHeader(promptText, choicesText), columns) + clearPrompt;
@@ -2977,7 +2965,7 @@ const handleSelectProcess = (options) => {
2977
2965
  const renderClearScreen = /*#__PURE__*/ fnUntraced(function* (state, options) {
2978
2966
  const columns = yield* (yield* Terminal).columns;
2979
2967
  const figures = yield* getTheme(options);
2980
- const resetCurrentLine = eraseLine + cursorLeft;
2968
+ const resetCurrentLine = eraseLine + "\x1B[G";
2981
2969
  const errorText = renderTextError(state, figures.pointerSmall, figures, { plain: true });
2982
2970
  return clearOutputWithError(renderTextOutput(state, figures.prefix, figures.pointerSmall, options, figures, { plain: true }), columns, errorText) + resetCurrentLine;
2983
2971
  });
@@ -3003,7 +2991,7 @@ const renderTextError = (nextState, pointer, theme, renderOptions) => {
3003
2991
  if (renderOptions?.plain === true) return separateSymbol(pointer, errorLines.join("\n"));
3004
2992
  const prefix = annotateSymbol(theme, pointer, theme.errorColor);
3005
2993
  const lines = map$4(errorLines, (str) => annotateErrorLine(theme, str));
3006
- return cursorSavePosition + "\n" + separateSymbol(prefix, lines.join("\n")) + cursorRestorePosition;
2994
+ return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
3007
2995
  }
3008
2996
  });
3009
2997
  return "";
@@ -3161,7 +3149,7 @@ const basePrompt = (options, type) => {
3161
3149
  const handleToggleClear = /*#__PURE__*/ fnUntraced(function* (options) {
3162
3150
  const columns = yield* (yield* Terminal).columns;
3163
3151
  const figures = yield* getTheme(options);
3164
- const clearPrompt = eraseLine + cursorLeft;
3152
+ const clearPrompt = eraseLine + "\x1B[G";
3165
3153
  const toggleText = options.active + " " + separateSymbol(figures.toggleSeparator, options.inactive);
3166
3154
  const promptText = renderPrompt(toggleText, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
3167
3155
  return eraseText(promptText, columns) + clearPrompt;
@@ -7612,7 +7600,7 @@ const runWith = (command, config) => {
7612
7600
  };
7613
7601
  //#endregion
7614
7602
  //#region package.json
7615
- var version = "0.1.1085";
7603
+ var version = "0.1.1089";
7616
7604
  //#endregion
7617
7605
  //#region src/main.cli.ts
7618
7606
  function section(title, text) {