videobook-engine 2.0.1
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 +214 -0
- package/dist/artifacts.d.ts +20 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +312 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/books.d.ts +7 -0
- package/dist/books.d.ts.map +1 -0
- package/dist/books.js +27 -0
- package/dist/books.js.map +1 -0
- package/dist/cas.d.ts +26 -0
- package/dist/cas.d.ts.map +1 -0
- package/dist/cas.js +139 -0
- package/dist/cas.js.map +1 -0
- package/dist/communications.d.ts +15 -0
- package/dist/communications.d.ts.map +1 -0
- package/dist/communications.js +139 -0
- package/dist/communications.js.map +1 -0
- package/dist/context.d.ts +42 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +197 -0
- package/dist/context.js.map +1 -0
- package/dist/domain.d.ts +32 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +399 -0
- package/dist/domain.js.map +1 -0
- package/dist/engine-types.d.ts +548 -0
- package/dist/engine-types.d.ts.map +1 -0
- package/dist/engine-types.js +10 -0
- package/dist/engine-types.js.map +1 -0
- package/dist/engine.d.ts +213 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +130 -0
- package/dist/engine.js.map +1 -0
- package/dist/files.d.ts +28 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +476 -0
- package/dist/files.js.map +1 -0
- package/dist/history-types.d.ts +74 -0
- package/dist/history-types.d.ts.map +1 -0
- package/dist/history-types.js +2 -0
- package/dist/history-types.js.map +1 -0
- package/dist/history.d.ts +20 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +921 -0
- package/dist/history.js.map +1 -0
- package/dist/ids.d.ts +4 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +14 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/job-queue.d.ts +51 -0
- package/dist/job-queue.d.ts.map +1 -0
- package/dist/job-queue.js +443 -0
- package/dist/job-queue.js.map +1 -0
- package/dist/media.d.ts +7 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +60 -0
- package/dist/media.js.map +1 -0
- package/dist/metadata.d.ts +21 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +222 -0
- package/dist/metadata.js.map +1 -0
- package/dist/notebook/types.d.ts +51 -0
- package/dist/notebook/types.d.ts.map +1 -0
- package/dist/notebook/types.js +2 -0
- package/dist/notebook/types.js.map +1 -0
- package/dist/resolver.d.ts +15 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +81 -0
- package/dist/resolver.js.map +1 -0
- package/dist/runtime-services.d.ts +65 -0
- package/dist/runtime-services.d.ts.map +1 -0
- package/dist/runtime-services.js +584 -0
- package/dist/runtime-services.js.map +1 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +509 -0
- package/dist/schema.js.map +1 -0
- package/dist/similarity.d.ts +4 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +1551 -0
- package/dist/similarity.js.map +1 -0
- package/dist/status.d.ts +9 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +231 -0
- package/dist/status.js.map +1 -0
- package/dist/storage.d.ts +7 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +129 -0
- package/dist/storage.js.map +1 -0
- package/dist/store.d.ts +55 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +378 -0
- package/dist/store.js.map +1 -0
- package/dist/timeline.d.ts +9 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +236 -0
- package/dist/timeline.js.map +1 -0
- package/docs/engine-layout.md +489 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# videobook-engine
|
|
2
|
+
|
|
3
|
+
`videobook-engine` is a local-first, Dolt-native storage engine for one
|
|
4
|
+
videobook per engine root. It keeps book state, artifacts, files, metadata,
|
|
5
|
+
notebook graphs, revisions, and action history in a single catalog.
|
|
6
|
+
|
|
7
|
+
There is no project layer. A fresh engine root creates exactly one Book;
|
|
8
|
+
reopening that root always returns the same book.
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { createEngine } from "videobook-engine";
|
|
14
|
+
|
|
15
|
+
const engine = createEngine({
|
|
16
|
+
rootDir: ".videobook",
|
|
17
|
+
initialBookSlug: "my-story",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const book = engine.book.get();
|
|
21
|
+
// { bookId: "…", slug: "my-story", createdAt: … }
|
|
22
|
+
|
|
23
|
+
const script = await engine.artifacts.create({
|
|
24
|
+
kind: "script",
|
|
25
|
+
name: "opening draft",
|
|
26
|
+
});
|
|
27
|
+
if (!script.ok) throw new Error(script.error.message);
|
|
28
|
+
|
|
29
|
+
await engine.files.write(
|
|
30
|
+
script.value.artifactId,
|
|
31
|
+
"original.md",
|
|
32
|
+
"# Opening\n\nA small cat waits by the window.",
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const history = engine.history.artifact(script.value.artifactId);
|
|
36
|
+
engine.close();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`initialBookSlug` is required only when `videobook.db` does not exist yet. On
|
|
40
|
+
later opens it is optional and never changes the stored book. Rename the book
|
|
41
|
+
explicitly with `await engine.book.rename("new-name")`.
|
|
42
|
+
|
|
43
|
+
## Storage model
|
|
44
|
+
|
|
45
|
+
Each engine root owns exactly one book:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
rootDir/
|
|
49
|
+
data/
|
|
50
|
+
videobook.db # Dolt semantic catalog and SQLite runtime state
|
|
51
|
+
objects/sha256/ # content-addressed file objects
|
|
52
|
+
workspaces/
|
|
53
|
+
<artifact UUID>/ # disposable materialized artifact files
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Semantic tables are committed as Dolt revisions. Runtime tables (jobs, leases,
|
|
57
|
+
views, caches, settings, and logs) share the same database, match the
|
|
58
|
+
versioned `runtime_%` ignore policy, and are never staged. Semantic surrogate
|
|
59
|
+
identities are UUIDv7 values. Artifact slugs are human-facing names and can be
|
|
60
|
+
reused after hard deletion; immutable CAS objects remain available to history.
|
|
61
|
+
|
|
62
|
+
The current catalog format is schema version 4. It intentionally rejects v3
|
|
63
|
+
and older catalogs rather than migrating them; create a fresh engine root.
|
|
64
|
+
|
|
65
|
+
The 25 versioned semantic tables are `engine_schema`, `book`, `artifacts`,
|
|
66
|
+
`objects`, `artifact_files`, `book_metadata`, `artifact_metadata`,
|
|
67
|
+
`entities`, `notebooks`, `cells`, `edges`, `runs`, `timeline`,
|
|
68
|
+
`timeline_slots`, `timeline_audio`, `audio_waveforms`, `prompt_entries`,
|
|
69
|
+
`messages`, `operations`, `actions`, `action_events`, `action_parents`,
|
|
70
|
+
`action_artifacts`, `action_write_set`, and `job_runs`. Dolt's versioned
|
|
71
|
+
`dolt_ignore` configuration table carries the local-table policy.
|
|
72
|
+
|
|
73
|
+
The 14 local-only tables are `runtime_meta`, `runtime_jobs`,
|
|
74
|
+
`runtime_resource_leases`, `runtime_object_publications`,
|
|
75
|
+
`runtime_workspace_entries`, `runtime_artifact_views`,
|
|
76
|
+
`runtime_pending_tasks`, `runtime_generation_errors`, `runtime_settings`,
|
|
77
|
+
`runtime_logs`, `runtime_commit_outbox`, `runtime_similarity_embeddings`,
|
|
78
|
+
`runtime_text_similarity_documents`, and `runtime_text_similarity_chunks`.
|
|
79
|
+
|
|
80
|
+
See [the complete engine layout](docs/engine-layout.md) for every schema
|
|
81
|
+
column, relationship, index, runtime/CAS structure, current editing contract,
|
|
82
|
+
and the additional normalized structures a full non-linear editor will need.
|
|
83
|
+
|
|
84
|
+
## Artifacts and slugs
|
|
85
|
+
|
|
86
|
+
Artifact slugs are canonical and kind-prefixed. Supplying a `name` derives a
|
|
87
|
+
slug; supplying a `slug` validates it. Repeated name-based creation adds a
|
|
88
|
+
numeric suffix when needed.
|
|
89
|
+
|
|
90
|
+
| Kind | Prefix | Example |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `video` | `vid-` | `vid-opening-shot` |
|
|
93
|
+
| `image` | `img-` | `img-cat-portrait` |
|
|
94
|
+
| `audio` | `aud-` | `aud-ambient-bed` |
|
|
95
|
+
| `script` | `script-` | `script-opening-draft` |
|
|
96
|
+
| `character` | `char-` | `char-protagonist` |
|
|
97
|
+
| `prompt` | `prompt-` | `prompt-sunrise` |
|
|
98
|
+
| `scene` | `scene-` | `scene-rooftop` |
|
|
99
|
+
| `final` | `final` | `final` |
|
|
100
|
+
|
|
101
|
+
There is no `notebook` artifact kind or `book-` artifact prefix. Notebook
|
|
102
|
+
graphs remain available separately through `engine.notebooks`.
|
|
103
|
+
|
|
104
|
+
## API surface
|
|
105
|
+
|
|
106
|
+
- `engine.book` — `get()` and `rename(slug)` for the singleton book
|
|
107
|
+
- `engine.artifacts` — create, list, get, rename, delete, and resolve slugs
|
|
108
|
+
- `engine.files` and `engine.workspaces` — immutable object-backed files and
|
|
109
|
+
disposable materialization
|
|
110
|
+
- `engine.metadata` — book metadata, artifact metadata, and audio waveforms
|
|
111
|
+
- `engine.timeline` — typed timeline reads, revision reads, replacement, and
|
|
112
|
+
reset
|
|
113
|
+
- `engine.entities` and `engine.notebooks` — normalized characters, prompts,
|
|
114
|
+
scenes, and notebook graph documents
|
|
115
|
+
- `engine.prompts` and `engine.messages` — semantic prompt and message history
|
|
116
|
+
- `engine.history` — revisions, generic action graph entries, and forward
|
|
117
|
+
restores
|
|
118
|
+
- `engine.jobs`, `engine.status`, `engine.settings`, and `engine.logs` —
|
|
119
|
+
runtime coordination
|
|
120
|
+
- `engine.storage` — object publication and catalog backup
|
|
121
|
+
- `engine.similarity` — optional local media and text similarity
|
|
122
|
+
|
|
123
|
+
All APIs operate in the engine's one book. No method accepts or returns a
|
|
124
|
+
project ID.
|
|
125
|
+
|
|
126
|
+
Deleting an artifact or entity that is referenced by a live cell or timeline
|
|
127
|
+
row returns `IN_USE` with `details.references`. Deleting a notebook cascades
|
|
128
|
+
its owned cells, edges, and terminal runs. There are no tombstone rows.
|
|
129
|
+
|
|
130
|
+
## Revisions and restores
|
|
131
|
+
|
|
132
|
+
Every semantic mutation creates a Dolt revision. Use a revision hash (or an
|
|
133
|
+
unambiguous prefix) to inspect or restore state:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const revisions = engine.history.revisions();
|
|
137
|
+
|
|
138
|
+
await engine.history.restoreArtifact(
|
|
139
|
+
artifactId,
|
|
140
|
+
revisions[0]!.hash,
|
|
141
|
+
"script-restored-draft", // optional replacement slug
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await engine.history.restore(revisions[0]!.hash);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`restoreArtifact` keeps the artifact UUID stable and restores its files,
|
|
148
|
+
metadata, and waveform as a new forward revision. `restore` replays the whole
|
|
149
|
+
book snapshot forward: book metadata, artifacts and files, entities,
|
|
150
|
+
notebooks, timeline, prompts, and messages. Runtime work is invalidated and
|
|
151
|
+
active jobs are aborted during a restore.
|
|
152
|
+
|
|
153
|
+
## Future forks
|
|
154
|
+
|
|
155
|
+
Schema v4 prepares stable row identities and normalized merge boundaries for
|
|
156
|
+
DoltHub-native forks. A fork is a separate catalog copy in another namespace,
|
|
157
|
+
keeps the same `bookId`, and can open a pull request against the upstream
|
|
158
|
+
`main` branch. User, origin, fork, and pull-request APIs are intentionally not
|
|
159
|
+
part of this release; an open engine still accepts only its local `main`
|
|
160
|
+
branch.
|
|
161
|
+
|
|
162
|
+
Generic action records are available for higher-level workflows:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const action = await engine.history.recordAction({
|
|
166
|
+
operation: "generate_image",
|
|
167
|
+
scope: "artifact",
|
|
168
|
+
targetArtifactId: imageId,
|
|
169
|
+
inputArtifactIds: [promptId],
|
|
170
|
+
outputArtifactIds: [imageId],
|
|
171
|
+
writeSet: [`artifact:${imageId}`],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const page = engine.history.actions({ limit: 50 });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Similarity
|
|
178
|
+
|
|
179
|
+
Similarity is opt-in. Provide a media embedding provider or use the built-in
|
|
180
|
+
local CLIP configuration. Text similarity is enabled separately.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
const engine = createEngine({
|
|
184
|
+
rootDir: ".videobook",
|
|
185
|
+
initialBookSlug: "reference-library",
|
|
186
|
+
similarity: {
|
|
187
|
+
audio: {},
|
|
188
|
+
text: {},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await engine.similarity.index(imageArtifactId);
|
|
193
|
+
await engine.similarity.index(similarImageArtifactId);
|
|
194
|
+
|
|
195
|
+
const matches = await engine.similarity.findSimilar(imageArtifactId, {
|
|
196
|
+
limit: 10,
|
|
197
|
+
minScore: 0.7,
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Image, video, and audio sources must be named `original.<extension>`. Audio
|
|
202
|
+
similarity is opt-in through `similarity.audio` and uses local CLAP embeddings
|
|
203
|
+
without Python. Supported audio extensions are MP3, WAV, OGG, FLAC, AAC, and
|
|
204
|
+
M4A. Text similarity supports `original.md`, `original.txt`, and
|
|
205
|
+
`original.json` for `script`, `character`, `prompt`, `scene`, and `final`
|
|
206
|
+
artifacts. All similarity queries search the single book-wide pool while
|
|
207
|
+
preserving media kind and embedding-space boundaries.
|
|
208
|
+
|
|
209
|
+
## Backups
|
|
210
|
+
|
|
211
|
+
Configure `remoteObjects` to publish content-addressed objects and
|
|
212
|
+
`catalogBackup` to push the Dolt catalog. `engine.storage.backup()` publishes
|
|
213
|
+
objects first, then pushes the catalog, so a restored catalog never points to
|
|
214
|
+
objects that have not been uploaded.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Artifact, ArtifactKind, CreateArtifactInput, EngineError, RenameArtifactInput, Result } from "./engine-types.js";
|
|
2
|
+
import { EngineContext } from "./context.js";
|
|
3
|
+
export declare function createArtifactsApi(context: EngineContext): {
|
|
4
|
+
create: (input: CreateArtifactInput | string, name?: string) => Promise<Result<Artifact, EngineError>>;
|
|
5
|
+
list: (options?: {
|
|
6
|
+
sort?: "newest" | "oldest";
|
|
7
|
+
}) => Artifact[];
|
|
8
|
+
get: (artifact: string) => Result<Artifact, EngineError>;
|
|
9
|
+
resolveSlug: (slug: string) => Result<Artifact, EngineError>;
|
|
10
|
+
isSlugAvailable: (slug: string) => boolean;
|
|
11
|
+
rename: (input: RenameArtifactInput | string, name?: string) => Promise<Result<Artifact, EngineError>>;
|
|
12
|
+
delete: (artifact: string) => Promise<Result<{
|
|
13
|
+
artifactId: string;
|
|
14
|
+
slug: string;
|
|
15
|
+
}, EngineError>>;
|
|
16
|
+
};
|
|
17
|
+
export declare function normalizeKind(input: string): ArtifactKind;
|
|
18
|
+
/** Normalizes a name or slug with the canonical prefix for its artifact kind. */
|
|
19
|
+
export declare function artifactSlug(kind: ArtifactKind, input: string): string;
|
|
20
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,MAAM,EACP,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EAId,MAAM,cAAc,CAAC;AActB,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa;oBAG5C,mBAAmB,GAAG,MAAM,SAC5B,MAAM,KACZ,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;qBAExB;QAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;KAAE,KAAG,QAAQ,EAAE;oBAE5C,MAAM,KAAG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC;wBAElC,MAAM,KAAG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC;4BAYlC,MAAM,KAAG,OAAO;oBAS/B,mBAAmB,GAAG,MAAM,SAC5B,MAAM,KACZ,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;uBAG7B,MAAM,KACf,OAAO,CACR,MAAM,CACJ;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EACpC,WAAW,CACZ,CACF;EAEJ;AAgPD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CA4BzD;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAuBtE"}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { ok } from "./engine-types.js";
|
|
3
|
+
import { resultOf, syncResultOf, } from "./context.js";
|
|
4
|
+
import { canonicalJson } from "./store.js";
|
|
5
|
+
import { EngineFault } from "./store.js";
|
|
6
|
+
import { newUuidV7 } from "./ids.js";
|
|
7
|
+
export function createArtifactsApi(context) {
|
|
8
|
+
return {
|
|
9
|
+
create: (input, name) => createArtifact(context, input, name),
|
|
10
|
+
list: (options) => listArtifacts(context, options),
|
|
11
|
+
get: (artifact) => syncResultOf(() => context.artifact(context.artifactRow(artifact))),
|
|
12
|
+
resolveSlug: (slug) => syncResultOf(() => {
|
|
13
|
+
const row = context.store.db
|
|
14
|
+
.prepare(`SELECT artifact_id, slug, kind, created_at
|
|
15
|
+
FROM artifacts
|
|
16
|
+
WHERE slug=?`)
|
|
17
|
+
.get(slug);
|
|
18
|
+
if (!row)
|
|
19
|
+
throw new Error(`Active artifact slug not found: ${slug}`);
|
|
20
|
+
return context.artifact(row);
|
|
21
|
+
}),
|
|
22
|
+
isSlugAvailable: (slug) => !context.store.db
|
|
23
|
+
.prepare(`SELECT 1 AS present
|
|
24
|
+
FROM artifacts
|
|
25
|
+
WHERE slug=?`)
|
|
26
|
+
.get(slug),
|
|
27
|
+
rename: (input, name) => renameArtifact(context, input, name),
|
|
28
|
+
delete: (artifact) => deleteArtifact(context, artifact),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function createArtifact(context, input, positionalName) {
|
|
32
|
+
return resultOf(async () => {
|
|
33
|
+
const parsed = typeof input === "string"
|
|
34
|
+
? {
|
|
35
|
+
kind: normalizeKind(input),
|
|
36
|
+
name: positionalName ?? "",
|
|
37
|
+
explicitSlug: undefined,
|
|
38
|
+
}
|
|
39
|
+
: {
|
|
40
|
+
kind: normalizeKind(input.kind),
|
|
41
|
+
name: input.name ?? input.slug ?? "",
|
|
42
|
+
explicitSlug: input.slug,
|
|
43
|
+
};
|
|
44
|
+
const base = artifactSlug(parsed.kind, parsed.explicitSlug ?? parsed.name);
|
|
45
|
+
const slug = parsed.explicitSlug === undefined
|
|
46
|
+
? nextActiveSlug(context, base)
|
|
47
|
+
: base;
|
|
48
|
+
const artifactId = newUuidV7();
|
|
49
|
+
const mutation = await context.store.semantic({
|
|
50
|
+
operation: "create_artifact",
|
|
51
|
+
artifactId,
|
|
52
|
+
details: { slug, kind: parsed.kind },
|
|
53
|
+
writeSet: [
|
|
54
|
+
`artifact:${artifactId}`,
|
|
55
|
+
`artifact-slug:${slug}`,
|
|
56
|
+
],
|
|
57
|
+
}, ["artifacts"], (_operationId, now) => {
|
|
58
|
+
context.store.db
|
|
59
|
+
.prepare(`INSERT INTO artifacts(
|
|
60
|
+
artifact_id, slug, kind, created_at
|
|
61
|
+
) VALUES (?, ?, ?, ?)`)
|
|
62
|
+
.run(artifactId, slug, parsed.kind, now);
|
|
63
|
+
context.store.db
|
|
64
|
+
.prepare(`INSERT INTO runtime_artifact_views(
|
|
65
|
+
artifact_id, status, meta_json, deadline_at, updated_at
|
|
66
|
+
) VALUES (?, 'pending', '{}', ?, ?)`)
|
|
67
|
+
.run(artifactId, now + 30_000, now);
|
|
68
|
+
context.store.db
|
|
69
|
+
.prepare(`INSERT INTO runtime_workspace_entries(
|
|
70
|
+
artifact_id, path, last_accessed_at
|
|
71
|
+
) VALUES (?, ?, ?)`)
|
|
72
|
+
.run(artifactId, context.artifactPath(artifactId), now);
|
|
73
|
+
});
|
|
74
|
+
context.ensureArtifactWorkspace(artifactId);
|
|
75
|
+
return ok(context.artifact(context.artifactRow(artifactId)), mutation.revision);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function listArtifacts(context, options = {}) {
|
|
79
|
+
const direction = options.sort === "oldest" ? "ASC" : "DESC";
|
|
80
|
+
const rows = context.store.db
|
|
81
|
+
.prepare(`SELECT artifact_id, slug, kind, created_at
|
|
82
|
+
FROM artifacts
|
|
83
|
+
ORDER BY created_at ${direction}, artifact_id ${direction}`)
|
|
84
|
+
.all();
|
|
85
|
+
return rows.map((row) => context.artifact(row));
|
|
86
|
+
}
|
|
87
|
+
async function renameArtifact(context, input, positionalName) {
|
|
88
|
+
return resultOf(async () => {
|
|
89
|
+
const parsed = typeof input === "string"
|
|
90
|
+
? { artifact: input, name: positionalName ?? "", slug: undefined }
|
|
91
|
+
: input;
|
|
92
|
+
const current = context.artifactRow(parsed.artifact);
|
|
93
|
+
const slug = artifactSlug(current.kind, parsed.slug ?? parsed.name ?? "");
|
|
94
|
+
if (slug === current.slug)
|
|
95
|
+
return context.artifact(current);
|
|
96
|
+
const mutation = await context.store.semantic({
|
|
97
|
+
operation: "rename_artifact",
|
|
98
|
+
artifactId: current.artifact_id,
|
|
99
|
+
details: { oldSlug: current.slug, newSlug: slug },
|
|
100
|
+
writeSet: [
|
|
101
|
+
`artifact:${current.artifact_id}`,
|
|
102
|
+
`artifact-slug:${current.slug}`,
|
|
103
|
+
`artifact-slug:${slug}`,
|
|
104
|
+
],
|
|
105
|
+
}, ["artifacts"], () => {
|
|
106
|
+
context.store.db
|
|
107
|
+
.prepare(`UPDATE artifacts
|
|
108
|
+
SET slug=?
|
|
109
|
+
WHERE artifact_id=?`)
|
|
110
|
+
.run(slug, current.artifact_id);
|
|
111
|
+
});
|
|
112
|
+
return ok(context.artifact(context.artifactRow(current.artifact_id)), mutation.revision);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function deleteArtifact(context, artifactReference) {
|
|
116
|
+
return resultOf(async () => {
|
|
117
|
+
const artifact = context.artifactRow(artifactReference);
|
|
118
|
+
const references = artifactReferences(context, artifact.artifact_id);
|
|
119
|
+
if (references.length > 0) {
|
|
120
|
+
throw new EngineFault({
|
|
121
|
+
code: "IN_USE",
|
|
122
|
+
message: `Artifact is still referenced: ${artifact.slug}`,
|
|
123
|
+
details: { references },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const jobs = context.store.db
|
|
127
|
+
.prepare(`SELECT id, artifact_id, type, payload_json, result_json, started_at
|
|
128
|
+
FROM runtime_jobs
|
|
129
|
+
WHERE artifact_id=?
|
|
130
|
+
AND state IN ('queued','running','completing')`)
|
|
131
|
+
.all(artifact.artifact_id);
|
|
132
|
+
const mutation = await context.store.semantic({
|
|
133
|
+
operation: "delete_artifact",
|
|
134
|
+
artifactId: artifact.artifact_id,
|
|
135
|
+
details: {
|
|
136
|
+
slug: artifact.slug,
|
|
137
|
+
cancelledJobs: jobs.map((job) => job.id),
|
|
138
|
+
},
|
|
139
|
+
writeSet: [
|
|
140
|
+
`artifact:${artifact.artifact_id}`,
|
|
141
|
+
`artifact-slug:${artifact.slug}`,
|
|
142
|
+
],
|
|
143
|
+
}, [
|
|
144
|
+
"artifacts",
|
|
145
|
+
"artifact_files",
|
|
146
|
+
"artifact_metadata",
|
|
147
|
+
"audio_waveforms",
|
|
148
|
+
"job_runs",
|
|
149
|
+
], (_operationId, now) => {
|
|
150
|
+
context.store.db
|
|
151
|
+
.prepare("DELETE FROM artifacts WHERE artifact_id=?")
|
|
152
|
+
.run(artifact.artifact_id);
|
|
153
|
+
for (const job of jobs) {
|
|
154
|
+
const errorJson = canonicalJson({ message: "Artifact deleted" });
|
|
155
|
+
context.store.db
|
|
156
|
+
.prepare(`UPDATE runtime_jobs
|
|
157
|
+
SET state='aborted', error_json=?, finished_at=?,
|
|
158
|
+
lease_expires_at=NULL, pid=NULL, fence=fence+1
|
|
159
|
+
WHERE id=?`)
|
|
160
|
+
.run(errorJson, now, job.id);
|
|
161
|
+
context.store.db
|
|
162
|
+
.prepare(`INSERT INTO job_runs(
|
|
163
|
+
run_id, artifact_id, job_type, state,
|
|
164
|
+
payload_json, result_json, error_json,
|
|
165
|
+
started_at, finished_at
|
|
166
|
+
) VALUES (?, ?, ?, 'aborted', ?, ?, ?, ?, ?)`)
|
|
167
|
+
.run(newUuidV7(), job.artifact_id, job.type, job.payload_json, job.result_json, errorJson, job.started_at, now);
|
|
168
|
+
}
|
|
169
|
+
context.store.db
|
|
170
|
+
.prepare(`UPDATE runtime_resource_leases
|
|
171
|
+
SET revoked_at=?, fence=fence+1
|
|
172
|
+
WHERE artifact_id=? AND revoked_at IS NULL`)
|
|
173
|
+
.run(now, artifact.artifact_id);
|
|
174
|
+
context.store.db
|
|
175
|
+
.prepare("DELETE FROM runtime_workspace_entries WHERE artifact_id=?")
|
|
176
|
+
.run(artifact.artifact_id);
|
|
177
|
+
context.store.db
|
|
178
|
+
.prepare("DELETE FROM runtime_artifact_views WHERE artifact_id=?")
|
|
179
|
+
.run(artifact.artifact_id);
|
|
180
|
+
context.store.db
|
|
181
|
+
.prepare("DELETE FROM runtime_pending_tasks WHERE artifact_id=?")
|
|
182
|
+
.run(artifact.artifact_id);
|
|
183
|
+
context.store.db
|
|
184
|
+
.prepare("DELETE FROM runtime_generation_errors WHERE artifact_id=?")
|
|
185
|
+
.run(artifact.artifact_id);
|
|
186
|
+
context.store.db
|
|
187
|
+
.prepare("DELETE FROM runtime_similarity_embeddings WHERE artifact_id=?")
|
|
188
|
+
.run(artifact.artifact_id);
|
|
189
|
+
context.store.db
|
|
190
|
+
.prepare("DELETE FROM runtime_text_similarity_documents WHERE artifact_id=?")
|
|
191
|
+
.run(artifact.artifact_id);
|
|
192
|
+
});
|
|
193
|
+
await rm(context.artifactPath(artifact.artifact_id), {
|
|
194
|
+
recursive: true,
|
|
195
|
+
force: true,
|
|
196
|
+
});
|
|
197
|
+
return ok({
|
|
198
|
+
artifactId: artifact.artifact_id,
|
|
199
|
+
slug: artifact.slug,
|
|
200
|
+
}, mutation.revision);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
export function normalizeKind(input) {
|
|
204
|
+
switch (input.trim().toLowerCase()) {
|
|
205
|
+
case "vid":
|
|
206
|
+
case "video":
|
|
207
|
+
return "video";
|
|
208
|
+
case "img":
|
|
209
|
+
case "image":
|
|
210
|
+
return "image";
|
|
211
|
+
case "aud":
|
|
212
|
+
case "audio":
|
|
213
|
+
return "audio";
|
|
214
|
+
case "script":
|
|
215
|
+
case "scr":
|
|
216
|
+
return "script";
|
|
217
|
+
case "char":
|
|
218
|
+
case "character":
|
|
219
|
+
return "character";
|
|
220
|
+
case "prm":
|
|
221
|
+
case "prompt":
|
|
222
|
+
return "prompt";
|
|
223
|
+
case "scn":
|
|
224
|
+
case "scene":
|
|
225
|
+
return "scene";
|
|
226
|
+
case "final":
|
|
227
|
+
return "final";
|
|
228
|
+
default:
|
|
229
|
+
throw new Error(`Invalid artifact kind: ${input}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** Normalizes a name or slug with the canonical prefix for its artifact kind. */
|
|
233
|
+
export function artifactSlug(kind, input) {
|
|
234
|
+
if (kind === "final")
|
|
235
|
+
return "final";
|
|
236
|
+
const prefix = prefixForKind(kind);
|
|
237
|
+
let normalized = input
|
|
238
|
+
.trim()
|
|
239
|
+
.toLowerCase()
|
|
240
|
+
.replace(/^@/, "")
|
|
241
|
+
.replace(/[^a-z0-9_-]+/g, "-")
|
|
242
|
+
.replace(/-+/g, "-")
|
|
243
|
+
.replace(/^[-_]+|[-_]+$/g, "");
|
|
244
|
+
if (!normalized)
|
|
245
|
+
throw new Error("Artifact name or slug is required");
|
|
246
|
+
const knownPrefix = /^(vid|img|aud|script|char|prompt|scene|prm|scn)-/;
|
|
247
|
+
if (knownPrefix.test(normalized)) {
|
|
248
|
+
if (!normalized.startsWith(`${prefix}-`)) {
|
|
249
|
+
throw new Error(`Artifact slug ${normalized} does not match kind ${kind}`);
|
|
250
|
+
}
|
|
251
|
+
return normalized;
|
|
252
|
+
}
|
|
253
|
+
normalized = `${prefix}-${normalized}`;
|
|
254
|
+
if (!/^[a-z0-9]+(?:[a-z0-9_-]*[a-z0-9])?$/.test(normalized)) {
|
|
255
|
+
throw new Error(`Invalid artifact slug: ${normalized}`);
|
|
256
|
+
}
|
|
257
|
+
return normalized;
|
|
258
|
+
}
|
|
259
|
+
function nextActiveSlug(context, base) {
|
|
260
|
+
let suffix = 1;
|
|
261
|
+
let candidate = base;
|
|
262
|
+
while (context.store.db
|
|
263
|
+
.prepare(`SELECT 1 AS present
|
|
264
|
+
FROM artifacts
|
|
265
|
+
WHERE slug=?`)
|
|
266
|
+
.get(candidate)) {
|
|
267
|
+
suffix += 1;
|
|
268
|
+
candidate = `${base}-${suffix}`;
|
|
269
|
+
}
|
|
270
|
+
return candidate;
|
|
271
|
+
}
|
|
272
|
+
function artifactReferences(context, artifactId) {
|
|
273
|
+
const references = [];
|
|
274
|
+
const cells = context.store.db
|
|
275
|
+
.prepare(`SELECT notebook_id, cell_id FROM cells
|
|
276
|
+
WHERE output_artifact_id=? ORDER BY notebook_id, cell_id`)
|
|
277
|
+
.all(artifactId);
|
|
278
|
+
references.push(...cells.map((cell) => ({
|
|
279
|
+
kind: "cell.outputArtifact",
|
|
280
|
+
id: `${cell.notebook_id}/${cell.cell_id}`,
|
|
281
|
+
})));
|
|
282
|
+
const slots = context.store.db
|
|
283
|
+
.prepare("SELECT slot_id FROM timeline_slots WHERE artifact_id=? ORDER BY slot_id")
|
|
284
|
+
.all(artifactId);
|
|
285
|
+
references.push(...slots.map((slot) => ({ kind: "timeline.slot", id: slot.slot_id })));
|
|
286
|
+
const audio = context.store.db
|
|
287
|
+
.prepare("SELECT audio_id FROM timeline_audio WHERE artifact_id=? ORDER BY audio_id")
|
|
288
|
+
.all(artifactId);
|
|
289
|
+
references.push(...audio.map((item) => ({ kind: "timeline.audio", id: item.audio_id })));
|
|
290
|
+
return references;
|
|
291
|
+
}
|
|
292
|
+
function prefixForKind(kind) {
|
|
293
|
+
switch (kind) {
|
|
294
|
+
case "video":
|
|
295
|
+
return "vid";
|
|
296
|
+
case "image":
|
|
297
|
+
return "img";
|
|
298
|
+
case "audio":
|
|
299
|
+
return "aud";
|
|
300
|
+
case "script":
|
|
301
|
+
return "script";
|
|
302
|
+
case "character":
|
|
303
|
+
return "char";
|
|
304
|
+
case "prompt":
|
|
305
|
+
return "prompt";
|
|
306
|
+
case "scene":
|
|
307
|
+
return "scene";
|
|
308
|
+
case "final":
|
|
309
|
+
return "final";
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"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"}
|
package/dist/books.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Book, EngineError, Result } from "./engine-types.js";
|
|
2
|
+
import { EngineContext } from "./context.js";
|
|
3
|
+
export declare function createBookApi(context: EngineContext): {
|
|
4
|
+
get: () => Book;
|
|
5
|
+
rename: (slug: string) => Promise<Result<Book, EngineError>>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=books.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"books.d.ts","sourceRoot":"","sources":["../src/books.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EACL,aAAa,EAGd,MAAM,cAAc,CAAC;AAEtB,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa;eAEvC,IAAI;mBACE,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;EAG7D"}
|
package/dist/books.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ok } from "./engine-types.js";
|
|
2
|
+
import { normalizeBookSlug, resultOf, } from "./context.js";
|
|
3
|
+
export function createBookApi(context) {
|
|
4
|
+
return {
|
|
5
|
+
get: () => context.book(),
|
|
6
|
+
rename: (slug) => renameBook(context, slug),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
async function renameBook(context, requestedSlug) {
|
|
10
|
+
return resultOf(async () => {
|
|
11
|
+
const current = context.bookRow();
|
|
12
|
+
const slug = normalizeBookSlug(requestedSlug);
|
|
13
|
+
if (current.slug === slug)
|
|
14
|
+
return context.book(current);
|
|
15
|
+
const mutation = await context.store.semantic({
|
|
16
|
+
operation: "rename_book",
|
|
17
|
+
details: { oldSlug: current.slug, newSlug: slug },
|
|
18
|
+
writeSet: ["book", `book-slug:${current.slug}`, `book-slug:${slug}`],
|
|
19
|
+
}, ["book"], () => {
|
|
20
|
+
context.store.db
|
|
21
|
+
.prepare("UPDATE book SET slug=? WHERE book_id=?")
|
|
22
|
+
.run(slug, current.book_id);
|
|
23
|
+
});
|
|
24
|
+
return ok(context.book(), mutation.revision);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=books.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"books.js","sourceRoot":"","sources":["../src/books.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAEL,iBAAiB,EACjB,QAAQ,GACT,MAAM,cAAc,CAAC;AAEtB,MAAM,UAAU,aAAa,CAAC,OAAsB;IAClD,OAAO;QACL,GAAG,EAAE,GAAS,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE;QAC/B,MAAM,EAAE,CAAC,IAAY,EAAsC,EAAE,CAC3D,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC;KAC5B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,OAAsB,EACtB,aAAqB;IAErB,OAAO,QAAQ,CAAC,KAAK,IAAI,EAAE;QACzB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,QAAQ,CAC3C;YACE,SAAS,EAAE,aAAa;YACxB,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;YACjD,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,IAAI,EAAE,CAAC;SACrE,EACD,CAAC,MAAM,CAAC,EACR,GAAG,EAAE;YACH,OAAO,CAAC,KAAK,CAAC,EAAE;iBACb,OAAO,CAAC,wCAAwC,CAAC;iBACjD,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC,CACF,CAAC;QACF,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cas.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ContentStore } from "./engine-types.js";
|
|
2
|
+
export interface StoredObject {
|
|
3
|
+
hash: string;
|
|
4
|
+
size: number;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class ObjectStore {
|
|
8
|
+
private readonly remote?;
|
|
9
|
+
readonly root: string;
|
|
10
|
+
readonly prefix: string;
|
|
11
|
+
constructor(root: string, remote?: ContentStore | undefined, prefix?: string);
|
|
12
|
+
put(data: Buffer | string): Promise<StoredObject>;
|
|
13
|
+
import(sourcePath: string): Promise<StoredObject>;
|
|
14
|
+
read(hash: string): Promise<Buffer>;
|
|
15
|
+
/**
|
|
16
|
+
* Makes a content-addressed object available locally and returns its path
|
|
17
|
+
* without copying it into an artifact workspace.
|
|
18
|
+
*/
|
|
19
|
+
ensureLocalPath(hash: string): Promise<string>;
|
|
20
|
+
materialize(hash: string, destinationPath: string): Promise<void>;
|
|
21
|
+
publish(hash: string, expectedSize: number): Promise<void>;
|
|
22
|
+
pathFor(hash: string): string;
|
|
23
|
+
keyFor(hash: string): string;
|
|
24
|
+
private ensureLocal;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=cas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cas.d.ts","sourceRoot":"","sources":["../src/cas.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAL1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGtB,IAAI,EAAE,MAAM,EACK,MAAM,CAAC,EAAE,YAAY,YAAA,EACtC,MAAM,SAAoC;IAMtC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAmBjD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAgBjD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKzC;;;OAGG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK9C,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBhE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAK7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;YAKd,WAAW;CAkB1B"}
|