@deslop/stash 0.1.0 → 0.1.1018
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 +39 -42
- package/dist/cli.js +823 -231
- package/dist/contracts-Cy_AB8uR.mjs +45867 -0
- package/dist/{execAsync-CS6-5S6V.mjs → execAsync-BuWzI3oS.mjs} +2 -2
- package/dist/{getMachineId-bsd-BfsG3k01.mjs → getMachineId-bsd-BpFhA9PK.mjs} +3 -4
- package/dist/{getMachineId-darwin-Dt44hGe-.mjs → getMachineId-darwin-R5WFW9-e.mjs} +3 -4
- package/dist/{getMachineId-linux-DWTz-mRA.mjs → getMachineId-linux-OOR5wRZh.mjs} +2 -3
- package/dist/{getMachineId-unsupported-D5QQBxpZ.mjs → getMachineId-unsupported-CGXxqFxB.mjs} +2 -3
- package/dist/{getMachineId-win-DRPdxiMP.mjs → getMachineId-win-RTYbWBWk.mjs} +3 -4
- package/dist/server.js +41758 -14319
- package/package.json +7 -35
- package/dist/rolldown-runtime-B2ow0EdR.mjs +0 -45
- package/dist/service-D6Z3eq9Z.mjs +0 -68381
- package/src/main.client.tsx +0 -11
package/README.md
CHANGED
|
@@ -1,45 +1,43 @@
|
|
|
1
1
|
# Stash
|
|
2
2
|
|
|
3
|
-
A personal
|
|
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
4
|
|
|
5
5
|
## CLI
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Needs Node 26+ and the tailnet.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
vpx @deslop/stash@latest
|
|
10
|
+
vpx @deslop/stash@latest save '<link or text>' [--server <url>]
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
| ---------------- | -------------------------------------------------------------------------------------------------------- |
|
|
15
|
-
| `info.md` | Title, author, date, duration, description and chapters; the text of an X post and of the post it quotes |
|
|
16
|
-
| `transcript.txt` | One `[mm:ss] text` line per caption or speech segment |
|
|
17
|
-
|
|
18
|
-
The output directory defaults to `/tmp/media`. The spoken language comes from `--language`, the video's original caption track or its declared language, defaulting to English, and published captions in that language win. Without them, the audio is transcribed locally with Whisper `small.en`, in about a quarter of the audio's duration (a 38-minute talk took 9 minutes on an 8-core server). Speech that is not English uses the multilingual Whisper model.
|
|
19
|
-
|
|
20
|
-
The first run downloads the standalone `yt-dlp`, and the first transcription the Whisper model, into `$XDG_CACHE_HOME/deslop/media` (`~/.cache` by default); later runs update `yt-dlp` in place. When YouTube refuses the connection, as it does for most datacenter addresses, `info.md` holds only the oEmbed title and channel. A URL nothing can be read from fails.
|
|
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`.
|
|
21
14
|
|
|
22
15
|
## Server
|
|
23
16
|
|
|
24
|
-
- **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
|
|
25
|
-
- **Environment.**
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
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. `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.
|
|
20
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
29
24
|
|
|
30
25
|
## iOS client
|
|
31
26
|
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
|
|
27
|
+
- **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
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
33
|
+
|
|
34
|
+
## Releases
|
|
35
|
+
|
|
36
|
+
On main, `deploy.yaml` checks the native fingerprint of a change under `apps/stash` or `packages`. A known fingerprint ships the JavaScript as an EAS Update; a new one builds on GitHub's `xcode-27` runner with `eas build --local`, submits to TestFlight, then publishes the update. Any pushed tag builds its commit for TestFlight. Each release is version `0.1.<run>` with build number `<run>`.
|
|
39
37
|
|
|
40
38
|
## Development build
|
|
41
39
|
|
|
42
|
-
`vp -C apps/stash run
|
|
40
|
+
`vp -C apps/stash run dev` serves Metro on localhost and writes the tailnet URL into its manifest; `sudo tailscale serve --bg --https=8081 http://localhost:8081` lets the iPhone's stash dev reach it. Use `localhost`, not `127.0.0.1`: Metro listens on `::1`.
|
|
43
41
|
|
|
44
42
|
## Checks without a Mac
|
|
45
43
|
|
|
@@ -54,23 +52,22 @@ The first EAS build is the first Swift compile.
|
|
|
54
52
|
<details>
|
|
55
53
|
<summary>For agents</summary>
|
|
56
54
|
|
|
57
|
-
| Owner
|
|
58
|
-
|
|
|
59
|
-
| Package
|
|
60
|
-
|
|
|
61
|
-
| Transcription
|
|
62
|
-
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
| `expo-share-
|
|
68
|
-
| React
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
| A separate `tools/media` package | Stash reads the same links; one package keeps one extractor, and notes get the transcripts |
|
|
55
|
+
| Owner | Decision |
|
|
56
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
57
|
+
| Package | Published as `@deslop/stash`; app dependencies are `devDependencies`. ONNX Runtime and sharp stay external through `deps.neverBundle`, because only the server loads them |
|
|
58
|
+
| Media | `yt-dlp` stays an external binary because no maintained JavaScript extractor covers its sites. The iOS client never imports `services/media` |
|
|
59
|
+
| Transcription | Update Transformers.js `4.3.0`, `onnxruntime-common`, `onnxruntime-node` and sharp together |
|
|
60
|
+
| Fingerprint | `fingerprint.config.js` adds `targets/share`, whose Swift the Expo fingerprint does not read |
|
|
61
|
+
| 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 |
|
|
62
|
+
|
|
63
|
+
| Rejected | Reason |
|
|
64
|
+
| --------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `expo-sharing` and `expo-share-intent` | Both open the main app to save; sharing from TikTok must not leave TikTok |
|
|
66
|
+
| React Native inside the share extension | It costs most of the extension's memory |
|
|
67
|
+
| A patch of `@expo/ui` | A patch breaks with each upgrade; the local module uses the public extension API |
|
|
68
|
+
| EAS cloud builds from the workflow | The free plan allows 15 iOS builds a month; macOS runners are free for this public repository |
|
|
69
|
+
| Binary RPC serialization | It failed to reopen a cancelled watch |
|
|
70
|
+
| An app outbox | The extension uploads in a background session, and the app saves through the RPC directly |
|
|
71
|
+
| `yt-dlp` and Whisper inside the CLI | API keys and models live on the server, and every analysis stays a note |
|
|
75
72
|
|
|
76
73
|
</details>
|