plaud-notes-to-notion 1.0.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/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/bin/plaud-notes-to-notion.js +16 -0
- package/dist/card.d.ts +30 -0
- package/dist/card.js +287 -0
- package/dist/card.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +266 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +41 -0
- package/dist/config.js +85 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.js +53 -0
- package/dist/constants.js.map +1 -0
- package/dist/daemon.d.ts +13 -0
- package/dist/daemon.js +182 -0
- package/dist/daemon.js.map +1 -0
- package/dist/format.d.ts +36 -0
- package/dist/format.js +108 -0
- package/dist/format.js.map +1 -0
- package/dist/ingest.d.ts +49 -0
- package/dist/ingest.js +205 -0
- package/dist/ingest.js.map +1 -0
- package/dist/llm.d.ts +65 -0
- package/dist/llm.js +177 -0
- package/dist/llm.js.map +1 -0
- package/dist/lock.d.ts +26 -0
- package/dist/lock.js +134 -0
- package/dist/lock.js.map +1 -0
- package/dist/log.d.ts +14 -0
- package/dist/log.js +41 -0
- package/dist/log.js.map +1 -0
- package/dist/notion.d.ts +86 -0
- package/dist/notion.js +254 -0
- package/dist/notion.js.map +1 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.js +51 -0
- package/dist/paths.js.map +1 -0
- package/dist/plaud/callback.d.ts +19 -0
- package/dist/plaud/callback.js +162 -0
- package/dist/plaud/callback.js.map +1 -0
- package/dist/plaud/client.d.ts +55 -0
- package/dist/plaud/client.js +246 -0
- package/dist/plaud/client.js.map +1 -0
- package/dist/plaud/constants.d.ts +18 -0
- package/dist/plaud/constants.js +19 -0
- package/dist/plaud/constants.js.map +1 -0
- package/dist/plaud/errors.d.ts +10 -0
- package/dist/plaud/errors.js +32 -0
- package/dist/plaud/errors.js.map +1 -0
- package/dist/plaud/login.d.ts +17 -0
- package/dist/plaud/login.js +89 -0
- package/dist/plaud/login.js.map +1 -0
- package/dist/plaud/oauth.d.ts +21 -0
- package/dist/plaud/oauth.js +197 -0
- package/dist/plaud/oauth.js.map +1 -0
- package/dist/plaud/pkce.d.ts +3 -0
- package/dist/plaud/pkce.js +11 -0
- package/dist/plaud/pkce.js.map +1 -0
- package/dist/plaud/session.d.ts +23 -0
- package/dist/plaud/session.js +77 -0
- package/dist/plaud/session.js.map +1 -0
- package/dist/plaud/types.d.ts +21 -0
- package/dist/plaud/types.js +2 -0
- package/dist/plaud/types.js.map +1 -0
- package/dist/redact.d.ts +3 -0
- package/dist/redact.js +37 -0
- package/dist/redact.js.map +1 -0
- package/dist/runtime.d.ts +44 -0
- package/dist/runtime.js +94 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scrub.d.ts +17 -0
- package/dist/scrub.js +124 -0
- package/dist/scrub.js.map +1 -0
- package/dist/secrets.d.ts +59 -0
- package/dist/secrets.js +220 -0
- package/dist/secrets.js.map +1 -0
- package/dist/ssn.d.ts +33 -0
- package/dist/ssn.js +170 -0
- package/dist/ssn.js.map +1 -0
- package/dist/state.d.ts +46 -0
- package/dist/state.js +23 -0
- package/dist/state.js.map +1 -0
- package/dist/sync.d.ts +60 -0
- package/dist/sync.js +190 -0
- package/dist/sync.js.map +1 -0
- package/examples/com.plaud-notes-to-notion.plist +34 -0
- package/examples/install-launchagent.sh +16 -0
- package/package.json +37 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { getProfile, loadConfig } from "./config.js";
|
|
3
|
+
import { ANTHROPIC_ACCOUNT, anthropicAccount, isAnthropicModel, notionAccount, OPENAI_ACCOUNT, openaiAccount, PACKAGE_NAME, PACKAGE_VERSION, plaudAccount } from "./constants.js";
|
|
4
|
+
import { runDaemon } from "./daemon.js";
|
|
5
|
+
import { runIngest } from "./ingest.js";
|
|
6
|
+
import { createLogger } from "./log.js";
|
|
7
|
+
import { getConfigPath, getLogFilePath } from "./paths.js";
|
|
8
|
+
import { runPlaudLogin } from "./plaud/login.js";
|
|
9
|
+
import { createAuthSession } from "./plaud/session.js";
|
|
10
|
+
import { safeErrorMessage } from "./redact.js";
|
|
11
|
+
import { buildProfileRuntime, llmKey, readStatus } from "./runtime.js";
|
|
12
|
+
import { createSecretStore } from "./secrets.js";
|
|
13
|
+
import { loadState, saveState } from "./state.js";
|
|
14
|
+
import { scrubSensitive } from "./scrub.js";
|
|
15
|
+
import { runDeletionSync, runSync } from "./sync.js";
|
|
16
|
+
const USAGE = `${PACKAGE_NAME} ${PACKAGE_VERSION}
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
${PACKAGE_NAME} run Daemon (LaunchAgent): ingest + sync for enabled profiles
|
|
20
|
+
${PACKAGE_NAME} once --profile <p> [--dry-run] [--deep] One ingest cycle
|
|
21
|
+
${PACKAGE_NAME} sync --profile <p> [--dry-run] [--full] One Summary→Transcript sync cycle
|
|
22
|
+
${PACKAGE_NAME} login --profile <p> [--no-browser] Plaud sign-in for that profile's Plaud account
|
|
23
|
+
${PACKAGE_NAME} logout --profile <p>
|
|
24
|
+
${PACKAGE_NAME} set-secret notion --profile <p> [--from-keychain <service>/<account>]
|
|
25
|
+
${PACKAGE_NAME} set-secret anthropic [--profile <p>] [--from-keychain <service>/<account>]
|
|
26
|
+
${PACKAGE_NAME} set-secret openai [--profile <p>] [--from-keychain <service>/<account>]
|
|
27
|
+
${PACKAGE_NAME} doctor --profile <p> Check sign-ins, Notion schema, LLM key for llmModel
|
|
28
|
+
${PACKAGE_NAME} status Last poll/sync/write per profile
|
|
29
|
+
${PACKAGE_NAME} scrub --profile <p> [--apply] Find (dry run) or remove SSNs and card details in existing rows
|
|
30
|
+
|
|
31
|
+
Config: ${getConfigPath()}
|
|
32
|
+
Log: ${getLogFilePath()}`;
|
|
33
|
+
function flag(argv, name) {
|
|
34
|
+
return argv.includes(name);
|
|
35
|
+
}
|
|
36
|
+
function option(argv, name) {
|
|
37
|
+
const i = argv.indexOf(name);
|
|
38
|
+
return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined;
|
|
39
|
+
}
|
|
40
|
+
function requireProfile(argv) {
|
|
41
|
+
const p = option(argv, "--profile");
|
|
42
|
+
if (!p) {
|
|
43
|
+
throw new Error("--profile <name> is required");
|
|
44
|
+
}
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
async function readSecretInput(argv) {
|
|
48
|
+
const from = option(argv, "--from-keychain");
|
|
49
|
+
if (from) {
|
|
50
|
+
const [service, ...rest] = from.split("/");
|
|
51
|
+
const account = rest.join("/");
|
|
52
|
+
if (!service || !account) {
|
|
53
|
+
throw new Error("--from-keychain expects <service>/<account>");
|
|
54
|
+
}
|
|
55
|
+
const value = execFileSync("/usr/bin/security", ["find-generic-password", "-s", service, "-a", account, "-w"], {
|
|
56
|
+
encoding: "utf8"
|
|
57
|
+
}).replace(/\n$/, "");
|
|
58
|
+
if (!value) {
|
|
59
|
+
throw new Error(`Keychain item ${from} is empty`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
if (process.stdin.isTTY) {
|
|
64
|
+
process.stderr.write("Paste the secret and press Enter (input is hidden): ");
|
|
65
|
+
execFileSync("/bin/stty", ["-echo"], { stdio: "inherit" });
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const value = await new Promise((resolve) => {
|
|
69
|
+
let buf = "";
|
|
70
|
+
process.stdin.setEncoding("utf8");
|
|
71
|
+
process.stdin.on("data", (c) => {
|
|
72
|
+
buf += c;
|
|
73
|
+
if (process.stdin.isTTY && buf.includes("\n")) {
|
|
74
|
+
process.stdin.pause();
|
|
75
|
+
resolve(buf);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
process.stdin.on("end", () => resolve(buf));
|
|
79
|
+
});
|
|
80
|
+
return value.trim();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (process.stdin.isTTY) {
|
|
84
|
+
execFileSync("/bin/stty", ["echo"], { stdio: "inherit" });
|
|
85
|
+
process.stderr.write("\n");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function doctor(profileName, store) {
|
|
90
|
+
const config = loadConfig();
|
|
91
|
+
const profile = getProfile(config, profileName);
|
|
92
|
+
const creds = profile.credentials;
|
|
93
|
+
let ok = true;
|
|
94
|
+
const line = (good, msg) => {
|
|
95
|
+
ok &&= good;
|
|
96
|
+
console.log(`${good ? "OK " : "FAIL"} ${msg}`);
|
|
97
|
+
};
|
|
98
|
+
console.log(`Profile ${profileName}: ${profile.enabled ? "enabled" : "DISABLED"}, ingest ${profile.ingest}, sync ${profile.syncTranscripts}, owner ${profile.owner}, credentials ${creds}`);
|
|
99
|
+
try {
|
|
100
|
+
const rt = await buildProfileRuntime({ name: profileName, profile, config, store, needPlaud: false, needLabeler: false });
|
|
101
|
+
const schema = await rt.notion.schema();
|
|
102
|
+
line(true, `Notion data source ${profile.notionDataSourceId}: Type ${schema.typeKind}, Participants ${schema.participantsKind} (${schema.participantOptions.length} options)`);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
line(false, `Notion: ${safeErrorMessage(err)}`);
|
|
106
|
+
}
|
|
107
|
+
if (profile.ingest) {
|
|
108
|
+
try {
|
|
109
|
+
const session = await createAuthSession({ store, account: plaudAccount(creds) });
|
|
110
|
+
if (!session.peek()) {
|
|
111
|
+
throw new Error(`not signed in — run: ${PACKAGE_NAME} login --profile ${creds}`);
|
|
112
|
+
}
|
|
113
|
+
const rt = await buildProfileRuntime({ name: profileName, profile, config, store, needPlaud: true, needLabeler: false });
|
|
114
|
+
const files = await rt.plaud.listFiles(1, 10);
|
|
115
|
+
line(true, `Plaud sign-in works (${files.length} recent files visible)`);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
line(false, `Plaud: ${safeErrorMessage(err)}`);
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
await llmKey(store, creds, config.llmModel, process.env);
|
|
122
|
+
line(true, isAnthropicModel(config.llmModel)
|
|
123
|
+
? `Anthropic key present (model ${config.llmModel})`
|
|
124
|
+
: `OpenAI key present (model ${config.llmModel}, effort ${config.llmEffort})`);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
line(false, safeErrorMessage(err));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return ok ? 0 : 1;
|
|
131
|
+
}
|
|
132
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
133
|
+
const cmd = argv[0];
|
|
134
|
+
const store = createSecretStore();
|
|
135
|
+
const verbose = flag(argv, "--verbose") || cmd !== "run";
|
|
136
|
+
const log = createLogger({ verbose, stdout: (s) => process.stdout.write(`${s}\n`) });
|
|
137
|
+
switch (cmd) {
|
|
138
|
+
case "run":
|
|
139
|
+
return runDaemon({ store, log });
|
|
140
|
+
case "once": {
|
|
141
|
+
const name = requireProfile(argv);
|
|
142
|
+
const config = loadConfig();
|
|
143
|
+
const profile = getProfile(config, name);
|
|
144
|
+
const dryRun = flag(argv, "--dry-run");
|
|
145
|
+
const rt = await buildProfileRuntime({ name, profile, config, store, needPlaud: true, needLabeler: true });
|
|
146
|
+
const state = loadState(name);
|
|
147
|
+
const r = await runIngest({
|
|
148
|
+
profile: name,
|
|
149
|
+
owner: profile.owner,
|
|
150
|
+
startAfter: new Date(option(argv, "--since") || profile.startAfter),
|
|
151
|
+
plaud: rt.plaud,
|
|
152
|
+
notion: rt.notion,
|
|
153
|
+
labeler: rt.labeler,
|
|
154
|
+
state,
|
|
155
|
+
save: () => (dryRun ? undefined : saveState(name, state)),
|
|
156
|
+
log: (m) => log.info(m),
|
|
157
|
+
dryRun
|
|
158
|
+
}, { deep: flag(argv, "--deep") });
|
|
159
|
+
console.log(JSON.stringify(r, null, 2));
|
|
160
|
+
return r.errors.length ? 1 : 0;
|
|
161
|
+
}
|
|
162
|
+
case "sync": {
|
|
163
|
+
const name = requireProfile(argv);
|
|
164
|
+
const config = loadConfig();
|
|
165
|
+
const profile = getProfile(config, name);
|
|
166
|
+
const rt = await buildProfileRuntime({ name, profile, config, store, needPlaud: false, needLabeler: false });
|
|
167
|
+
const state = loadState(name);
|
|
168
|
+
if (flag(argv, "--full")) {
|
|
169
|
+
delete state.lastFullSyncAt;
|
|
170
|
+
}
|
|
171
|
+
const dryRun = flag(argv, "--dry-run");
|
|
172
|
+
const r = await runSync({ profile: name, notion: rt.notion, state, save: () => saveState(name, state), log: (m) => log.info(m), dryRun });
|
|
173
|
+
const d = await runDeletionSync({ profile: name, notion: rt.notion, state, save: () => saveState(name, state), log: (m) => log.info(m), dryRun });
|
|
174
|
+
console.log(JSON.stringify({ ...r, deletions: d }, null, 2));
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
case "login": {
|
|
178
|
+
const name = requireProfile(argv);
|
|
179
|
+
return runPlaudLogin({ profile: name, store, account: plaudAccount(name), noBrowser: flag(argv, "--no-browser") });
|
|
180
|
+
}
|
|
181
|
+
case "logout": {
|
|
182
|
+
const name = requireProfile(argv);
|
|
183
|
+
await store.delete(plaudAccount(name));
|
|
184
|
+
console.log(`Removed Plaud sign-in for profile ${name}.`);
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
case "set-secret": {
|
|
188
|
+
const kind = argv[1];
|
|
189
|
+
const profile = option(argv, "--profile");
|
|
190
|
+
if (kind !== "notion" && kind !== "openai" && kind !== "anthropic") {
|
|
191
|
+
throw new Error("set-secret expects notion, anthropic or openai");
|
|
192
|
+
}
|
|
193
|
+
if (kind === "notion" && !profile) {
|
|
194
|
+
throw new Error("set-secret notion needs --profile <name>");
|
|
195
|
+
}
|
|
196
|
+
const value = await readSecretInput(argv);
|
|
197
|
+
if (!value) {
|
|
198
|
+
throw new Error("Empty secret; nothing saved.");
|
|
199
|
+
}
|
|
200
|
+
const account = kind === "notion"
|
|
201
|
+
? notionAccount(profile)
|
|
202
|
+
: kind === "anthropic"
|
|
203
|
+
? profile
|
|
204
|
+
? anthropicAccount(profile)
|
|
205
|
+
: ANTHROPIC_ACCOUNT
|
|
206
|
+
: profile
|
|
207
|
+
? openaiAccount(profile)
|
|
208
|
+
: OPENAI_ACCOUNT;
|
|
209
|
+
await store.set(account, value);
|
|
210
|
+
console.log(`Saved ${kind} secret to ${store.describe()} account ${account}.`);
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
case "scrub":
|
|
214
|
+
case "scrub-ssn": {
|
|
215
|
+
const name = requireProfile(argv);
|
|
216
|
+
const profile = getProfile(loadConfig(), name);
|
|
217
|
+
const token = await store.get(notionAccount(profile.credentials));
|
|
218
|
+
if (!token) {
|
|
219
|
+
throw new Error(`No Notion token for ${profile.credentials}`);
|
|
220
|
+
}
|
|
221
|
+
const r = await scrubSensitive({ token, dataSourceId: profile.notionDataSourceId, apply: flag(argv, "--apply"), log: (m) => log.info(m) });
|
|
222
|
+
console.log(`Scanned ${r.rowsScanned} rows; ${r.rowsAffected.length} affected; ${r.blocksUpdated} block(s) ${flag(argv, "--apply") ? "updated" : "would be updated"}.`);
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
case "doctor":
|
|
226
|
+
return doctor(requireProfile(argv), store);
|
|
227
|
+
case "status": {
|
|
228
|
+
const status = readStatus();
|
|
229
|
+
let config;
|
|
230
|
+
try {
|
|
231
|
+
config = loadConfig();
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
config = null;
|
|
235
|
+
}
|
|
236
|
+
for (const [name, p] of Object.entries(config?.profiles || {})) {
|
|
237
|
+
const s = status[name] || {};
|
|
238
|
+
const state = loadState(name);
|
|
239
|
+
const pending = Object.values(state.files).filter((f) => f.status === "pending");
|
|
240
|
+
console.log(`${name}: ${p.enabled ? "ON" : "off"} (ingest ${p.ingest}, sync ${p.syncTranscripts})`);
|
|
241
|
+
console.log(` last poll ok: ${s.lastPollOkAt || "never"}`);
|
|
242
|
+
console.log(` last sync ok: ${s.lastSyncOkAt || "never"}`);
|
|
243
|
+
console.log(` last written: ${s.lastWritten ? `${s.lastWritten.title} (${s.lastWritten.at})` : "none"}`);
|
|
244
|
+
console.log(` pending: ${pending.length}${pending.length ? ` — ${pending.map((f) => f.name || "?").join("; ")}` : ""}`);
|
|
245
|
+
if (s.lastError) {
|
|
246
|
+
console.log(` last error: ${s.lastError} (${s.lastErrorAt})`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return 0;
|
|
250
|
+
}
|
|
251
|
+
case undefined:
|
|
252
|
+
case "help":
|
|
253
|
+
case "--help":
|
|
254
|
+
case "-h":
|
|
255
|
+
console.log(USAGE);
|
|
256
|
+
return 0;
|
|
257
|
+
case "--version":
|
|
258
|
+
case "version":
|
|
259
|
+
console.log(PACKAGE_VERSION);
|
|
260
|
+
return 0;
|
|
261
|
+
default:
|
|
262
|
+
console.error(USAGE);
|
|
263
|
+
return 2;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One Plaud account → one Plaud Notes database. Peter and Tim are identical
|
|
3
|
+
* except for these fields; everything else (pipeline, prompt, schedule) is shared.
|
|
4
|
+
*/
|
|
5
|
+
export interface ProfileConfig {
|
|
6
|
+
/** Off = never polled or synced. */
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
/** Recorder owner. Never listed in Participants; named in the labeling prompt. */
|
|
9
|
+
owner: string;
|
|
10
|
+
/** Plaud Notes data source id (collection://…) in that person's Notion. */
|
|
11
|
+
notionDataSourceId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Only recordings uploaded to Plaud at/after this instant are ingested.
|
|
14
|
+
* Set at cutover so recordings the Zap already wrote are not re-processed.
|
|
15
|
+
*/
|
|
16
|
+
startAfter: string;
|
|
17
|
+
/** Poll Plaud and write new Summary/Transcript rows. */
|
|
18
|
+
ingest: boolean;
|
|
19
|
+
/** Run the 5-minute Summary→Transcript alignment for this profile. */
|
|
20
|
+
syncTranscripts: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Keychain profile whose Plaud/Notion secrets this profile uses (default: itself).
|
|
23
|
+
* Lets a test profile share Peter's sign-in while writing to a test database.
|
|
24
|
+
*/
|
|
25
|
+
credentials: string;
|
|
26
|
+
}
|
|
27
|
+
export interface AppConfig {
|
|
28
|
+
pollSeconds: number;
|
|
29
|
+
syncSeconds: number;
|
|
30
|
+
llmModel: string;
|
|
31
|
+
llmEffort: string;
|
|
32
|
+
openaiBaseUrl: string;
|
|
33
|
+
anthropicBaseUrl: string;
|
|
34
|
+
profiles: Record<string, ProfileConfig>;
|
|
35
|
+
}
|
|
36
|
+
export declare const DEFAULT_CONFIG: AppConfig;
|
|
37
|
+
export declare function normalizeId(raw: string): string;
|
|
38
|
+
export declare function parseConfig(raw: unknown): AppConfig;
|
|
39
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): AppConfig;
|
|
40
|
+
export declare function saveConfig(config: AppConfig, env?: NodeJS.ProcessEnv): void;
|
|
41
|
+
export declare function getProfile(config: AppConfig, name: string): ProfileConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { DEFAULT_ANTHROPIC_BASE_URL, DEFAULT_LLM_EFFORT, DEFAULT_LLM_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_POLL_SECONDS, DEFAULT_SYNC_SECONDS } from "./constants.js";
|
|
2
|
+
import { getConfigPath, readJson, writeJsonAtomic } from "./paths.js";
|
|
3
|
+
export const DEFAULT_CONFIG = {
|
|
4
|
+
pollSeconds: DEFAULT_POLL_SECONDS,
|
|
5
|
+
syncSeconds: DEFAULT_SYNC_SECONDS,
|
|
6
|
+
llmModel: DEFAULT_LLM_MODEL,
|
|
7
|
+
llmEffort: DEFAULT_LLM_EFFORT,
|
|
8
|
+
openaiBaseUrl: DEFAULT_OPENAI_BASE_URL,
|
|
9
|
+
anthropicBaseUrl: DEFAULT_ANTHROPIC_BASE_URL,
|
|
10
|
+
profiles: {}
|
|
11
|
+
};
|
|
12
|
+
function clamp(n, lo, hi, fallback) {
|
|
13
|
+
const v = typeof n === "number" && Number.isFinite(n) ? n : fallback;
|
|
14
|
+
return Math.min(hi, Math.max(lo, v));
|
|
15
|
+
}
|
|
16
|
+
function isIsoInstant(value) {
|
|
17
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
18
|
+
}
|
|
19
|
+
export function normalizeId(raw) {
|
|
20
|
+
const hex = raw.replace(/^collection:\/\//, "").replace(/-/g, "").toLowerCase();
|
|
21
|
+
if (!/^[0-9a-f]{32}$/.test(hex)) {
|
|
22
|
+
throw new Error(`Not a Notion id: ${raw}`);
|
|
23
|
+
}
|
|
24
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
25
|
+
}
|
|
26
|
+
export function parseConfig(raw) {
|
|
27
|
+
const rec = (raw && typeof raw === "object" ? raw : {});
|
|
28
|
+
const profilesRaw = (rec.profiles && typeof rec.profiles === "object" ? rec.profiles : {});
|
|
29
|
+
const profiles = {};
|
|
30
|
+
for (const [name, value] of Object.entries(profilesRaw)) {
|
|
31
|
+
if (!/^[a-z0-9_-]+$/.test(name)) {
|
|
32
|
+
throw new Error(`Profile name must be lowercase letters, digits, - or _: ${name}`);
|
|
33
|
+
}
|
|
34
|
+
const p = (value && typeof value === "object" ? value : {});
|
|
35
|
+
if (typeof p.owner !== "string" || !p.owner.trim()) {
|
|
36
|
+
throw new Error(`Profile ${name}: owner is required`);
|
|
37
|
+
}
|
|
38
|
+
if (typeof p.notionDataSourceId !== "string") {
|
|
39
|
+
throw new Error(`Profile ${name}: notionDataSourceId is required`);
|
|
40
|
+
}
|
|
41
|
+
if (!isIsoInstant(p.startAfter)) {
|
|
42
|
+
throw new Error(`Profile ${name}: startAfter must be an ISO date-time`);
|
|
43
|
+
}
|
|
44
|
+
profiles[name] = {
|
|
45
|
+
enabled: p.enabled === true,
|
|
46
|
+
owner: p.owner.trim(),
|
|
47
|
+
notionDataSourceId: normalizeId(p.notionDataSourceId),
|
|
48
|
+
startAfter: new Date(p.startAfter).toISOString(),
|
|
49
|
+
ingest: p.ingest !== false,
|
|
50
|
+
syncTranscripts: p.syncTranscripts !== false,
|
|
51
|
+
credentials: typeof p.credentials === "string" && /^[a-z0-9_-]+$/.test(p.credentials) ? p.credentials : name
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
pollSeconds: clamp(rec.pollSeconds, 10, 3600, DEFAULT_CONFIG.pollSeconds),
|
|
56
|
+
syncSeconds: clamp(rec.syncSeconds, 60, 86_400, DEFAULT_CONFIG.syncSeconds),
|
|
57
|
+
llmModel: typeof rec.llmModel === "string" && rec.llmModel.trim() ? rec.llmModel.trim() : DEFAULT_CONFIG.llmModel,
|
|
58
|
+
llmEffort: typeof rec.llmEffort === "string" && rec.llmEffort.trim() ? rec.llmEffort.trim() : DEFAULT_CONFIG.llmEffort,
|
|
59
|
+
openaiBaseUrl: typeof rec.openaiBaseUrl === "string" && rec.openaiBaseUrl.trim()
|
|
60
|
+
? rec.openaiBaseUrl.trim()
|
|
61
|
+
: DEFAULT_CONFIG.openaiBaseUrl,
|
|
62
|
+
anthropicBaseUrl: typeof rec.anthropicBaseUrl === "string" && rec.anthropicBaseUrl.trim()
|
|
63
|
+
? rec.anthropicBaseUrl.trim()
|
|
64
|
+
: DEFAULT_CONFIG.anthropicBaseUrl,
|
|
65
|
+
profiles
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function loadConfig(env = process.env) {
|
|
69
|
+
const raw = readJson(getConfigPath(env));
|
|
70
|
+
if (raw === null) {
|
|
71
|
+
throw new Error(`No config at ${getConfigPath(env)}. Run: plaud-notes-to-notion init`);
|
|
72
|
+
}
|
|
73
|
+
return parseConfig(raw);
|
|
74
|
+
}
|
|
75
|
+
export function saveConfig(config, env = process.env) {
|
|
76
|
+
writeJsonAtomic(getConfigPath(env), config);
|
|
77
|
+
}
|
|
78
|
+
export function getProfile(config, name) {
|
|
79
|
+
const p = config.profiles[name];
|
|
80
|
+
if (!p) {
|
|
81
|
+
throw new Error(`Unknown profile "${name}". Known: ${Object.keys(config.profiles).join(", ") || "(none)"}`);
|
|
82
|
+
}
|
|
83
|
+
return p;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Product constants. No secrets. */
|
|
2
|
+
export declare const PACKAGE_NAME = "plaud-notes-to-notion";
|
|
3
|
+
export declare const PACKAGE_VERSION = "1.0.0";
|
|
4
|
+
/** macOS Keychain service. One service, named accounts per profile. */
|
|
5
|
+
export declare const KEYCHAIN_SERVICE = "plaud-notes-to-notion";
|
|
6
|
+
/** Plaud OAuth token-set JSON for a profile: `plaud:<profile>`. */
|
|
7
|
+
export declare const plaudAccount: (profile: string) => string;
|
|
8
|
+
/** Notion integration token for a profile: `notion:<profile>`. */
|
|
9
|
+
export declare const notionAccount: (profile: string) => string;
|
|
10
|
+
/** OpenAI API key. Shared unless a profile has its own `openai:<profile>`. */
|
|
11
|
+
export declare const OPENAI_ACCOUNT = "openai";
|
|
12
|
+
export declare const openaiAccount: (profile: string) => string;
|
|
13
|
+
/** Anthropic API key. Shared unless a profile has its own `anthropic:<profile>`. */
|
|
14
|
+
export declare const ANTHROPIC_ACCOUNT = "anthropic";
|
|
15
|
+
export declare const anthropicAccount: (profile: string) => string;
|
|
16
|
+
export declare const DEFAULT_POLL_SECONDS = 30;
|
|
17
|
+
export declare const DEFAULT_SYNC_SECONDS = 300;
|
|
18
|
+
/** Full Summary→Transcript reconcile window (matches the retired Grok routine). */
|
|
19
|
+
export declare const SYNC_FULL_WINDOW_DAYS = 90;
|
|
20
|
+
export declare const SYNC_FULL_EVERY_HOURS = 24;
|
|
21
|
+
/** Recordings waiting on Plaud are re-checked every poll for this long, then every 10 min. */
|
|
22
|
+
export declare const PENDING_FAST_HOURS = 48;
|
|
23
|
+
/** How far back deep scans and the cutover snapshot look for late summaries. */
|
|
24
|
+
export declare const WATCH_DAYS = 30;
|
|
25
|
+
/** Stop retrying the labeling call and write with Plaud's own title after this many failures. */
|
|
26
|
+
export declare const LLM_MAX_ATTEMPTS = 6;
|
|
27
|
+
export declare const STATE_KEEP_DAYS = 45;
|
|
28
|
+
/** Claude Haiku by default; set `"llmModel": "gpt-6-luna"` in config.json to go back to OpenAI. */
|
|
29
|
+
export declare const DEFAULT_LLM_MODEL = "claude-haiku-4-5";
|
|
30
|
+
/** OpenAI reasoning effort (GPT-6 Luna). Ignored for Claude models. */
|
|
31
|
+
export declare const DEFAULT_LLM_EFFORT = "high";
|
|
32
|
+
export declare const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
33
|
+
export declare const DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
34
|
+
/** `claude-*` models go to Anthropic's Messages API; everything else to OpenAI. */
|
|
35
|
+
export declare const isAnthropicModel: (model: string) => boolean;
|
|
36
|
+
/** Transcript characters sent to the labeler (names usually surface early). */
|
|
37
|
+
export declare const LLM_TRANSCRIPT_CHARS = 24000;
|
|
38
|
+
/** Markdown page create/read needs this version; also used for queries and updates. */
|
|
39
|
+
export declare const NOTION_VERSION = "2026-03-11";
|
|
40
|
+
export declare const NOTION_TEXT_CHUNK = 2000;
|
|
41
|
+
export declare const NOTION_RICH_TEXT_PER_BLOCK = 100;
|
|
42
|
+
export declare const TYPE_SUMMARY = "Summary";
|
|
43
|
+
export declare const TYPE_TRANSCRIPT = "Transcript";
|
|
44
|
+
export declare const LAUNCHAGENT_LABEL = "com.plaud-notes-to-notion";
|
|
45
|
+
export declare const LOG_FILE_NAME = "plaud-notes-to-notion.log";
|
|
46
|
+
export declare const LOCK_FILE_NAME = "daemon.lock";
|
|
47
|
+
export declare const relogin: (profile: string) => string;
|
|
48
|
+
export declare const RELLOGIN_NOTION: (profile: string) => string;
|
|
49
|
+
export declare const RELLOGIN_LLM = "OpenAI API key missing. Run: plaud-notes-to-notion set-secret openai (or set OPENAI_API_KEY).";
|
|
50
|
+
export declare const RELLOGIN_ANTHROPIC = "Anthropic API key missing. Run: plaud-notes-to-notion set-secret anthropic (or set ANTHROPIC_API_KEY).";
|
|
51
|
+
/** The missing-key message for whichever provider serves `model`. */
|
|
52
|
+
export declare const relloginLlmFor: (model: string) => string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Product constants. No secrets. */
|
|
2
|
+
export const PACKAGE_NAME = "plaud-notes-to-notion";
|
|
3
|
+
export const PACKAGE_VERSION = "1.0.0";
|
|
4
|
+
/** macOS Keychain service. One service, named accounts per profile. */
|
|
5
|
+
export const KEYCHAIN_SERVICE = "plaud-notes-to-notion";
|
|
6
|
+
/** Plaud OAuth token-set JSON for a profile: `plaud:<profile>`. */
|
|
7
|
+
export const plaudAccount = (profile) => `plaud:${profile}`;
|
|
8
|
+
/** Notion integration token for a profile: `notion:<profile>`. */
|
|
9
|
+
export const notionAccount = (profile) => `notion:${profile}`;
|
|
10
|
+
/** OpenAI API key. Shared unless a profile has its own `openai:<profile>`. */
|
|
11
|
+
export const OPENAI_ACCOUNT = "openai";
|
|
12
|
+
export const openaiAccount = (profile) => `openai:${profile}`;
|
|
13
|
+
/** Anthropic API key. Shared unless a profile has its own `anthropic:<profile>`. */
|
|
14
|
+
export const ANTHROPIC_ACCOUNT = "anthropic";
|
|
15
|
+
export const anthropicAccount = (profile) => `anthropic:${profile}`;
|
|
16
|
+
export const DEFAULT_POLL_SECONDS = 30;
|
|
17
|
+
export const DEFAULT_SYNC_SECONDS = 300;
|
|
18
|
+
/** Full Summary→Transcript reconcile window (matches the retired Grok routine). */
|
|
19
|
+
export const SYNC_FULL_WINDOW_DAYS = 90;
|
|
20
|
+
export const SYNC_FULL_EVERY_HOURS = 24;
|
|
21
|
+
/** Recordings waiting on Plaud are re-checked every poll for this long, then every 10 min. */
|
|
22
|
+
export const PENDING_FAST_HOURS = 48;
|
|
23
|
+
/** How far back deep scans and the cutover snapshot look for late summaries. */
|
|
24
|
+
export const WATCH_DAYS = 30;
|
|
25
|
+
/** Stop retrying the labeling call and write with Plaud's own title after this many failures. */
|
|
26
|
+
export const LLM_MAX_ATTEMPTS = 6;
|
|
27
|
+
export const STATE_KEEP_DAYS = 45;
|
|
28
|
+
/** Claude Haiku by default; set `"llmModel": "gpt-6-luna"` in config.json to go back to OpenAI. */
|
|
29
|
+
export const DEFAULT_LLM_MODEL = "claude-haiku-4-5";
|
|
30
|
+
/** OpenAI reasoning effort (GPT-6 Luna). Ignored for Claude models. */
|
|
31
|
+
export const DEFAULT_LLM_EFFORT = "high";
|
|
32
|
+
export const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
33
|
+
export const DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
34
|
+
/** `claude-*` models go to Anthropic's Messages API; everything else to OpenAI. */
|
|
35
|
+
export const isAnthropicModel = (model) => /^claude-/i.test(model.trim());
|
|
36
|
+
/** Transcript characters sent to the labeler (names usually surface early). */
|
|
37
|
+
export const LLM_TRANSCRIPT_CHARS = 24_000;
|
|
38
|
+
/** Markdown page create/read needs this version; also used for queries and updates. */
|
|
39
|
+
export const NOTION_VERSION = "2026-03-11";
|
|
40
|
+
export const NOTION_TEXT_CHUNK = 2000;
|
|
41
|
+
export const NOTION_RICH_TEXT_PER_BLOCK = 100;
|
|
42
|
+
export const TYPE_SUMMARY = "Summary";
|
|
43
|
+
export const TYPE_TRANSCRIPT = "Transcript";
|
|
44
|
+
export const LAUNCHAGENT_LABEL = "com.plaud-notes-to-notion";
|
|
45
|
+
export const LOG_FILE_NAME = "plaud-notes-to-notion.log";
|
|
46
|
+
export const LOCK_FILE_NAME = "daemon.lock";
|
|
47
|
+
export const relogin = (profile) => `Plaud sign-in expired for profile ${profile}. Re-run: plaud-notes-to-notion login --profile ${profile}`;
|
|
48
|
+
export const RELLOGIN_NOTION = (profile) => `Notion token missing or rejected for profile ${profile}. Run: plaud-notes-to-notion set-secret notion --profile ${profile} (and share the Plaud Notes database with that integration).`;
|
|
49
|
+
export const RELLOGIN_LLM = "OpenAI API key missing. Run: plaud-notes-to-notion set-secret openai (or set OPENAI_API_KEY).";
|
|
50
|
+
export const RELLOGIN_ANTHROPIC = "Anthropic API key missing. Run: plaud-notes-to-notion set-secret anthropic (or set ANTHROPIC_API_KEY).";
|
|
51
|
+
/** The missing-key message for whichever provider serves `model`. */
|
|
52
|
+
export const relloginLlmFor = (model) => (isAnthropicModel(model) ? RELLOGIN_ANTHROPIC : RELLOGIN_LLM);
|
|
53
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Logger } from "./log.js";
|
|
2
|
+
import type { SecretStore } from "./secrets.js";
|
|
3
|
+
/**
|
|
4
|
+
* Long-running LaunchAgent loop. Per enabled profile: ingest every pollSeconds
|
|
5
|
+
* (deep scan every 10 min), Summary→Transcript sync every syncSeconds.
|
|
6
|
+
* Re-reads config.json when it changes, so turning Tim on needs no restart.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runDaemon(options: {
|
|
9
|
+
store: SecretStore;
|
|
10
|
+
log: Logger;
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}): Promise<number>;
|