poddrill 0.1.1 → 0.2.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/.agents/skills/poddrill/SKILL.md +34 -38
- package/.agents/skills/poddrill/references/fetch-audio.md +4 -4
- package/.agents/skills/poddrill/references/select-models.md +6 -4
- package/README.md +19 -4
- package/dist/cli.js +163 -10
- package/dist/client.js +222 -36
- package/dist/embed.js +11 -6
- package/dist/fleet.js +1 -1
- package/dist/moonshine.js +3 -2
- package/dist/needle.js +8 -1
- package/dist/node-version.js +59 -0
- package/dist/owner.js +65 -39
- package/dist/provider.js +27 -23
- package/dist/python-env.js +222 -0
- package/dist/weights.js +88 -0
- package/dist/worker.js +6 -3
- package/dist/workspace.js +37 -5
- package/package.json +6 -4
- package/requirements.txt +3 -0
package/dist/workspace.js
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
6
6
|
import { mkdir, realpath, rename, writeFile } from "node:fs/promises";
|
|
7
|
-
import { homedir } from "node:os";
|
|
8
7
|
import { isAbsolute, join, resolve } from "node:path";
|
|
9
8
|
import { asRecord, errorCode, pathExists, readJsonFile } from "./disk.js";
|
|
10
9
|
import { isModelId, modelIds } from "./models.js";
|
|
11
|
-
import {
|
|
10
|
+
import { homeFromEnv } from "./python-env.js";
|
|
11
|
+
import { isProviderId, providerIds, refuseUnwiredTransport, providerTransport } from "./provider.js";
|
|
12
12
|
/** Every artifact an episode lists, in the order it lists them. */
|
|
13
13
|
export const artifactKinds = ["transcript", "embedding"];
|
|
14
14
|
const CONFIG_FILE = "poddrill.json";
|
|
@@ -18,10 +18,17 @@ const ARTIFACT_OUTPUTS = {
|
|
|
18
18
|
transcript: "transcript.vtt",
|
|
19
19
|
embedding: "embedding.json",
|
|
20
20
|
};
|
|
21
|
+
/** `PODDRILL_WORKSPACE`, else `~/poddrill`. Setup and every other command use this path. */
|
|
22
|
+
export function defaultWorkspacePath(env) {
|
|
23
|
+
const configured = env["PODDRILL_WORKSPACE"];
|
|
24
|
+
if (configured !== undefined && configured !== "") {
|
|
25
|
+
return resolve(configured);
|
|
26
|
+
}
|
|
27
|
+
return resolve(join(homeFromEnv(env), "poddrill"));
|
|
28
|
+
}
|
|
21
29
|
/** `PODDRILL_WORKSPACE`, else `~/poddrill`, resolved with realpath. */
|
|
22
30
|
export async function resolveWorkspace(env) {
|
|
23
|
-
const
|
|
24
|
-
const candidate = resolve(configured === undefined || configured === "" ? join(homedir(), "poddrill") : configured);
|
|
31
|
+
const candidate = defaultWorkspacePath(env);
|
|
25
32
|
let root;
|
|
26
33
|
try {
|
|
27
34
|
root = asWorkspaceRoot(await realpath(candidate));
|
|
@@ -56,6 +63,7 @@ export async function setupWorkspace(input) {
|
|
|
56
63
|
if (!isProviderId(input.provider)) {
|
|
57
64
|
throw new Error(`unknown provider ${input.provider}. Use one of ${providerIds.join(", ")}.`);
|
|
58
65
|
}
|
|
66
|
+
refuseUnwiredTransport(input.provider, providerTransport(input.provider));
|
|
59
67
|
if (!isCount(input.queueLength)) {
|
|
60
68
|
throw new Error(`queue length must be a positive integer, got ${input.queueLength}`);
|
|
61
69
|
}
|
|
@@ -65,12 +73,16 @@ export async function setupWorkspace(input) {
|
|
|
65
73
|
if (input.embeddingLimit !== undefined && !isCount(input.embeddingLimit)) {
|
|
66
74
|
throw new Error(`embedding limit must be a positive integer, got ${input.embeddingLimit}`);
|
|
67
75
|
}
|
|
76
|
+
if (input.python !== undefined && !isAbsolute(input.python)) {
|
|
77
|
+
throw new Error(`python must be an absolute path, got ${input.python}`);
|
|
78
|
+
}
|
|
68
79
|
const requested = resolve(input.root);
|
|
69
80
|
const current = parseConfig(await readJsonFile(join(requested, CONFIG_FILE)));
|
|
70
81
|
const modelFleet = input.modelFleet ?? current?.modelFleet ?? {};
|
|
71
82
|
const modelWeights = input.modelWeights ?? current?.modelWeights ?? {};
|
|
72
83
|
assertModelFleet(modelFleet);
|
|
73
84
|
assertModelWeights(modelWeights);
|
|
85
|
+
const python = pythonPath(input.python, current?.python);
|
|
74
86
|
const config = {
|
|
75
87
|
provider: input.provider,
|
|
76
88
|
queueLength: input.queueLength,
|
|
@@ -78,6 +90,7 @@ export async function setupWorkspace(input) {
|
|
|
78
90
|
modelFleet,
|
|
79
91
|
modelWeights,
|
|
80
92
|
embeddingLimit: input.embeddingLimit ?? current?.embeddingLimit ?? 1,
|
|
93
|
+
...(python === undefined ? {} : { python }),
|
|
81
94
|
};
|
|
82
95
|
const unchanged = current !== undefined && sameConfig(current, config);
|
|
83
96
|
if (input.ownerAlive && current !== undefined && !unchanged) {
|
|
@@ -89,7 +102,7 @@ export async function setupWorkspace(input) {
|
|
|
89
102
|
`poddrill serve is running with provider ${current.provider},`,
|
|
90
103
|
`queue length ${current.queueLength}, fleet limit ${current.fleetLimit},`,
|
|
91
104
|
`and embedding limit ${current.embeddingLimit}.`,
|
|
92
|
-
"Stop it before changing the setup.",
|
|
105
|
+
"Stop it with poddrill stop before changing the setup.",
|
|
93
106
|
].join(" "),
|
|
94
107
|
};
|
|
95
108
|
}
|
|
@@ -181,6 +194,7 @@ function parseConfig(value) {
|
|
|
181
194
|
}
|
|
182
195
|
const fleetLimit = readFleetLimit(record);
|
|
183
196
|
const embeddingLimit = optionalCount(record["embeddingLimit"]);
|
|
197
|
+
const python = readPython(record);
|
|
184
198
|
if (fleetLimit === undefined || embeddingLimit === undefined) {
|
|
185
199
|
return undefined;
|
|
186
200
|
}
|
|
@@ -191,8 +205,19 @@ function parseConfig(value) {
|
|
|
191
205
|
modelFleet: readModelFleet(record["modelFleet"]),
|
|
192
206
|
modelWeights: readModelWeights(record["modelWeights"]),
|
|
193
207
|
embeddingLimit,
|
|
208
|
+
...(python === undefined ? {} : { python }),
|
|
194
209
|
};
|
|
195
210
|
}
|
|
211
|
+
function readPython(record) {
|
|
212
|
+
if (!Object.prototype.hasOwnProperty.call(record, "python")) {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
const python = record["python"];
|
|
216
|
+
if (typeof python !== "string" || !isAbsolute(python)) {
|
|
217
|
+
throw new Error(`python must be an absolute path, got ${String(python)}`);
|
|
218
|
+
}
|
|
219
|
+
return python;
|
|
220
|
+
}
|
|
196
221
|
/**
|
|
197
222
|
* `fleetLimit` wins. An old file that only has `whistleLimit` uses that number.
|
|
198
223
|
* Neither field reads as 1. A present field that is not a positive integer does not parse.
|
|
@@ -275,8 +300,14 @@ function writtenConfig(config) {
|
|
|
275
300
|
body["modelWeights"] = config.modelWeights;
|
|
276
301
|
}
|
|
277
302
|
body["embeddingLimit"] = config.embeddingLimit;
|
|
303
|
+
if (config.python !== undefined) {
|
|
304
|
+
body["python"] = config.python;
|
|
305
|
+
}
|
|
278
306
|
return `${JSON.stringify(body, null, 2)}\n`;
|
|
279
307
|
}
|
|
308
|
+
function pythonPath(requested, current) {
|
|
309
|
+
return requested ?? current;
|
|
310
|
+
}
|
|
280
311
|
/** Absent reads as 1. Present and not a positive integer is `undefined`. */
|
|
281
312
|
function optionalCount(value) {
|
|
282
313
|
if (value === undefined) {
|
|
@@ -289,6 +320,7 @@ function sameConfig(a, b) {
|
|
|
289
320
|
a.queueLength === b.queueLength &&
|
|
290
321
|
a.fleetLimit === b.fleetLimit &&
|
|
291
322
|
a.embeddingLimit === b.embeddingLimit &&
|
|
323
|
+
a.python === b.python &&
|
|
292
324
|
sameById(a.modelFleet, b.modelFleet) &&
|
|
293
325
|
sameById(a.modelWeights, b.modelWeights));
|
|
294
326
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poddrill",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Transcribe episode audio into timed text, group the voices, and store a summary.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jianyu Zhao",
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
-
".agents/skills/poddrill"
|
|
13
|
+
".agents/skills/poddrill",
|
|
14
|
+
"requirements.txt"
|
|
14
15
|
],
|
|
15
16
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
17
|
+
"node": ">=20.19.0"
|
|
17
18
|
},
|
|
18
19
|
"repository": {
|
|
19
20
|
"type": "git",
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"cactusNeedle": "3.2.0",
|
|
23
24
|
"scripts": {
|
|
24
25
|
"build": "node scripts/build-js.mjs",
|
|
25
|
-
"test": "node --experimental-strip-types --test test/episode.test.ts test/fleet.test.ts test/idle-fleet.test.ts test/jobs.test.ts test/cues.test.ts test/summary.test.ts test/cli.test.ts test/audit.test.ts test/needle.test.ts test/publish.test.ts test/client.test.ts test/harness/run.test.ts"
|
|
26
|
+
"test": "node --experimental-strip-types --test test/episode.test.ts test/fleet.test.ts test/idle-fleet.test.ts test/jobs.test.ts test/cues.test.ts test/summary.test.ts test/cli.test.ts test/audit.test.ts test/needle.test.ts test/publish.test.ts test/client.test.ts test/runtime.test.ts test/harness/run.test.ts",
|
|
27
|
+
"test:smoke": "node --experimental-strip-types --test test/smoke.test.ts"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
30
|
"yaml": "2.9.1"
|
package/requirements.txt
ADDED