plaud 0.1.0
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/CONTRIBUTING.md +28 -0
- package/LICENSE +22 -0
- package/README.md +101 -0
- package/SECURITY.md +23 -0
- package/dist/auth.js +155 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.js +583 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/download.js +88 -0
- package/dist/download.js.map +1 -0
- package/dist/export.js +164 -0
- package/dist/export.js.map +1 -0
- package/dist/output.js +52 -0
- package/dist/output.js.map +1 -0
- package/dist/plaud-api.js +145 -0
- package/dist/plaud-api.js.map +1 -0
- package/dist/recordings-format.js +46 -0
- package/dist/recordings-format.js.map +1 -0
- package/docs/CONTRACT_V1.md +218 -0
- package/package.json +53 -0
- package/skills/plaud/SKILL.md +41 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest. This is a small, agent-first CLI and we try to keep it simple and robust.
|
|
4
|
+
|
|
5
|
+
## Principles
|
|
6
|
+
|
|
7
|
+
- **No secret leakage**: never include tokens, HAR files, or signed URLs in issues/PRs.
|
|
8
|
+
- **Stable JSON contract**: keep `--json` output compatible with `docs/CONTRACT_V1.md`.
|
|
9
|
+
- **Agent-first UX**: stdout should be machine-friendly; progress/logs go to stderr.
|
|
10
|
+
- **Minimal deps**: prefer standard library; add dependencies only when they clearly improve correctness or maintainability.
|
|
11
|
+
|
|
12
|
+
## Development
|
|
13
|
+
|
|
14
|
+
Requirements:
|
|
15
|
+
- Node.js 22+
|
|
16
|
+
|
|
17
|
+
Commands:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
npm test
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Submitting changes
|
|
25
|
+
|
|
26
|
+
- Keep PRs small and focused.
|
|
27
|
+
- Add or update tests when behavior changes.
|
|
28
|
+
- Update `README.md` and/or `docs/CONTRACT_V1.md` if you change CLI surface or JSON output.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Daniel Wilson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# plaud (CLI)
|
|
2
|
+
|
|
3
|
+
Export all your Plaud recordings with speaker-labeled transcripts and optional AI summaries.
|
|
4
|
+
|
|
5
|
+
## Install (local)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd plaud/plaud-cli
|
|
9
|
+
npm install
|
|
10
|
+
npm link
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requirements:
|
|
14
|
+
- Node.js 22+ (tested on Node 24)
|
|
15
|
+
|
|
16
|
+
## Auth
|
|
17
|
+
|
|
18
|
+
Preferred (easy onboarding, stores token locally):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
plaud auth login
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Verify:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
plaud auth status
|
|
28
|
+
plaud doctor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Fallbacks:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
plaud auth set --stdin
|
|
35
|
+
plaud auth import-har /path/to/web.plaud.ai.har
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or via env var (no local storage):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export PLAUD_AUTH_TOKEN="eyJ..."
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Tip (Node 22+): you can also use Node’s `--env-file` if you want to load a local `.env` without adding any dependency to the CLI:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node --env-file .env "$(command -v plaud)" auth status --json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Export
|
|
51
|
+
|
|
52
|
+
Create a single ZIP (default):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
plaud recordings export --zip
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Export to a directory:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
plaud recordings export --out ./plaud-transcripts --formats txt,json,md
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Download a single recording
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
plaud recordings list --json --max 10
|
|
68
|
+
plaud recordings download <id> --out ./plaud-download --what transcript,summary,json
|
|
69
|
+
plaud recordings download <id> --out ./plaud-download --what audio --audio-format opus
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Notes:
|
|
73
|
+
- `plaud recordings export` prints a JSON summary to stdout; progress goes to stderr.
|
|
74
|
+
- Tokens are stored at `~/.config/plaud/config.json` with `0600` permissions.
|
|
75
|
+
|
|
76
|
+
## Agent-first JSON contract
|
|
77
|
+
|
|
78
|
+
See `docs/CONTRACT_V1.md`.
|
|
79
|
+
|
|
80
|
+
## Install (npm)
|
|
81
|
+
|
|
82
|
+
Global (recommended for frequent use):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm i -g plaud
|
|
86
|
+
plaud auth login
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
No install (convenient for agents/one-offs):
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx -y plaud auth status --json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Install (skill)
|
|
96
|
+
|
|
97
|
+
Once this lives in a GitHub repo, you’ll be able to add the agent skill with:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx -y skills add danielgwilson/plaud --skill plaud -g -y
|
|
101
|
+
```
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
This project is an **unofficial** CLI for Plaud. It works by capturing a Plaud bearer token from an authenticated browser session and calling private endpoints.
|
|
4
|
+
|
|
5
|
+
## Reporting a security issue
|
|
6
|
+
|
|
7
|
+
Please **do not** open a public issue containing secrets.
|
|
8
|
+
|
|
9
|
+
If you find a security issue (token leakage, unsafe file permissions, etc.), report it privately to the maintainer.
|
|
10
|
+
|
|
11
|
+
## Never share secrets
|
|
12
|
+
|
|
13
|
+
Do not paste any of the following into issues, PRs, logs, or screenshots:
|
|
14
|
+
|
|
15
|
+
- Plaud auth tokens (`Authorization: Bearer …`, typically JWTs starting with `eyJ`)
|
|
16
|
+
- HAR files (`*.har`, `*.har.gz`) — these often contain auth headers
|
|
17
|
+
- Signed file URLs returned by Plaud (may embed temporary credentials)
|
|
18
|
+
|
|
19
|
+
## Local storage
|
|
20
|
+
|
|
21
|
+
By default the CLI stores the token at `~/.config/plaud/config.json` with file mode `0600`.
|
|
22
|
+
|
|
23
|
+
If you don’t want local storage, use the `PLAUD_AUTH_TOKEN` environment variable instead.
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { writeConfig } from "./config.js";
|
|
3
|
+
import { getMe } from "./plaud-api.js";
|
|
4
|
+
function cleanToken(token) {
|
|
5
|
+
return String(token || "")
|
|
6
|
+
.trim()
|
|
7
|
+
.replace(/^bearer\s+/i, "");
|
|
8
|
+
}
|
|
9
|
+
function isProbablyJwt(token) {
|
|
10
|
+
const t = cleanToken(token);
|
|
11
|
+
return t.startsWith("eyJ") && t.length > 20;
|
|
12
|
+
}
|
|
13
|
+
function stripUrlQuery(url) {
|
|
14
|
+
try {
|
|
15
|
+
const u = new URL(String(url));
|
|
16
|
+
u.search = "";
|
|
17
|
+
return u.toString();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function sanitizeMe(me) {
|
|
24
|
+
if (!me || typeof me !== "object")
|
|
25
|
+
return null;
|
|
26
|
+
const dataUser = me.data_user && typeof me.data_user === "object" ? me.data_user : null;
|
|
27
|
+
const dataState = me.data_state && typeof me.data_state === "object" ? me.data_state : null;
|
|
28
|
+
const user = dataUser
|
|
29
|
+
? {
|
|
30
|
+
id: dataUser.id || null,
|
|
31
|
+
email: dataUser.email || null,
|
|
32
|
+
nickname: dataUser.nickname || null,
|
|
33
|
+
country: dataUser.country || null,
|
|
34
|
+
userAreaName: dataUser.user_area_name || null,
|
|
35
|
+
avatarUrl: dataUser.avatar ? stripUrlQuery(dataUser.avatar) : null,
|
|
36
|
+
}
|
|
37
|
+
: null;
|
|
38
|
+
const state = dataState
|
|
39
|
+
? {
|
|
40
|
+
isMembership: dataState.is_membership ?? null,
|
|
41
|
+
membershipType: dataState.membership_type ?? null,
|
|
42
|
+
membershipFlag: dataState.membership_flag ?? null,
|
|
43
|
+
}
|
|
44
|
+
: null;
|
|
45
|
+
return { status: me.status ?? null, user, state };
|
|
46
|
+
}
|
|
47
|
+
export async function validateToken(token) {
|
|
48
|
+
if (!token)
|
|
49
|
+
return { ok: false, reason: "missing" };
|
|
50
|
+
try {
|
|
51
|
+
const me = await getMe({ token });
|
|
52
|
+
return { ok: true, me: sanitizeMe(me) };
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return { ok: false, reason: error?.message || "invalid" };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function saveToken(token) {
|
|
59
|
+
const clean = cleanToken(token);
|
|
60
|
+
if (!isProbablyJwt(clean))
|
|
61
|
+
throw new Error("Invalid token format");
|
|
62
|
+
await writeConfig({ authToken: clean });
|
|
63
|
+
return clean;
|
|
64
|
+
}
|
|
65
|
+
export async function importTokenFromHar(harPath) {
|
|
66
|
+
const raw = await fs.readFile(harPath, "utf8");
|
|
67
|
+
const har = JSON.parse(raw);
|
|
68
|
+
const entries = har?.log?.entries;
|
|
69
|
+
if (!Array.isArray(entries)) {
|
|
70
|
+
throw new Error("Invalid HAR: missing log.entries");
|
|
71
|
+
}
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
const req = entry?.request;
|
|
74
|
+
const headers = req?.headers;
|
|
75
|
+
if (!Array.isArray(headers))
|
|
76
|
+
continue;
|
|
77
|
+
const auth = headers.find((h) => String(h?.name || "").toLowerCase() === "authorization")?.value;
|
|
78
|
+
if (!auth)
|
|
79
|
+
continue;
|
|
80
|
+
if (!String(auth).toLowerCase().startsWith("bearer "))
|
|
81
|
+
continue;
|
|
82
|
+
const token = cleanToken(auth);
|
|
83
|
+
if (!isProbablyJwt(token))
|
|
84
|
+
continue;
|
|
85
|
+
return token;
|
|
86
|
+
}
|
|
87
|
+
throw new Error("No bearer token found in HAR");
|
|
88
|
+
}
|
|
89
|
+
export async function captureTokenFromBrowser({ url = "https://app.plaud.ai", timeoutMs = 180_000, channel = "chrome", headless = false, onStatus, }) {
|
|
90
|
+
let playwright;
|
|
91
|
+
try {
|
|
92
|
+
playwright = await import("playwright-core");
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
throw new Error("Missing dependency: playwright-core");
|
|
96
|
+
}
|
|
97
|
+
const { chromium } = playwright;
|
|
98
|
+
const startedAt = Date.now();
|
|
99
|
+
const status = (msg) => {
|
|
100
|
+
if (typeof onStatus === "function")
|
|
101
|
+
onStatus({ msg, elapsedMs: Date.now() - startedAt });
|
|
102
|
+
};
|
|
103
|
+
status(`Launching browser (${channel}${headless ? ", headless" : ""})`);
|
|
104
|
+
let browser;
|
|
105
|
+
try {
|
|
106
|
+
browser = await chromium.launch({ headless, channel });
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
throw new Error(`Failed to launch browser channel "${channel}". Install Chrome/Edge, or use \`plaud auth import-har\`.`);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const context = await browser.newContext();
|
|
113
|
+
const page = await context.newPage();
|
|
114
|
+
let capturedToken = "";
|
|
115
|
+
const started = Date.now();
|
|
116
|
+
const maybeCapture = (request) => {
|
|
117
|
+
try {
|
|
118
|
+
const reqUrl = request.url();
|
|
119
|
+
if (!reqUrl.includes("api.plaud.ai"))
|
|
120
|
+
return;
|
|
121
|
+
const headers = request.headers?.() || {};
|
|
122
|
+
const auth = headers.authorization || headers.Authorization;
|
|
123
|
+
if (!auth)
|
|
124
|
+
return;
|
|
125
|
+
if (!String(auth).toLowerCase().startsWith("bearer "))
|
|
126
|
+
return;
|
|
127
|
+
const token = cleanToken(auth);
|
|
128
|
+
if (isProbablyJwt(token)) {
|
|
129
|
+
capturedToken = token;
|
|
130
|
+
status("Captured Plaud bearer token");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// ignore
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
page.on("request", maybeCapture);
|
|
138
|
+
context.on("request", maybeCapture);
|
|
139
|
+
status("Opening Plaud login page (complete sign-in in the browser)");
|
|
140
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
141
|
+
status("Waiting for Plaud API request with auth header");
|
|
142
|
+
while (!capturedToken && Date.now() - started < timeoutMs) {
|
|
143
|
+
await page.waitForTimeout(250);
|
|
144
|
+
}
|
|
145
|
+
if (!capturedToken) {
|
|
146
|
+
throw new Error("Timed out waiting for Plaud API auth. Please complete login in the opened browser window, or use `plaud auth import-har`.");
|
|
147
|
+
}
|
|
148
|
+
return capturedToken;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
status("Closing browser");
|
|
152
|
+
await browser.close();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|