@deslop/stash 0.1.1060 → 0.1.1062

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
@@ -16,17 +16,19 @@ The CLI saves the entry through the server's RPC, waits until the server has rea
16
16
 
17
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
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. `STASH_AI_MODEL` defaults to `claude-haiku-5-5`, at high effort. `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. `STASH_MEDIA_PROXY` lists proxies, separated by commas; `yt-dlp` starts with the one that last got through and moves on when a site blocks it. On `dev` it lists the five Mullvad proxies from the environment skill.
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.
20
22
  - **Storage.** SQLite at `stash.db` in `STASH_DATA_DIR`, one row per note, without migrations: a change to its shape can drop it. Previews and uploaded files sit beside it in `images/` and `files/`.
21
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.
22
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>`.
23
- - **Organizer.** Claude reads each entry as a developer would: a title of at most 32 characters, a one-line summary, one to three tags, search topics, two to six lines of notes, and the words in the images. The preview and six video stills go with it. A short link resolves before saving, so another share of the same post finds the saved note.
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 40 characters, a summary of one or two sentences, one to three tags, search topics, Markdown notes whose length follows the content (headings, facts, steps, bold names and links), 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.
24
26
 
25
27
  ## iOS client
26
28
 
27
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 pencil writes a note.
28
- - **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 long press opens the note in its app, regenerates or deletes it; swipe deletes. A note the server could not read shows why, and a tap retries it.
29
- - **Note page.** The title sits in the bar and the app's logo opens the link. Below come the preview, the tags and the AI's notes. Pulling down regenerates the 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 link and a spinner. 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, then the transcript, the source text and the words in the images, each collapsed. 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.
30
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.
31
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.
32
34
  - **Variants.** `APP_VARIANT` from `eas.json` picks `development` or `production`; the development build installs beside the TestFlight one. `APPLE_TEAM_ID` comes from the EAS environment.
@@ -80,5 +82,8 @@ A Swift change compiles first in the simulator build on CI.
80
82
  | Binary RPC serialization | It failed to reopen a cancelled watch |
81
83
  | An app outbox | The extension uploads in a background session, and the app saves through the RPC directly |
82
84
  | `yt-dlp` and Whisper inside the CLI | API keys and models live on the server, and every analysis stays a note |
85
+ | Mozilla Readability for web pages | It needs a DOM library; the cheerio Markdown walker keeps headings and links without one |
86
+ | Reddit and Hacker News readers | The owner saves neither |
87
+ | `yt-dlp --impersonate chrome` | It changed no result on the 21 probe links |
83
88
 
84
89
  </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 { $ as Socket, $l as dual, $o as MinimumLogLevel, Ao as effect, Ar as take, At as TaggedError, B as constPing, Ci as fnUntraced, Cl as assignProperty, Cr as failCause, Ct as Literal, D as option, Di as forkIn, Do as squash, Ea as timeoutOrElse, Er as offerAll, F as layerJson, Fa as whileLoop, Fi as interruptible, Fs as Reference, Gc as succeed$2, Gn as fromQueue, Gt as tag, Ha as exponential, Hc as isSuccess, Hl as hasProperty, Ho as Scope, Hs as getUnsafe, Ht as is, Ia as withFiber, Ic as fail$2, Ii as isEffect, Ir as makeUnsafe, Is as Service, It as decodeSync, J as spanAttributes, Jc as exists, Ji as matchCauseEffect, K as getStreamSchemas, Ki as mapError, Ks as Prototype, L as RequestId, Lo as provide$1, Lr as getCurrent, Ls as add, Lt as decodeUnknownEffect, Mi as ignore, N as withRunClient, Na as useSpan, Ni as ignoreCause, Nt as Union, Oi as forkScoped, Ot as String$6, P as RpcSerialization, Pa as void_, Pi as interrupt$1, Ps as toMillis, Qi as onError, Qs as empty$2, Rr as interrupt$2, Rs as empty$1, Rt as encodeEffect, Sa as tapCause, Sc as reduce, Sl as withFiber$1, So as interruptors, Sr as end, Ss as sync, Ti as forever, Tt as NonEmptyArray, U as exitSchema, Ua as min, Ui as makeSpanScoped, Ul as isNotUndefined, Uo as addFinalizer, Us as make$3, Ut as optional$2, Vi as logInfo, Vs as getOrUndefinedUnsafe, Wa as spaced, Wi as map$3, Wo as addFinalizerExit, Wt as optionalKey, X as Collector, Xa as isEmpty, Xr as andThen, Y as spanName, Z as makeCollectorUnsafe, Za as isNonEmpty, Zl as constVoid, Zr as annotateLogs, _ as QuitError, _a as serviceOption, _o as findError, _t as BooleanLiterals, aa as provide, al as isSome, ar as runHead, at as layerWebSocket, ba as suspend, bc as match, bi as flatMap$1, bo as hasInterrupts, br as bounded, c as NotesError, ca as raceFirst, cl as map$4, dt as HttpClientErrorSchema, el as fromUndefinedOr, et as SocketError, fa as runForkWith, fi as context, fl as some, g as layer, gc as join, gi as ensuring, gt as ArraySchema, h as errorReported, ha as scoped, hc as isReadonlyArrayNonEmpty, hn as value, ic as findLast, ii as catchCauseIf, il as isNone, is as interrupt, j as Stdio, ja as uninterruptibleMask, ji as gen, jl as format, js as taggedEnum, jt as TrueLiterals, kr as shutdownUnsafe, la as result, li as catchTag, ll as match$1, lo as round, m as errorExitCode, mi as delay, mn as make$2, ms as ConsoleRef, na as orDie, nc as findFirst, ni as callback, ns as fail, nu as pipe, oa as provideContext, oi as catchFilter, on as empty, os as isFailure, ot as layerWebSocketConstructorGlobal, p as runMain, pr as unwrap, q as isStreamSchema, qi as match$2, qt as toCodecStringTree, rc as findFirstIndex, ri as catchCause, rl as getOrUndefined, rs as failCause$1, rt as SocketReadError, ru as pipeArguments, sa as provideService, sn as fromInput, t as RpcContracts, ta as onInterrupt, tc as filter$1, tl as getOrElse, to as replace, ts as die, tt as SocketErrorReason, tu as identity, u as LogToStderr, ua as retryOrElse, ui as catchTags, ul as none, un as merge, uo as Clock, v as Terminal, va as succeed$1, vi as fail$1, vt as Defect, w as String$7, wa as timeout, wc as some$1, wi as forEach, x as Crypto, xa as sync$1, xt as FalseLiterals, y as isQuitError, yc as map$5, yt as Error$1, za as withParentSpan, zi as logError, zn as filter, zs as get } from "./contracts-B4aEKL_A.mjs";
