@nodetool-ai/runtime 0.8.8 → 0.8.9-beta.2
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/dist/.nodetool-build-stamp +1 -1
- package/dist/context.d.ts +6 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +13 -24
- package/dist/context.js.map +1 -1
- package/dist/host-binaries.d.ts +5 -5
- package/dist/host-binaries.js +5 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/invocation-account.d.ts +1 -42
- package/dist/invocation-account.d.ts.map +1 -1
- package/dist/invocation-account.js +1 -59
- package/dist/invocation-account.js.map +1 -1
- package/dist/media/abort.d.ts +8 -0
- package/dist/media/abort.d.ts.map +1 -0
- package/dist/media/abort.js +18 -0
- package/dist/media/abort.js.map +1 -0
- package/dist/media/audio-encoder.d.ts +37 -0
- package/dist/media/audio-encoder.d.ts.map +1 -0
- package/dist/media/audio-encoder.js +118 -0
- package/dist/media/audio-encoder.js.map +1 -0
- package/dist/media/audio.d.ts +36 -0
- package/dist/media/audio.d.ts.map +1 -0
- package/dist/media/audio.js +84 -0
- package/dist/media/audio.js.map +1 -0
- package/dist/media/av.d.ts +51 -0
- package/dist/media/av.d.ts.map +1 -0
- package/dist/media/av.js +146 -0
- package/dist/media/av.js.map +1 -0
- package/dist/media/codecs.d.ts +9 -0
- package/dist/media/codecs.d.ts.map +1 -0
- package/dist/media/codecs.js +17 -0
- package/dist/media/codecs.js.map +1 -0
- package/dist/media/concat.d.ts +56 -0
- package/dist/media/concat.d.ts.map +1 -0
- package/dist/media/concat.js +319 -0
- package/dist/media/concat.js.map +1 -0
- package/dist/media/convert.d.ts +31 -0
- package/dist/media/convert.d.ts.map +1 -0
- package/dist/media/convert.js +114 -0
- package/dist/media/convert.js.map +1 -0
- package/dist/media/decode.d.ts +31 -0
- package/dist/media/decode.d.ts.map +1 -0
- package/dist/media/decode.js +85 -0
- package/dist/media/decode.js.map +1 -0
- package/dist/media/filter-graph.d.ts +53 -0
- package/dist/media/filter-graph.d.ts.map +1 -0
- package/dist/media/filter-graph.js +260 -0
- package/dist/media/filter-graph.js.map +1 -0
- package/dist/media/frames.d.ts +31 -0
- package/dist/media/frames.d.ts.map +1 -0
- package/dist/media/frames.js +112 -0
- package/dist/media/frames.js.map +1 -0
- package/dist/media/index.d.ts +26 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +26 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/mux.d.ts +58 -0
- package/dist/media/mux.d.ts.map +1 -0
- package/dist/media/mux.js +234 -0
- package/dist/media/mux.js.map +1 -0
- package/dist/media/probe.d.ts +84 -0
- package/dist/media/probe.d.ts.map +1 -0
- package/dist/media/probe.js +133 -0
- package/dist/media/probe.js.map +1 -0
- package/dist/media/rgba.d.ts +78 -0
- package/dist/media/rgba.d.ts.map +1 -0
- package/dist/media/rgba.js +285 -0
- package/dist/media/rgba.js.map +1 -0
- package/dist/media/testing.d.ts +119 -0
- package/dist/media/testing.d.ts.map +1 -0
- package/dist/media/testing.js +343 -0
- package/dist/media/testing.js.map +1 -0
- package/dist/media/transcode.d.ts +17 -0
- package/dist/media/transcode.d.ts.map +1 -0
- package/dist/media/transcode.js +19 -0
- package/dist/media/transcode.js.map +1 -0
- package/dist/media/transform.d.ts +61 -0
- package/dist/media/transform.d.ts.map +1 -0
- package/dist/media/transform.js +371 -0
- package/dist/media/transform.js.map +1 -0
- package/dist/media/verify.d.ts +17 -0
- package/dist/media/verify.d.ts.map +1 -0
- package/dist/media/verify.js +65 -0
- package/dist/media/verify.js.map +1 -0
- package/dist/media-loader.d.ts +8 -0
- package/dist/media-loader.d.ts.map +1 -0
- package/dist/media-loader.js +10 -0
- package/dist/media-loader.js.map +1 -0
- package/dist/prefixed-storage-adapter.d.ts.map +1 -1
- package/dist/prefixed-storage-adapter.js +1 -1
- package/dist/prefixed-storage-adapter.js.map +1 -1
- package/dist/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/providers/anthropic-provider.js +1 -17
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/data-uri.d.ts +6 -0
- package/dist/providers/data-uri.d.ts.map +1 -0
- package/dist/providers/data-uri.js +19 -0
- package/dist/providers/data-uri.js.map +1 -0
- package/dist/providers/fake-provider.js +1 -1
- package/dist/providers/meta-transcription.d.ts +1 -5
- package/dist/providers/meta-transcription.d.ts.map +1 -1
- package/dist/providers/meta-transcription.js +9 -55
- package/dist/providers/meta-transcription.js.map +1 -1
- package/dist/providers/node-llama-cpp-trending.generated.js +132 -132
- package/dist/providers/node-llama-cpp-trending.generated.js.map +1 -1
- package/dist/providers/ollama-provider.d.ts.map +1 -1
- package/dist/providers/ollama-provider.js +1 -17
- package/dist/providers/ollama-provider.js.map +1 -1
- package/dist/providers/openai-provider.js +2 -2
- package/dist/providers/openai-provider.js.map +1 -1
- package/dist/providers/openrouter-provider.d.ts.map +1 -1
- package/dist/providers/openrouter-provider.js +1 -0
- package/dist/providers/openrouter-provider.js.map +1 -1
- package/dist/providers/safe-url.d.ts +1 -69
- package/dist/providers/safe-url.d.ts.map +1 -1
- package/dist/providers/safe-url.js +1 -284
- package/dist/providers/safe-url.js.map +1 -1
- package/dist/providers/topaz-provider.d.ts +1 -1
- package/dist/providers/topaz-provider.js +1 -1
- package/dist/providers/video-frame-fallback.d.ts +1 -1
- package/dist/providers/video-frame-fallback.js +4 -4
- package/dist/providers/video-frame-fallback.js.map +1 -1
- package/dist/providers/video-frames.d.ts +6 -16
- package/dist/providers/video-frames.d.ts.map +1 -1
- package/dist/providers/video-frames.js +48 -116
- package/dist/providers/video-frames.js.map +1 -1
- package/dist/storage-workspace.d.ts +1 -61
- package/dist/storage-workspace.d.ts.map +1 -1
- package/dist/storage-workspace.js +2 -430
- package/dist/storage-workspace.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +57 -1
- package/dist/testing.js.map +1 -1
- package/dist/trim-video-window.d.ts.map +1 -1
- package/dist/trim-video-window.js +2 -32
- package/dist/trim-video-window.js.map +1 -1
- package/dist/workspace.d.ts +1 -118
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +1 -111
- package/dist/workspace.js.map +1 -1
- package/dist/yt-dlp-format.d.ts +22 -0
- package/dist/yt-dlp-format.d.ts.map +1 -0
- package/dist/yt-dlp-format.js +90 -0
- package/dist/yt-dlp-format.js.map +1 -0
- package/package.json +23 -6
package/dist/workspace.d.ts
CHANGED
|
@@ -1,119 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* The workspace a run reads and writes files in, as an interface rather than a
|
|
3
|
-
* directory.
|
|
4
|
-
*
|
|
5
|
-
* Everything that touched the workspace used to take `workspaceDir: string` and
|
|
6
|
-
* call `node:fs`, which is why a cloud deployment had no workspace worth the
|
|
7
|
-
* name: there is no directory to hand out. A `Workspace` is backed by any
|
|
8
|
-
* `StorageAdapter`, so the local install passes a `FileStorageAdapter` over a
|
|
9
|
-
* real folder and the cloud passes its S3/Supabase adapter scoped to a per-user
|
|
10
|
-
* prefix. Callers cannot tell the difference and must not try — the interface
|
|
11
|
-
* exposes no adapter for that reason.
|
|
12
|
-
*
|
|
13
|
-
* Paths are workspace-relative and normalized: `notes.md`, `out/report.pdf`,
|
|
14
|
-
* `/workspace/notes.md` and `workspace/notes.md` all name the same file, and a
|
|
15
|
-
* path that would climb out of the root is rejected rather than clamped.
|
|
16
|
-
*
|
|
17
|
-
* Object stores have no directories. `mkdir` is therefore a no-op that
|
|
18
|
-
* succeeds, `list` synthesizes directory entries from key prefixes, and an
|
|
19
|
-
* empty directory does not survive a round trip. Code that needs a real
|
|
20
|
-
* directory — a host binary, an mmap'd database — goes through
|
|
21
|
-
* {@link Workspace.materialize} and {@link Workspace.absorb}, or reads
|
|
22
|
-
* {@link Workspace.localDir} and says plainly that it needs a local workspace.
|
|
23
|
-
*/
|
|
24
|
-
export interface WorkspaceEntry {
|
|
25
|
-
/** Workspace-relative path. */
|
|
26
|
-
path: string;
|
|
27
|
-
/** Last path segment. */
|
|
28
|
-
name: string;
|
|
29
|
-
/** Byte size; 0 for a directory. */
|
|
30
|
-
size: number;
|
|
31
|
-
/** Last-modified time in ms since epoch; 0 for a synthesized directory. */
|
|
32
|
-
modifiedAt: number;
|
|
33
|
-
isDirectory: boolean;
|
|
34
|
-
}
|
|
35
|
-
export interface WorkspaceStat {
|
|
36
|
-
path: string;
|
|
37
|
-
size: number;
|
|
38
|
-
modifiedAt: number;
|
|
39
|
-
contentType?: string;
|
|
40
|
-
isDirectory: boolean;
|
|
41
|
-
}
|
|
42
|
-
export interface Workspace {
|
|
43
|
-
/**
|
|
44
|
-
* The real directory backing this workspace, or null when it is virtual.
|
|
45
|
-
*
|
|
46
|
-
* Read it only to decide whether a host binary can run in place. Anything
|
|
47
|
-
* that merely moves bytes must use the methods below, which work either way.
|
|
48
|
-
*/
|
|
49
|
-
readonly localDir: string | null;
|
|
50
|
-
/** Normalize a caller-supplied path to a workspace key. Throws if it escapes. */
|
|
51
|
-
key(path: string): string;
|
|
52
|
-
/** Opaque URI for a workspace path — what `retrieve`/`delete` round-trip. */
|
|
53
|
-
uri(path: string): string;
|
|
54
|
-
read(path: string): Promise<Uint8Array | null>;
|
|
55
|
-
readText(path: string): Promise<string | null>;
|
|
56
|
-
write(path: string, data: Uint8Array | string, contentType?: string): Promise<void>;
|
|
57
|
-
exists(path: string): Promise<boolean>;
|
|
58
|
-
stat(path: string): Promise<WorkspaceStat | null>;
|
|
59
|
-
/** Direct children of `path`, or every descendant when `recursive`. */
|
|
60
|
-
list(path?: string, opts?: {
|
|
61
|
-
recursive?: boolean;
|
|
62
|
-
}): Promise<WorkspaceEntry[]>;
|
|
63
|
-
/** Delete one file. Returns false when it was not there. */
|
|
64
|
-
delete(path: string): Promise<boolean>;
|
|
65
|
-
/** Delete a directory and everything under it. Returns how many files went. */
|
|
66
|
-
deleteAll(path: string): Promise<number>;
|
|
67
|
-
/** No-op on an object store; creates the directory on a local one. */
|
|
68
|
-
mkdir(path: string): Promise<void>;
|
|
69
|
-
copy(from: string, to: string): Promise<void>;
|
|
70
|
-
move(from: string, to: string): Promise<void>;
|
|
71
|
-
/**
|
|
72
|
-
* A real local path holding this file's current bytes, for handing to a host
|
|
73
|
-
* binary. On a local workspace that is the file itself, so a binary writing
|
|
74
|
-
* in place works. On a virtual one the bytes are staged into a scratch
|
|
75
|
-
* directory and the caller must {@link absorb} anything it changed.
|
|
76
|
-
*/
|
|
77
|
-
materialize(path: string): Promise<string>;
|
|
78
|
-
/** Copy a real local file into the workspace. The inverse of materialize. */
|
|
79
|
-
absorb(localPath: string, path: string): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* A real directory a host binary may use for its inputs and outputs. The
|
|
82
|
-
* workspace root on a local workspace; a per-run scratch directory on a
|
|
83
|
-
* virtual one, whose contents reach storage only through `absorb`.
|
|
84
|
-
*/
|
|
85
|
-
scratchDir(): Promise<string>;
|
|
86
|
-
/** Remove scratch files staged for this workspace after its run ends. */
|
|
87
|
-
cleanupScratch?(): Promise<void>;
|
|
88
|
-
}
|
|
89
|
-
/** Thrown when a path would resolve outside the workspace root. */
|
|
90
|
-
export declare class WorkspacePathError extends Error {
|
|
91
|
-
constructor(path: string);
|
|
92
|
-
}
|
|
93
|
-
/** Thrown when an operation needs a real directory and the workspace is virtual. */
|
|
94
|
-
export declare class WorkspaceNotLocalError extends Error {
|
|
95
|
-
constructor(what: string);
|
|
96
|
-
}
|
|
97
|
-
/** What a mutation did, for a host that wants to react to it. */
|
|
98
|
-
export interface WorkspaceChange {
|
|
99
|
-
kind: "write" | "delete" | "mkdir" | "copy" | "move";
|
|
100
|
-
/** The path written, created or removed. Workspace-relative. */
|
|
101
|
-
path: string;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* A workspace that reports its own mutations.
|
|
105
|
-
*
|
|
106
|
-
* The Workspace Explorer lists files over tRPC and has no way to learn that a
|
|
107
|
-
* chat turn just wrote one — workspace files are not database rows, so the
|
|
108
|
-
* `resource_change` broadcast that keeps every other panel live never fires for
|
|
109
|
-
* them. Wrapping the workspace a run resolves is the one place every writer
|
|
110
|
-
* passes through: the file capabilities, the save nodes, and anything else that
|
|
111
|
-
* goes through the interface rather than `node:fs`.
|
|
112
|
-
*
|
|
113
|
-
* `onChange` fires only after the underlying call resolves, so a rejected write
|
|
114
|
-
* never announces a file that is not there. It is called synchronously and must
|
|
115
|
-
* not throw — a notifier is a side channel, and a run must not fail because a
|
|
116
|
-
* listener did.
|
|
117
|
-
*/
|
|
118
|
-
export declare function observeWorkspace(inner: Workspace, onChange: (change: WorkspaceChange) => void): Workspace;
|
|
1
|
+
export { WorkspacePathError, WorkspaceNotLocalError, observeWorkspace, type Workspace, type WorkspaceEntry, type WorkspaceStat, type WorkspaceChange } from "@nodetool-ai/runtime-core";
|
|
119
2
|
//# sourceMappingURL=workspace.d.ts.map
|
package/dist/workspace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,2BAA2B,CAAC"}
|
package/dist/workspace.js
CHANGED
|
@@ -1,112 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* The workspace a run reads and writes files in, as an interface rather than a
|
|
3
|
-
* directory.
|
|
4
|
-
*
|
|
5
|
-
* Everything that touched the workspace used to take `workspaceDir: string` and
|
|
6
|
-
* call `node:fs`, which is why a cloud deployment had no workspace worth the
|
|
7
|
-
* name: there is no directory to hand out. A `Workspace` is backed by any
|
|
8
|
-
* `StorageAdapter`, so the local install passes a `FileStorageAdapter` over a
|
|
9
|
-
* real folder and the cloud passes its S3/Supabase adapter scoped to a per-user
|
|
10
|
-
* prefix. Callers cannot tell the difference and must not try — the interface
|
|
11
|
-
* exposes no adapter for that reason.
|
|
12
|
-
*
|
|
13
|
-
* Paths are workspace-relative and normalized: `notes.md`, `out/report.pdf`,
|
|
14
|
-
* `/workspace/notes.md` and `workspace/notes.md` all name the same file, and a
|
|
15
|
-
* path that would climb out of the root is rejected rather than clamped.
|
|
16
|
-
*
|
|
17
|
-
* Object stores have no directories. `mkdir` is therefore a no-op that
|
|
18
|
-
* succeeds, `list` synthesizes directory entries from key prefixes, and an
|
|
19
|
-
* empty directory does not survive a round trip. Code that needs a real
|
|
20
|
-
* directory — a host binary, an mmap'd database — goes through
|
|
21
|
-
* {@link Workspace.materialize} and {@link Workspace.absorb}, or reads
|
|
22
|
-
* {@link Workspace.localDir} and says plainly that it needs a local workspace.
|
|
23
|
-
*/
|
|
24
|
-
/** Thrown when a path would resolve outside the workspace root. */
|
|
25
|
-
export class WorkspacePathError extends Error {
|
|
26
|
-
constructor(path) {
|
|
27
|
-
super(`Path '${path}' is outside the workspace`);
|
|
28
|
-
this.name = "WorkspacePathError";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/** Thrown when an operation needs a real directory and the workspace is virtual. */
|
|
32
|
-
export class WorkspaceNotLocalError extends Error {
|
|
33
|
-
constructor(what) {
|
|
34
|
-
super(`${what} needs a local workspace directory, and this run has a virtual ` +
|
|
35
|
-
`one (cloud storage). Run it on a local install, or use a node that ` +
|
|
36
|
-
`reads and writes through the workspace instead.`);
|
|
37
|
-
this.name = "WorkspaceNotLocalError";
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* A workspace that reports its own mutations.
|
|
42
|
-
*
|
|
43
|
-
* The Workspace Explorer lists files over tRPC and has no way to learn that a
|
|
44
|
-
* chat turn just wrote one — workspace files are not database rows, so the
|
|
45
|
-
* `resource_change` broadcast that keeps every other panel live never fires for
|
|
46
|
-
* them. Wrapping the workspace a run resolves is the one place every writer
|
|
47
|
-
* passes through: the file capabilities, the save nodes, and anything else that
|
|
48
|
-
* goes through the interface rather than `node:fs`.
|
|
49
|
-
*
|
|
50
|
-
* `onChange` fires only after the underlying call resolves, so a rejected write
|
|
51
|
-
* never announces a file that is not there. It is called synchronously and must
|
|
52
|
-
* not throw — a notifier is a side channel, and a run must not fail because a
|
|
53
|
-
* listener did.
|
|
54
|
-
*/
|
|
55
|
-
export function observeWorkspace(inner, onChange) {
|
|
56
|
-
const notify = (kind, path) => {
|
|
57
|
-
try {
|
|
58
|
-
onChange({ kind, path });
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// A listener must never break the write it is reporting.
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
return {
|
|
65
|
-
get localDir() {
|
|
66
|
-
return inner.localDir;
|
|
67
|
-
},
|
|
68
|
-
key: (path) => inner.key(path),
|
|
69
|
-
uri: (path) => inner.uri(path),
|
|
70
|
-
read: (path) => inner.read(path),
|
|
71
|
-
readText: (path) => inner.readText(path),
|
|
72
|
-
exists: (path) => inner.exists(path),
|
|
73
|
-
stat: (path) => inner.stat(path),
|
|
74
|
-
list: (path, opts) => inner.list(path, opts),
|
|
75
|
-
materialize: (path) => inner.materialize(path),
|
|
76
|
-
scratchDir: () => inner.scratchDir(),
|
|
77
|
-
cleanupScratch: () => inner.cleanupScratch?.() ?? Promise.resolve(),
|
|
78
|
-
async write(path, data, contentType) {
|
|
79
|
-
await inner.write(path, data, contentType);
|
|
80
|
-
notify("write", path);
|
|
81
|
-
},
|
|
82
|
-
async delete(path) {
|
|
83
|
-
const removed = await inner.delete(path);
|
|
84
|
-
if (removed)
|
|
85
|
-
notify("delete", path);
|
|
86
|
-
return removed;
|
|
87
|
-
},
|
|
88
|
-
async deleteAll(path) {
|
|
89
|
-
const count = await inner.deleteAll(path);
|
|
90
|
-
if (count > 0)
|
|
91
|
-
notify("delete", path);
|
|
92
|
-
return count;
|
|
93
|
-
},
|
|
94
|
-
async mkdir(path) {
|
|
95
|
-
await inner.mkdir(path);
|
|
96
|
-
notify("mkdir", path);
|
|
97
|
-
},
|
|
98
|
-
async copy(from, to) {
|
|
99
|
-
await inner.copy(from, to);
|
|
100
|
-
notify("copy", to);
|
|
101
|
-
},
|
|
102
|
-
async move(from, to) {
|
|
103
|
-
await inner.move(from, to);
|
|
104
|
-
notify("move", to);
|
|
105
|
-
},
|
|
106
|
-
async absorb(localPath, path) {
|
|
107
|
-
await inner.absorb(localPath, path);
|
|
108
|
-
notify("write", path);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
}
|
|
1
|
+
export { WorkspacePathError, WorkspaceNotLocalError, observeWorkspace } from "@nodetool-ai/runtime-core";
|
|
112
2
|
//# sourceMappingURL=workspace.js.map
|
package/dist/workspace.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAKjB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yt-dlp format selectors, split so yt-dlp never merges.
|
|
3
|
+
*
|
|
4
|
+
* yt-dlp merges a `+` selector (`bv*+ba`) with the ffmpeg binary. NodeTool
|
|
5
|
+
* ships no ffmpeg, so a caller downloads each side of the top-level `+` with
|
|
6
|
+
* its own yt-dlp call and muxes the two files in process with
|
|
7
|
+
* `muxStreamCopy` from `@nodetool-ai/runtime/media`.
|
|
8
|
+
*/
|
|
9
|
+
/** What NodeTool asks for when no selector is given: best picture, best sound. */
|
|
10
|
+
export declare const DEFAULT_YT_DLP_FORMAT = "bv*+ba/b";
|
|
11
|
+
/**
|
|
12
|
+
* Split `selector` on its top-level `+`.
|
|
13
|
+
*
|
|
14
|
+
* The result has one component (download one file, no mux) or two (the
|
|
15
|
+
* video side, then the audio side). A `/` fallback stays inside its component
|
|
16
|
+
* for yt-dlp to resolve, so `bv+ba/b` splits into `bv` and `ba/b`. A `+`
|
|
17
|
+
* inside `[...]` is part of a filter and does not split. A `+` inside `(...)`
|
|
18
|
+
* is a merge this cannot split, so it throws, as do unbalanced brackets, an
|
|
19
|
+
* empty side, more than two sides, and a top-level `,` beside a `+`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function splitYtDlpFormat(selector: string): string[];
|
|
22
|
+
//# sourceMappingURL=yt-dlp-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yt-dlp-format.d.ts","sourceRoot":"","sources":["../src/yt-dlp-format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA2D3D"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yt-dlp format selectors, split so yt-dlp never merges.
|
|
3
|
+
*
|
|
4
|
+
* yt-dlp merges a `+` selector (`bv*+ba`) with the ffmpeg binary. NodeTool
|
|
5
|
+
* ships no ffmpeg, so a caller downloads each side of the top-level `+` with
|
|
6
|
+
* its own yt-dlp call and muxes the two files in process with
|
|
7
|
+
* `muxStreamCopy` from `@nodetool-ai/runtime/media`.
|
|
8
|
+
*/
|
|
9
|
+
/** What NodeTool asks for when no selector is given: best picture, best sound. */
|
|
10
|
+
export const DEFAULT_YT_DLP_FORMAT = "bv*+ba/b";
|
|
11
|
+
/**
|
|
12
|
+
* Split `selector` on its top-level `+`.
|
|
13
|
+
*
|
|
14
|
+
* The result has one component (download one file, no mux) or two (the
|
|
15
|
+
* video side, then the audio side). A `/` fallback stays inside its component
|
|
16
|
+
* for yt-dlp to resolve, so `bv+ba/b` splits into `bv` and `ba/b`. A `+`
|
|
17
|
+
* inside `[...]` is part of a filter and does not split. A `+` inside `(...)`
|
|
18
|
+
* is a merge this cannot split, so it throws, as do unbalanced brackets, an
|
|
19
|
+
* empty side, more than two sides, and a top-level `,` beside a `+`.
|
|
20
|
+
*/
|
|
21
|
+
export function splitYtDlpFormat(selector) {
|
|
22
|
+
const text = selector.trim();
|
|
23
|
+
if (!text)
|
|
24
|
+
throw new Error("The format selector is empty");
|
|
25
|
+
const cuts = [];
|
|
26
|
+
let depth = 0;
|
|
27
|
+
let inFilter = false;
|
|
28
|
+
let quote = null;
|
|
29
|
+
let plusInGroup = false;
|
|
30
|
+
let commaAtTop = false;
|
|
31
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
32
|
+
const ch = text[i];
|
|
33
|
+
if (quote) {
|
|
34
|
+
if (ch === quote)
|
|
35
|
+
quote = null;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (inFilter) {
|
|
39
|
+
if (ch === "'" || ch === '"')
|
|
40
|
+
quote = ch;
|
|
41
|
+
else if (ch === "]")
|
|
42
|
+
inFilter = false;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (ch === "[")
|
|
46
|
+
inFilter = true;
|
|
47
|
+
else if (ch === "]")
|
|
48
|
+
throw new Error(`Format selector "${text}" has a "]" with no "["`);
|
|
49
|
+
else if (ch === "(")
|
|
50
|
+
depth += 1;
|
|
51
|
+
else if (ch === ")") {
|
|
52
|
+
if (depth === 0)
|
|
53
|
+
throw new Error(`Format selector "${text}" has a ")" with no "("`);
|
|
54
|
+
depth -= 1;
|
|
55
|
+
}
|
|
56
|
+
else if (ch === "+") {
|
|
57
|
+
if (depth > 0)
|
|
58
|
+
plusInGroup = true;
|
|
59
|
+
else
|
|
60
|
+
cuts.push(i);
|
|
61
|
+
}
|
|
62
|
+
else if (ch === "," && depth === 0) {
|
|
63
|
+
commaAtTop = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (inFilter || quote)
|
|
67
|
+
throw new Error(`Format selector "${text}" has an unclosed "["`);
|
|
68
|
+
if (depth > 0)
|
|
69
|
+
throw new Error(`Format selector "${text}" has an unclosed "("`);
|
|
70
|
+
if (plusInGroup) {
|
|
71
|
+
throw new Error(`Format selector "${text}" merges inside parentheses. NodeTool merges ` +
|
|
72
|
+
`without ffmpeg only at the top level: write it as "<video>+<audio>".`);
|
|
73
|
+
}
|
|
74
|
+
if (cuts.length === 0)
|
|
75
|
+
return [text];
|
|
76
|
+
if (commaAtTop) {
|
|
77
|
+
throw new Error(`Format selector "${text}" mixes "," and "+". Ask for one video and ` +
|
|
78
|
+
`one audio format, as "<video>+<audio>".`);
|
|
79
|
+
}
|
|
80
|
+
if (cuts.length > 1) {
|
|
81
|
+
throw new Error(`Format selector "${text}" merges ${cuts.length + 1} formats. NodeTool ` +
|
|
82
|
+
`muxes one video and one audio format, as "<video>+<audio>".`);
|
|
83
|
+
}
|
|
84
|
+
const parts = [text.slice(0, cuts[0]).trim(), text.slice(cuts[0] + 1).trim()];
|
|
85
|
+
if (parts.some((part) => part.length === 0)) {
|
|
86
|
+
throw new Error(`Format selector "${text}" has an empty side of "+"`);
|
|
87
|
+
}
|
|
88
|
+
return parts;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=yt-dlp-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yt-dlp-format.js","sourceRoot":"","sources":["../src/yt-dlp-format.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodetool-ai/runtime",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.9-beta.2",
|
|
4
4
|
"description": "Processing context, message queue, and output normalization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"@anthropic-ai/sdk": "^0.105.0",
|
|
21
21
|
"@huggingface/inference": "^4.13.25",
|
|
22
22
|
"@meta-sam/parser": "^0.1.0",
|
|
23
|
-
"@nodetool-ai/browser": "0.8.
|
|
24
|
-
"@nodetool-ai/config": "0.8.
|
|
25
|
-
"@nodetool-ai/protocol": "0.8.
|
|
26
|
-
"@nodetool-ai/storage": "0.8.
|
|
23
|
+
"@nodetool-ai/browser": "0.8.9-beta.2",
|
|
24
|
+
"@nodetool-ai/config": "0.8.9-beta.2",
|
|
25
|
+
"@nodetool-ai/protocol": "0.8.9-beta.2",
|
|
26
|
+
"@nodetool-ai/storage": "0.8.9-beta.2",
|
|
27
27
|
"@opentelemetry/api": "^1.9.0",
|
|
28
28
|
"@pydantic/genai-prices": "^0.1.9",
|
|
29
29
|
"fflate": "^0.8.2",
|
|
@@ -32,7 +32,12 @@
|
|
|
32
32
|
"replicate": "^1.4.0",
|
|
33
33
|
"ws": "^8.19.0",
|
|
34
34
|
"zod": "^4.4.3",
|
|
35
|
-
"@nodetool-ai/antigravity-cli": "0.8.
|
|
35
|
+
"@nodetool-ai/antigravity-cli": "0.8.9-beta.2",
|
|
36
|
+
"@mediabunny/server": "1.54.0",
|
|
37
|
+
"mediabunny": "1.54.0",
|
|
38
|
+
"node-av": "^6.1.1",
|
|
39
|
+
"@nodetool-ai/runtime-core": "0.8.9-beta.2",
|
|
40
|
+
"@nodetool-ai/execution-core": "0.8.9-beta.2"
|
|
36
41
|
},
|
|
37
42
|
"devDependencies": {
|
|
38
43
|
"js-tiktoken": "^1.0.21",
|
|
@@ -97,6 +102,18 @@
|
|
|
97
102
|
"import": "./dist/trim-video-window.js",
|
|
98
103
|
"default": "./dist/trim-video-window.js"
|
|
99
104
|
},
|
|
105
|
+
"./media": {
|
|
106
|
+
"nodetool-dev": "./src/media/index.ts",
|
|
107
|
+
"types": "./dist/media/index.d.ts",
|
|
108
|
+
"import": "./dist/media/index.js",
|
|
109
|
+
"default": "./dist/media/index.js"
|
|
110
|
+
},
|
|
111
|
+
"./media/testing": {
|
|
112
|
+
"nodetool-dev": "./src/media/testing.ts",
|
|
113
|
+
"types": "./dist/media/testing.d.ts",
|
|
114
|
+
"import": "./dist/media/testing.js",
|
|
115
|
+
"default": "./dist/media/testing.js"
|
|
116
|
+
},
|
|
100
117
|
"./context": {
|
|
101
118
|
"nodetool-dev": "./src/context.ts",
|
|
102
119
|
"types": "./dist/context.d.ts",
|