2
+ import { $ as Socket, $a as isNonEmpty, $l as isNotUndefined, Ac as some$1, Ai as gen, Ar as take, At as TaggedError, B as constPing, Bi as logInfo, Bs as Reference, Ca as sync$1, Ci as forEach, Cr as failCause, Ct as Literal, D as option, Di as forkScoped, Do as interruptors, Ds as sync, Ea as timeout, Ec as match, Ei as forkIn, Er as offerAll, F as layerJson, Fa as useSpan, Fi as isEffect, Fo as effect, Fr as getCurrent, Ga as min, Gi as mapError, Gn as fromQueue, Gt as tag, Hi as makeSpanScoped, Ho as provide$1, Hs as add, Ht as is, Ia as void_, Ir as interrupt$2, Is as taggedEnum, It as decodeSync, J as spanAttributes, Jo as addFinalizer, Jr as andThen, Js as make$3, K as getStreamSchemas, Ka as spaced, Ki as match$2, Ks as getOrUndefinedUnsafe, L as RequestId, La as whileLoop, Lt as decodeUnknownEffect, Mi as ignoreCause, Ml as withFiber$1, Mo as squash, N as withRunClient, Na as uninterruptibleMask, Ni as interrupt$1, Nl as assignProperty, Nt as Union, Oa as timeoutOrElse, Oc as reduce, Ot as String$6, P as RpcSerialization, Pi as interruptible, Pr as makeUnsafe, Qa as isEmpty, Ql as hasProperty, Ra as withFiber, Ri as logError, Rt as encodeEffect, Sa as suspend, Sc as join, Si as fnUntraced, Sl as some, So as findError, Sr as end, Tc as map$5, To as hasInterrupts, Tt as NonEmptyArray, U as exitSchema, Uc as fail$2, Ui as map$3, Us as empty$1, Ut as optional$2, Va as withParentSpan, Vl as format, Vs as Service, Wa as exponential, Ws as get, Wt as optionalKey, X as Collector, Y as spanName, Yo as addFinalizerExit, Yr as annotateLogs, Z as makeCollectorUnsafe, Zc as isSuccess, Zi as onError, Zs as Prototype, _ as QuitError, _a as scoped, _t as BooleanLiterals, aa as provide, ar as runHead, at as layerWebSocket, ba as succeed$1, bl as none, br as bounded, c as NotesError, ca as raceFirst, cc as findFirst, ci as catchTags, cs as failCause$1, dl as getOrElse, ds as isFailure, dt as HttpClientErrorSchema, du as identity, ea as onInterrupt, ei as callback, el as succeed$2, et as SocketError, fa as retryOrElse, fi as delay, fu as pipe, g as layer, gi as fail$1, gt as ArraySchema, h as errorReported, hl as isSome, hn as value, ho as Clock, ii as catchFilter, il as exists, io as replace, is as MinimumLogLevel, j as Stdio, ji as ignore, jt as TrueLiterals, kr as shutdownUnsafe, lc as findFirstIndex, ls as interrupt, lu as dual, m as errorExitCode, ma as runForkWith, mi as ensuring, ml as isNone, mn as make$2, mo as round, na as orDie, ni as catchCauseIf, oa as provideContext, oc as filter$1, on as empty, os as die, ot as layerWebSocketConstructorGlobal, p as runMain, pl as getOrUndefined, pr as unwrap, pu as pipeArguments, q as isStreamSchema, qi as matchCauseEffect, qo as Scope, qs as getUnsafe, qt as toCodecStringTree, rc as empty$2, rt as SocketReadError, sa as provideService, si as catchTag, sn as fromInput, ss as fail, su as constVoid, t as RpcContracts, ti as catchCause, tt as SocketErrorReason, u as LogToStderr, ua as result, uc as findLast, ui as context, ul as fromUndefinedOr, un as merge, v as Terminal, vl as map$4, vt as Defect, w as String$7, wa as tapCause, wi as forever, x as Crypto, xc as isReadonlyArrayNonEmpty, xt as FalseLiterals, y as isQuitError, ya as serviceOption, yi as flatMap$1, yl as match$1, ys as ConsoleRef, yt as Error$1, zn as filter, zs as toMillis } from "./contracts-CoHsVor4.mjs";
3
3
  //#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/workers/WorkerError.js
4
4
  /**
5
5
  * Worker error reason for failures while spawning or setting up a worker.
@@ -7255,7 +7255,7 @@ const runWith = (command, config) => {
7255
7255
  };
7256
7256
  //#endregion
7257
7257
  //#region package.json
7258
- var version = "0.1.1060";
7258
+ var version = "0.1.1062";
7259
7259
  //#endregion
7260
7260
  //#region src/main.cli.ts
7261
7261
  function section(title, text) {