@docyrus/animaguru 0.26.0 → 0.28.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/README.md +41 -3
- package/dist/animaguru.js +756 -467
- package/package.json +1 -1
- package/skills/animaguru/SKILL.md +13 -1
- package/skills/animaguru-3d-models/SKILL.md +86 -0
- package/skills/animaguru-character-stage-3d/SKILL.md +35 -0
- package/skills/animaguru-character-stage-3d/references/recipe.md +26 -0
- package/skills/animaguru-exploded-teardown-3d/SKILL.md +38 -0
- package/skills/animaguru-exploded-teardown-3d/references/recipe.md +20 -0
- package/skills/animaguru-product-turntable-3d/SKILL.md +38 -0
- package/skills/animaguru-product-turntable-3d/references/recipe.md +27 -0
- package/skills/animaguru-quiz/SKILL.md +1 -1
- package/skills/animaguru-toy-diorama-3d/SKILL.md +33 -0
- package/skills/animaguru-toy-diorama-3d/references/recipe.md +26 -0
- package/skills/animaguru-video/SKILL.md +5 -1
- package/templates/video/AGENTS.md +1 -1
- package/templates/video/README.md +5 -1
- package/templates/video/package.json +3 -1
- package/templates/video/scripts/install-example.mjs +10 -6
- package/templates/video/shared/locales/en/style-studies.json +35 -0
- package/templates/video/shared/locales/en/timeline.json +1 -0
- package/templates/video/src/kit/index.ts +1 -0
- package/templates/video/src/kit/three-stage.ts +262 -0
- package/templates/video/src/resource-timeline.ts +1 -0
- package/templates/video/src/studies/three/character-stage-3d.ts +172 -0
- package/templates/video/src/studies/three/exploded-teardown-3d.ts +214 -0
- package/templates/video/src/studies/three/index.ts +16 -0
- package/templates/video/src/studies/three/product-turntable-3d.ts +160 -0
- package/templates/video/src/studies/three/toy-diorama-3d.ts +245 -0
- package/templates/video/src/studies/three-film.ts +42 -0
- package/templates/video/src/style.css +2 -1
- package/templates/video/src/timeline-model.ts +1 -1
package/dist/animaguru.js
CHANGED
|
@@ -369,19 +369,19 @@ function jsonInstabilityIssues(document2) {
|
|
|
369
369
|
return issues;
|
|
370
370
|
}
|
|
371
371
|
function createStore(options) {
|
|
372
|
-
const { dirPath, name: name2, fields, pruneUnknown, access:
|
|
372
|
+
const { dirPath, name: name2, fields, pruneUnknown, access: access4 } = options;
|
|
373
373
|
const validators = /* @__PURE__ */ new Map();
|
|
374
374
|
for (const [key, def] of Object.entries(fields)) if (def.schema !== void 0) {
|
|
375
375
|
for (const option of ["default", "validate"]) if (def[option] !== void 0) throw new CrustStoreError("DEFINITION", `field "${key}" mixes "schema" with "${option}" \u2014 the schema exclusively owns validation, transformation, defaults, and optionality`);
|
|
376
376
|
validators.set(key, makeSchemaValidator(def.schema));
|
|
377
377
|
} else if (def.validate !== void 0) validators.set(key, def.validate);
|
|
378
378
|
const filePath = resolveStorePath(dirPath, name2);
|
|
379
|
-
const writeOptions =
|
|
379
|
+
const writeOptions = access4 === "private" ? {
|
|
380
380
|
fileMode: 384,
|
|
381
381
|
directoryMode: 448
|
|
382
|
-
} :
|
|
383
|
-
fileMode:
|
|
384
|
-
directoryMode:
|
|
382
|
+
} : access4 === void 0 || access4 === "default" ? {} : {
|
|
383
|
+
fileMode: access4.file,
|
|
384
|
+
directoryMode: access4.directory
|
|
385
385
|
};
|
|
386
386
|
function normalizeStateTypes(state) {
|
|
387
387
|
const normalized = { ...state };
|
|
@@ -2312,8 +2312,8 @@ var require_lib = __commonJS({
|
|
|
2312
2312
|
if (typeof cb !== "function") {
|
|
2313
2313
|
opts = cb;
|
|
2314
2314
|
cb = null;
|
|
2315
|
-
deferred = new this.Promise(function(
|
|
2316
|
-
deferredResolve =
|
|
2315
|
+
deferred = new this.Promise(function(resolve19, reject) {
|
|
2316
|
+
deferredResolve = resolve19;
|
|
2317
2317
|
deferredReject = reject;
|
|
2318
2318
|
});
|
|
2319
2319
|
}
|
|
@@ -2461,17 +2461,17 @@ var require_lib = __commonJS({
|
|
|
2461
2461
|
if (typeof cb === "function") {
|
|
2462
2462
|
fnx(cb);
|
|
2463
2463
|
} else {
|
|
2464
|
-
return new this.Promise(function(
|
|
2464
|
+
return new this.Promise(function(resolve19, reject) {
|
|
2465
2465
|
if (fnx.length === 1) {
|
|
2466
2466
|
fnx(function(err2, ret) {
|
|
2467
2467
|
if (err2) {
|
|
2468
2468
|
reject(err2);
|
|
2469
2469
|
} else {
|
|
2470
|
-
|
|
2470
|
+
resolve19(ret);
|
|
2471
2471
|
}
|
|
2472
2472
|
});
|
|
2473
2473
|
} else {
|
|
2474
|
-
|
|
2474
|
+
resolve19(fnx());
|
|
2475
2475
|
}
|
|
2476
2476
|
});
|
|
2477
2477
|
}
|
|
@@ -6862,7 +6862,7 @@ var require_pify = __commonJS({
|
|
|
6862
6862
|
"use strict";
|
|
6863
6863
|
var processFn = (fn, options) => function(...args) {
|
|
6864
6864
|
const P = options.promiseModule;
|
|
6865
|
-
return new P((
|
|
6865
|
+
return new P((resolve19, reject) => {
|
|
6866
6866
|
if (options.multiArgs) {
|
|
6867
6867
|
args.push((...result) => {
|
|
6868
6868
|
if (options.errorFirst) {
|
|
@@ -6870,10 +6870,10 @@ var require_pify = __commonJS({
|
|
|
6870
6870
|
reject(result);
|
|
6871
6871
|
} else {
|
|
6872
6872
|
result.shift();
|
|
6873
|
-
|
|
6873
|
+
resolve19(result);
|
|
6874
6874
|
}
|
|
6875
6875
|
} else {
|
|
6876
|
-
|
|
6876
|
+
resolve19(result);
|
|
6877
6877
|
}
|
|
6878
6878
|
});
|
|
6879
6879
|
} else if (options.errorFirst) {
|
|
@@ -6881,11 +6881,11 @@ var require_pify = __commonJS({
|
|
|
6881
6881
|
if (error62) {
|
|
6882
6882
|
reject(error62);
|
|
6883
6883
|
} else {
|
|
6884
|
-
|
|
6884
|
+
resolve19(result);
|
|
6885
6885
|
}
|
|
6886
6886
|
});
|
|
6887
6887
|
} else {
|
|
6888
|
-
args.push(
|
|
6888
|
+
args.push(resolve19);
|
|
6889
6889
|
}
|
|
6890
6890
|
fn.apply(this, args);
|
|
6891
6891
|
});
|
|
@@ -8083,17 +8083,17 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8083
8083
|
const length = Math.ceil((62 + bpath.length + 1) / 8) * 8;
|
|
8084
8084
|
const written = Buffer.alloc(length);
|
|
8085
8085
|
const writer = new BufferCursor(written);
|
|
8086
|
-
const
|
|
8087
|
-
writer.writeUInt32BE(
|
|
8088
|
-
writer.writeUInt32BE(
|
|
8089
|
-
writer.writeUInt32BE(
|
|
8090
|
-
writer.writeUInt32BE(
|
|
8091
|
-
writer.writeUInt32BE(
|
|
8092
|
-
writer.writeUInt32BE(
|
|
8093
|
-
writer.writeUInt32BE(
|
|
8094
|
-
writer.writeUInt32BE(
|
|
8095
|
-
writer.writeUInt32BE(
|
|
8096
|
-
writer.writeUInt32BE(
|
|
8086
|
+
const stat12 = normalizeStats(entry);
|
|
8087
|
+
writer.writeUInt32BE(stat12.ctimeSeconds);
|
|
8088
|
+
writer.writeUInt32BE(stat12.ctimeNanoseconds);
|
|
8089
|
+
writer.writeUInt32BE(stat12.mtimeSeconds);
|
|
8090
|
+
writer.writeUInt32BE(stat12.mtimeNanoseconds);
|
|
8091
|
+
writer.writeUInt32BE(stat12.dev);
|
|
8092
|
+
writer.writeUInt32BE(stat12.ino);
|
|
8093
|
+
writer.writeUInt32BE(stat12.mode);
|
|
8094
|
+
writer.writeUInt32BE(stat12.uid);
|
|
8095
|
+
writer.writeUInt32BE(stat12.gid);
|
|
8096
|
+
writer.writeUInt32BE(stat12.size);
|
|
8097
8097
|
writer.write(entry.oid, 20, "hex");
|
|
8098
8098
|
writer.writeUInt16BE(renderCacheEntryFlags(entry));
|
|
8099
8099
|
writer.write(entry.path, bpath.length, "utf8");
|
|
@@ -8145,13 +8145,13 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8145
8145
|
};
|
|
8146
8146
|
}
|
|
8147
8147
|
async function updateCachedIndexFile(fs2, filepath, cache) {
|
|
8148
|
-
const [
|
|
8148
|
+
const [stat12, rawIndexFile] = await Promise.all([
|
|
8149
8149
|
fs2.lstat(filepath),
|
|
8150
8150
|
fs2.read(filepath)
|
|
8151
8151
|
]);
|
|
8152
8152
|
const index3 = await GitIndex.from(rawIndexFile);
|
|
8153
8153
|
cache.map.set(filepath, index3);
|
|
8154
|
-
cache.stats.set(filepath,
|
|
8154
|
+
cache.stats.set(filepath, stat12);
|
|
8155
8155
|
}
|
|
8156
8156
|
async function isIndexStale(fs2, filepath, cache) {
|
|
8157
8157
|
const savedStats = cache.stats.get(filepath);
|
|
@@ -8208,7 +8208,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8208
8208
|
}
|
|
8209
8209
|
return path;
|
|
8210
8210
|
}
|
|
8211
|
-
function
|
|
8211
|
+
function dirname16(path) {
|
|
8212
8212
|
const last = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
8213
8213
|
if (last === -1) return ".";
|
|
8214
8214
|
if (last === 0) return "/";
|
|
@@ -8216,7 +8216,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8216
8216
|
}
|
|
8217
8217
|
function flatFileListToDirectoryStructure(files) {
|
|
8218
8218
|
const inodes = /* @__PURE__ */ new Map();
|
|
8219
|
-
const
|
|
8219
|
+
const mkdir17 = function(name2) {
|
|
8220
8220
|
if (!inodes.has(name2)) {
|
|
8221
8221
|
const dir = {
|
|
8222
8222
|
type: "tree",
|
|
@@ -8226,7 +8226,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8226
8226
|
children: []
|
|
8227
8227
|
};
|
|
8228
8228
|
inodes.set(name2, dir);
|
|
8229
|
-
dir.parent =
|
|
8229
|
+
dir.parent = mkdir17(dirname16(name2));
|
|
8230
8230
|
if (dir.parent && dir.parent !== dir) dir.parent.children.push(dir);
|
|
8231
8231
|
}
|
|
8232
8232
|
return inodes.get(name2);
|
|
@@ -8239,7 +8239,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8239
8239
|
basename: basename8(name2),
|
|
8240
8240
|
metadata,
|
|
8241
8241
|
// This recursively generates any missing parent folders.
|
|
8242
|
-
parent:
|
|
8242
|
+
parent: mkdir17(dirname16(name2)),
|
|
8243
8243
|
children: []
|
|
8244
8244
|
};
|
|
8245
8245
|
if (file2.parent) file2.parent.children.push(file2);
|
|
@@ -8247,7 +8247,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8247
8247
|
}
|
|
8248
8248
|
return inodes.get(name2);
|
|
8249
8249
|
};
|
|
8250
|
-
|
|
8250
|
+
mkdir17(".");
|
|
8251
8251
|
for (const file2 of files) {
|
|
8252
8252
|
mkfile(file2.path, file2);
|
|
8253
8253
|
}
|
|
@@ -8650,7 +8650,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
8650
8650
|
}
|
|
8651
8651
|
return isAbsolute2 ? `/${normalized}` : normalized;
|
|
8652
8652
|
}
|
|
8653
|
-
function
|
|
8653
|
+
function join20(...args) {
|
|
8654
8654
|
if (args.length === 0) return ".";
|
|
8655
8655
|
let joined;
|
|
8656
8656
|
for (let i2 = 0; i2 < args.length; ++i2) {
|
|
@@ -9052,7 +9052,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
9052
9052
|
for (const [key, value] of actualRefsToWrite) {
|
|
9053
9053
|
await acquireLock(
|
|
9054
9054
|
key,
|
|
9055
|
-
async () => fs2.write(
|
|
9055
|
+
async () => fs2.write(join20(gitdir, key), `${value.trim()}
|
|
9056
9056
|
`, "utf8")
|
|
9057
9057
|
);
|
|
9058
9058
|
}
|
|
@@ -9076,7 +9076,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
9076
9076
|
}
|
|
9077
9077
|
await acquireLock(
|
|
9078
9078
|
ref,
|
|
9079
|
-
async () => fs2.write(
|
|
9079
|
+
async () => fs2.write(join20(gitdir, ref), `${value.trim()}
|
|
9080
9080
|
`, "utf8")
|
|
9081
9081
|
);
|
|
9082
9082
|
}
|
|
@@ -9094,7 +9094,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
9094
9094
|
assertWritableRef(ref);
|
|
9095
9095
|
await acquireLock(
|
|
9096
9096
|
ref,
|
|
9097
|
-
async () => fs2.write(
|
|
9097
|
+
async () => fs2.write(join20(gitdir, ref), `ref: ${value.trim()}
|
|
9098
9098
|
`, "utf8")
|
|
9099
9099
|
);
|
|
9100
9100
|
}
|
|
@@ -9121,7 +9121,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
9121
9121
|
*/
|
|
9122
9122
|
static async deleteRefs({ fs: fs2, gitdir, refs }) {
|
|
9123
9123
|
refs.forEach(assertWritableRef);
|
|
9124
|
-
await Promise.all(refs.map((ref) => fs2.rm(
|
|
9124
|
+
await Promise.all(refs.map((ref) => fs2.rm(join20(gitdir, ref))));
|
|
9125
9125
|
let text2 = await acquireLock(
|
|
9126
9126
|
"packed-refs",
|
|
9127
9127
|
async () => fs2.read(`${gitdir}/packed-refs`, { encoding: "utf8" })
|
|
@@ -10208,7 +10208,7 @@ If you're a developer and you believe this is a bug in isomorphic-git, please fi
|
|
|
10208
10208
|
format = "content",
|
|
10209
10209
|
getExternalRefDelta
|
|
10210
10210
|
}) {
|
|
10211
|
-
let list3 = await fs2.readdir(
|
|
10211
|
+
let list3 = await fs2.readdir(join20(gitdir, "objects/pack"));
|
|
10212
10212
|
list3 = list3.filter((x2) => x2.endsWith(".idx"));
|
|
10213
10213
|
for (const filename of list3) {
|
|
10214
10214
|
const indexFile = `${gitdir}/objects/pack/${filename}`;
|
|
@@ -11065,9 +11065,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11065
11065
|
}
|
|
11066
11066
|
const tree = GitTree.from(object2);
|
|
11067
11067
|
for (const entry2 of tree) {
|
|
11068
|
-
map2.set(
|
|
11068
|
+
map2.set(join20(filepath, entry2.path), entry2);
|
|
11069
11069
|
}
|
|
11070
|
-
return tree.entries().map((entry2) =>
|
|
11070
|
+
return tree.entries().map((entry2) => join20(filepath, entry2.path));
|
|
11071
11071
|
}
|
|
11072
11072
|
async type(entry) {
|
|
11073
11073
|
if (entry._type === false) {
|
|
@@ -11160,9 +11160,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11160
11160
|
if (await entry.type() !== "tree") return null;
|
|
11161
11161
|
const filepath = entry._fullpath;
|
|
11162
11162
|
const { fs: fs2, dir } = this;
|
|
11163
|
-
const names = await fs2.readdir(
|
|
11163
|
+
const names = await fs2.readdir(join20(dir, filepath));
|
|
11164
11164
|
if (names === null) return null;
|
|
11165
|
-
return names.map((name2) =>
|
|
11165
|
+
return names.map((name2) => join20(filepath, name2));
|
|
11166
11166
|
}
|
|
11167
11167
|
async type(entry) {
|
|
11168
11168
|
if (entry._type === false) {
|
|
@@ -11179,23 +11179,23 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11179
11179
|
async stat(entry) {
|
|
11180
11180
|
if (entry._stat === false) {
|
|
11181
11181
|
const { fs: fs2, dir } = this;
|
|
11182
|
-
let
|
|
11183
|
-
if (!
|
|
11182
|
+
let stat12 = await fs2.lstat(`${dir}/${entry._fullpath}`);
|
|
11183
|
+
if (!stat12) {
|
|
11184
11184
|
throw new Error(
|
|
11185
11185
|
`ENOENT: no such file or directory, lstat '${entry._fullpath}'`
|
|
11186
11186
|
);
|
|
11187
11187
|
}
|
|
11188
|
-
let type =
|
|
11189
|
-
if (type === "blob" && !
|
|
11188
|
+
let type = stat12.isDirectory() ? "tree" : "blob";
|
|
11189
|
+
if (type === "blob" && !stat12.isFile() && !stat12.isSymbolicLink()) {
|
|
11190
11190
|
type = "special";
|
|
11191
11191
|
}
|
|
11192
11192
|
entry._type = type;
|
|
11193
|
-
|
|
11194
|
-
entry._mode =
|
|
11195
|
-
if (
|
|
11196
|
-
|
|
11193
|
+
stat12 = normalizeStats(stat12);
|
|
11194
|
+
entry._mode = stat12.mode;
|
|
11195
|
+
if (stat12.size === -1 && entry._actualSize) {
|
|
11196
|
+
stat12.size = entry._actualSize;
|
|
11197
11197
|
}
|
|
11198
|
-
entry._stat =
|
|
11198
|
+
entry._stat = stat12;
|
|
11199
11199
|
}
|
|
11200
11200
|
return entry._stat;
|
|
11201
11201
|
}
|
|
@@ -11383,24 +11383,24 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11383
11383
|
};
|
|
11384
11384
|
return walk2(root);
|
|
11385
11385
|
}
|
|
11386
|
-
async function mkdirp(
|
|
11386
|
+
async function mkdirp(mkdir17, filepath, retries = 10) {
|
|
11387
11387
|
try {
|
|
11388
|
-
await
|
|
11388
|
+
await mkdir17(filepath);
|
|
11389
11389
|
} catch (err2) {
|
|
11390
11390
|
if (err2 === null) return;
|
|
11391
11391
|
if (err2.code === "EEXIST") return;
|
|
11392
11392
|
if (err2.code !== "ENOENT") throw err2;
|
|
11393
|
-
const parent =
|
|
11393
|
+
const parent = dirname16(filepath);
|
|
11394
11394
|
if (parent === "." || parent === "/" || parent === filepath) throw err2;
|
|
11395
|
-
await mkdirp(
|
|
11395
|
+
await mkdirp(mkdir17, parent, retries);
|
|
11396
11396
|
for (let attempt = 0; ; attempt++) {
|
|
11397
11397
|
try {
|
|
11398
|
-
await
|
|
11398
|
+
await mkdir17(filepath);
|
|
11399
11399
|
return;
|
|
11400
11400
|
} catch (err22) {
|
|
11401
11401
|
if (err22 === null || err22.code === "EEXIST") return;
|
|
11402
11402
|
if (err22.code === "ENOENT" && attempt < retries) {
|
|
11403
|
-
await new Promise((
|
|
11403
|
+
await new Promise((resolve19) => setTimeout(resolve19, 0));
|
|
11404
11404
|
continue;
|
|
11405
11405
|
}
|
|
11406
11406
|
throw err22;
|
|
@@ -11415,10 +11415,10 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11415
11415
|
} else if (entries.length) {
|
|
11416
11416
|
await Promise.all(
|
|
11417
11417
|
entries.map((entry) => {
|
|
11418
|
-
const subpath =
|
|
11419
|
-
return fs2.lstat(subpath).then((
|
|
11420
|
-
if (!
|
|
11421
|
-
return
|
|
11418
|
+
const subpath = join20(filepath, entry);
|
|
11419
|
+
return fs2.lstat(subpath).then((stat12) => {
|
|
11420
|
+
if (!stat12) return;
|
|
11421
|
+
return stat12.isDirectory() ? rmRecursive(fs2, subpath) : fs2.rm(subpath);
|
|
11422
11422
|
});
|
|
11423
11423
|
})
|
|
11424
11424
|
).then(() => fs2.rmdir(filepath));
|
|
@@ -11554,7 +11554,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11554
11554
|
try {
|
|
11555
11555
|
await this._writeFile(filepath, contents, options);
|
|
11556
11556
|
} catch (err2) {
|
|
11557
|
-
await this.mkdir(
|
|
11557
|
+
await this.mkdir(dirname16(filepath));
|
|
11558
11558
|
await this._writeFile(filepath, contents, options);
|
|
11559
11559
|
}
|
|
11560
11560
|
}
|
|
@@ -11700,7 +11700,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11700
11700
|
if (isAbsolute(submoduleGitdir)) {
|
|
11701
11701
|
return submoduleGitdir;
|
|
11702
11702
|
}
|
|
11703
|
-
const gitdir =
|
|
11703
|
+
const gitdir = join20(dirname16(dotgit), submoduleGitdir);
|
|
11704
11704
|
return gitdir;
|
|
11705
11705
|
});
|
|
11706
11706
|
} else {
|
|
@@ -11722,7 +11722,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11722
11722
|
async function abortMerge({
|
|
11723
11723
|
fs: _fs,
|
|
11724
11724
|
dir,
|
|
11725
|
-
gitdir =
|
|
11725
|
+
gitdir = join20(dir, ".git"),
|
|
11726
11726
|
commit: commit2 = "HEAD",
|
|
11727
11727
|
cache = {}
|
|
11728
11728
|
}) {
|
|
@@ -11803,17 +11803,17 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11803
11803
|
* @param {string} args.filepath - The path of the file to check.
|
|
11804
11804
|
* @returns {Promise<boolean>} - `true` if the file is ignored, `false` otherwise.
|
|
11805
11805
|
*/
|
|
11806
|
-
static async isIgnored({ fs: fs2, dir, gitdir =
|
|
11806
|
+
static async isIgnored({ fs: fs2, dir, gitdir = join20(dir, ".git"), filepath }) {
|
|
11807
11807
|
if (basename8(filepath) === ".git") return true;
|
|
11808
11808
|
if (filepath === ".") return false;
|
|
11809
11809
|
let excludes = "";
|
|
11810
|
-
const excludesFile =
|
|
11810
|
+
const excludesFile = join20(gitdir, "info", "exclude");
|
|
11811
11811
|
if (await fs2.exists(excludesFile)) {
|
|
11812
11812
|
excludes = await fs2.read(excludesFile, "utf8");
|
|
11813
11813
|
}
|
|
11814
11814
|
const pairs = [
|
|
11815
11815
|
{
|
|
11816
|
-
gitignore:
|
|
11816
|
+
gitignore: join20(dir, ".gitignore"),
|
|
11817
11817
|
filepath
|
|
11818
11818
|
}
|
|
11819
11819
|
];
|
|
@@ -11822,7 +11822,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11822
11822
|
const folder = pieces.slice(0, i2).join("/");
|
|
11823
11823
|
const file2 = pieces.slice(i2).join("/");
|
|
11824
11824
|
pairs.push({
|
|
11825
|
-
gitignore:
|
|
11825
|
+
gitignore: join20(dir, folder, ".gitignore"),
|
|
11826
11826
|
filepath: file2
|
|
11827
11827
|
});
|
|
11828
11828
|
}
|
|
@@ -11836,7 +11836,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11836
11836
|
}
|
|
11837
11837
|
const ign = ignore2().add(excludes);
|
|
11838
11838
|
ign.add(file2);
|
|
11839
|
-
const parentdir =
|
|
11839
|
+
const parentdir = dirname16(p.filepath);
|
|
11840
11840
|
if (parentdir !== "." && ign.ignores(parentdir)) return true;
|
|
11841
11841
|
if (ignoredStatus) {
|
|
11842
11842
|
ignoredStatus = !ign.test(p.filepath).unignored;
|
|
@@ -11909,7 +11909,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11909
11909
|
async function add({
|
|
11910
11910
|
fs: _fs,
|
|
11911
11911
|
dir,
|
|
11912
|
-
gitdir =
|
|
11912
|
+
gitdir = join20(dir, ".git"),
|
|
11913
11913
|
filepath,
|
|
11914
11914
|
cache = {},
|
|
11915
11915
|
force = false,
|
|
@@ -11973,17 +11973,17 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11973
11973
|
});
|
|
11974
11974
|
if (ignored) return;
|
|
11975
11975
|
}
|
|
11976
|
-
const stats = await fs2.lstat(
|
|
11976
|
+
const stats = await fs2.lstat(join20(dir, currentFilepath));
|
|
11977
11977
|
if (!stats) throw new NotFoundError(currentFilepath);
|
|
11978
11978
|
if (stats.isDirectory()) {
|
|
11979
|
-
const children = await fs2.readdir(
|
|
11979
|
+
const children = await fs2.readdir(join20(dir, currentFilepath));
|
|
11980
11980
|
if (parallel) {
|
|
11981
11981
|
const promises3 = children.map(
|
|
11982
11982
|
(child) => addToIndex({
|
|
11983
11983
|
dir,
|
|
11984
11984
|
gitdir,
|
|
11985
11985
|
fs: fs2,
|
|
11986
|
-
filepath: [
|
|
11986
|
+
filepath: [join20(currentFilepath, child)],
|
|
11987
11987
|
index: index3,
|
|
11988
11988
|
force,
|
|
11989
11989
|
parallel,
|
|
@@ -11997,7 +11997,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11997
11997
|
dir,
|
|
11998
11998
|
gitdir,
|
|
11999
11999
|
fs: fs2,
|
|
12000
|
-
filepath: [
|
|
12000
|
+
filepath: [join20(currentFilepath, child)],
|
|
12001
12001
|
index: index3,
|
|
12002
12002
|
force,
|
|
12003
12003
|
parallel,
|
|
@@ -12006,7 +12006,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
12006
12006
|
}
|
|
12007
12007
|
}
|
|
12008
12008
|
} else {
|
|
12009
|
-
const object2 = stats.isSymbolicLink() ? await fs2.readlink(
|
|
12009
|
+
const object2 = stats.isSymbolicLink() ? await fs2.readlink(join20(dir, currentFilepath)).then(posixifyPathBuffer) : await fs2.read(join20(dir, currentFilepath), { autocrlf });
|
|
12010
12010
|
if (object2 === null) throw new NotFoundError(currentFilepath);
|
|
12011
12011
|
const oid = await _writeObject({ fs: fs2, gitdir, type: "blob", object: object2 });
|
|
12012
12012
|
index3.insert({ filepath: currentFilepath, stats, oid });
|
|
@@ -12440,7 +12440,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
12440
12440
|
fs: _fs,
|
|
12441
12441
|
onSign,
|
|
12442
12442
|
dir,
|
|
12443
|
-
gitdir =
|
|
12443
|
+
gitdir = join20(dir, ".git"),
|
|
12444
12444
|
ref = "refs/notes/commits",
|
|
12445
12445
|
oid,
|
|
12446
12446
|
note,
|
|
@@ -12510,7 +12510,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
12510
12510
|
async function addRemote({
|
|
12511
12511
|
fs: fs2,
|
|
12512
12512
|
dir,
|
|
12513
|
-
gitdir =
|
|
12513
|
+
gitdir = join20(dir, ".git"),
|
|
12514
12514
|
remote,
|
|
12515
12515
|
url: url3,
|
|
12516
12516
|
force = false
|
|
@@ -12580,7 +12580,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
12580
12580
|
fs: _fs,
|
|
12581
12581
|
onSign,
|
|
12582
12582
|
dir,
|
|
12583
|
-
gitdir =
|
|
12583
|
+
gitdir = join20(dir, ".git"),
|
|
12584
12584
|
ref,
|
|
12585
12585
|
tagger: _tagger,
|
|
12586
12586
|
message = ref,
|
|
@@ -12661,7 +12661,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
12661
12661
|
async function branch({
|
|
12662
12662
|
fs: fs2,
|
|
12663
12663
|
dir,
|
|
12664
|
-
gitdir =
|
|
12664
|
+
gitdir = join20(dir, ".git"),
|
|
12665
12665
|
ref,
|
|
12666
12666
|
object: object2,
|
|
12667
12667
|
checkout: checkout2 = false,
|
|
@@ -13325,7 +13325,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13325
13325
|
onProgress,
|
|
13326
13326
|
onPostCheckout,
|
|
13327
13327
|
dir,
|
|
13328
|
-
gitdir =
|
|
13328
|
+
gitdir = join20(dir, ".git"),
|
|
13329
13329
|
remote = "origin",
|
|
13330
13330
|
ref: _ref,
|
|
13331
13331
|
filepaths,
|
|
@@ -13406,7 +13406,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13406
13406
|
fs: fs2,
|
|
13407
13407
|
cache,
|
|
13408
13408
|
dir,
|
|
13409
|
-
gitdir =
|
|
13409
|
+
gitdir = join20(dir, ".git"),
|
|
13410
13410
|
index: index3,
|
|
13411
13411
|
ourOid,
|
|
13412
13412
|
baseOid,
|
|
@@ -13676,7 +13676,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13676
13676
|
workdir: WORKDIR
|
|
13677
13677
|
};
|
|
13678
13678
|
async function checkAndWriteBlob(fs2, gitdir, dir, filepath, oid = null) {
|
|
13679
|
-
const currentFilepath =
|
|
13679
|
+
const currentFilepath = join20(dir, filepath);
|
|
13680
13680
|
const stats = await fs2.lstat(currentFilepath);
|
|
13681
13681
|
if (!stats) throw new NotFoundError(currentFilepath);
|
|
13682
13682
|
if (stats.isDirectory())
|
|
@@ -13845,7 +13845,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13845
13845
|
stageUpdated.push({
|
|
13846
13846
|
filepath,
|
|
13847
13847
|
oid,
|
|
13848
|
-
stats: await fs2.lstat(
|
|
13848
|
+
stats: await fs2.lstat(join20(dir, filepath))
|
|
13849
13849
|
});
|
|
13850
13850
|
return {
|
|
13851
13851
|
method: "write",
|
|
@@ -13858,7 +13858,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13858
13858
|
});
|
|
13859
13859
|
await acquireLock(gitdir, async () => {
|
|
13860
13860
|
for (const op of ops) {
|
|
13861
|
-
const currentFilepath =
|
|
13861
|
+
const currentFilepath = join20(dir, op.filepath);
|
|
13862
13862
|
switch (op.method) {
|
|
13863
13863
|
case "rmdir":
|
|
13864
13864
|
await fs2.rmdir(currentFilepath);
|
|
@@ -13992,7 +13992,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
13992
13992
|
async function cherryPick({
|
|
13993
13993
|
fs: _fs,
|
|
13994
13994
|
dir,
|
|
13995
|
-
gitdir =
|
|
13995
|
+
gitdir = join20(dir, ".git"),
|
|
13996
13996
|
oid,
|
|
13997
13997
|
cache = {},
|
|
13998
13998
|
committer,
|
|
@@ -14497,7 +14497,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14497
14497
|
* @returns {Promise<Set<string>>} - A set of shallow object IDs.
|
|
14498
14498
|
*/
|
|
14499
14499
|
static async read({ fs: fs2, gitdir }) {
|
|
14500
|
-
const filepath =
|
|
14500
|
+
const filepath = join20(gitdir, "shallow");
|
|
14501
14501
|
const oids = /* @__PURE__ */ new Set();
|
|
14502
14502
|
await acquireLock(filepath, async function() {
|
|
14503
14503
|
const text2 = await fs2.read(filepath, { encoding: "utf8" });
|
|
@@ -14518,7 +14518,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14518
14518
|
* @returns {Promise<void>}
|
|
14519
14519
|
*/
|
|
14520
14520
|
static async write({ fs: fs2, gitdir, oids }) {
|
|
14521
|
-
const filepath =
|
|
14521
|
+
const filepath = join20(gitdir, "shallow");
|
|
14522
14522
|
if (oids.size > 0) {
|
|
14523
14523
|
const text2 = [...oids].join("\n") + "\n";
|
|
14524
14524
|
await acquireLock(filepath, async function() {
|
|
@@ -14544,7 +14544,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14544
14544
|
oid,
|
|
14545
14545
|
getExternalRefDelta
|
|
14546
14546
|
}) {
|
|
14547
|
-
let list3 = await fs2.readdir(
|
|
14547
|
+
let list3 = await fs2.readdir(join20(gitdir, "objects/pack"));
|
|
14548
14548
|
list3 = list3.filter((x2) => x2.endsWith(".idx"));
|
|
14549
14549
|
for (const filename of list3) {
|
|
14550
14550
|
const indexFile = `${gitdir}/objects/pack/${filename}`;
|
|
@@ -14616,9 +14616,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14616
14616
|
throw Error("You cannot write to a FIFO that has already been ended!");
|
|
14617
14617
|
}
|
|
14618
14618
|
if (this._waiting) {
|
|
14619
|
-
const
|
|
14619
|
+
const resolve19 = this._waiting;
|
|
14620
14620
|
this._waiting = null;
|
|
14621
|
-
|
|
14621
|
+
resolve19({ value: chunk });
|
|
14622
14622
|
} else {
|
|
14623
14623
|
this._queue.push(chunk);
|
|
14624
14624
|
}
|
|
@@ -14626,9 +14626,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14626
14626
|
end() {
|
|
14627
14627
|
this._ended = true;
|
|
14628
14628
|
if (this._waiting) {
|
|
14629
|
-
const
|
|
14629
|
+
const resolve19 = this._waiting;
|
|
14630
14630
|
this._waiting = null;
|
|
14631
|
-
|
|
14631
|
+
resolve19({ done: true });
|
|
14632
14632
|
}
|
|
14633
14633
|
}
|
|
14634
14634
|
destroy(err2) {
|
|
@@ -14647,8 +14647,8 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14647
14647
|
"You cannot call read until the previous call to read has returned!"
|
|
14648
14648
|
);
|
|
14649
14649
|
}
|
|
14650
|
-
return new Promise((
|
|
14651
|
-
this._waiting =
|
|
14650
|
+
return new Promise((resolve19) => {
|
|
14651
|
+
this._waiting = resolve19;
|
|
14652
14652
|
});
|
|
14653
14653
|
}
|
|
14654
14654
|
};
|
|
@@ -14803,7 +14803,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14803
14803
|
const acks = [];
|
|
14804
14804
|
let nak = false;
|
|
14805
14805
|
let done = false;
|
|
14806
|
-
return new Promise((
|
|
14806
|
+
return new Promise((resolve19, reject) => {
|
|
14807
14807
|
forAwait2(packetlines, (data) => {
|
|
14808
14808
|
const line = data.toString("utf8").trim();
|
|
14809
14809
|
if (line.startsWith("shallow")) {
|
|
@@ -14830,11 +14830,11 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14830
14830
|
nak = true;
|
|
14831
14831
|
}
|
|
14832
14832
|
if (done) {
|
|
14833
|
-
stream.error ? reject(stream.error) :
|
|
14833
|
+
stream.error ? reject(stream.error) : resolve19({ shallows, unshallows, acks, nak, packfile, progress });
|
|
14834
14834
|
}
|
|
14835
14835
|
}).finally(() => {
|
|
14836
14836
|
if (!done) {
|
|
14837
|
-
stream.error ? reject(stream.error) :
|
|
14837
|
+
stream.error ? reject(stream.error) : resolve19({ shallows, unshallows, acks, nak, packfile, progress });
|
|
14838
14838
|
}
|
|
14839
14839
|
});
|
|
14840
14840
|
});
|
|
@@ -15135,7 +15135,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15135
15135
|
}
|
|
15136
15136
|
if (packfileSha !== "" && !emptyPackfile(packfile)) {
|
|
15137
15137
|
res.packfile = `objects/pack/pack-${packfileSha}.pack`;
|
|
15138
|
-
const fullpath =
|
|
15138
|
+
const fullpath = join20(gitdir, res.packfile);
|
|
15139
15139
|
await fs2.write(fullpath, packfile);
|
|
15140
15140
|
const getExternalRefDelta = (oid2) => _readObject({ fs: fs2, cache, gitdir, oid: oid2 });
|
|
15141
15141
|
const idx = await GitPackIndex.fromPack({
|
|
@@ -15151,7 +15151,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15151
15151
|
fs: fs2,
|
|
15152
15152
|
bare = false,
|
|
15153
15153
|
dir,
|
|
15154
|
-
gitdir = bare ? dir :
|
|
15154
|
+
gitdir = bare ? dir : join20(dir, ".git"),
|
|
15155
15155
|
defaultBranch = "master"
|
|
15156
15156
|
}) {
|
|
15157
15157
|
if (await fs2.exists(gitdir + "/config")) return;
|
|
@@ -15265,7 +15265,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15265
15265
|
onAuthFailure,
|
|
15266
15266
|
onPostCheckout,
|
|
15267
15267
|
dir,
|
|
15268
|
-
gitdir =
|
|
15268
|
+
gitdir = join20(dir, ".git"),
|
|
15269
15269
|
url: url3,
|
|
15270
15270
|
corsProxy = void 0,
|
|
15271
15271
|
ref = void 0,
|
|
@@ -15328,7 +15328,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15328
15328
|
fs: _fs,
|
|
15329
15329
|
onSign,
|
|
15330
15330
|
dir,
|
|
15331
|
-
gitdir =
|
|
15331
|
+
gitdir = join20(dir, ".git"),
|
|
15332
15332
|
message,
|
|
15333
15333
|
author,
|
|
15334
15334
|
committer,
|
|
@@ -15377,7 +15377,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15377
15377
|
async function currentBranch({
|
|
15378
15378
|
fs: fs2,
|
|
15379
15379
|
dir,
|
|
15380
|
-
gitdir =
|
|
15380
|
+
gitdir = join20(dir, ".git"),
|
|
15381
15381
|
fullname = false,
|
|
15382
15382
|
test = false
|
|
15383
15383
|
}) {
|
|
@@ -15418,7 +15418,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15418
15418
|
async function deleteBranch({
|
|
15419
15419
|
fs: fs2,
|
|
15420
15420
|
dir,
|
|
15421
|
-
gitdir =
|
|
15421
|
+
gitdir = join20(dir, ".git"),
|
|
15422
15422
|
ref
|
|
15423
15423
|
}) {
|
|
15424
15424
|
try {
|
|
@@ -15436,7 +15436,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15436
15436
|
throw err2;
|
|
15437
15437
|
}
|
|
15438
15438
|
}
|
|
15439
|
-
async function deleteRef({ fs: fs2, dir, gitdir =
|
|
15439
|
+
async function deleteRef({ fs: fs2, dir, gitdir = join20(dir, ".git"), ref }) {
|
|
15440
15440
|
try {
|
|
15441
15441
|
assertParameter("fs", fs2);
|
|
15442
15442
|
assertParameter("ref", ref);
|
|
@@ -15456,7 +15456,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15456
15456
|
async function deleteRemote({
|
|
15457
15457
|
fs: fs2,
|
|
15458
15458
|
dir,
|
|
15459
|
-
gitdir =
|
|
15459
|
+
gitdir = join20(dir, ".git"),
|
|
15460
15460
|
remote
|
|
15461
15461
|
}) {
|
|
15462
15462
|
try {
|
|
@@ -15478,7 +15478,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15478
15478
|
ref = ref.startsWith("refs/tags/") ? ref : `refs/tags/${ref}`;
|
|
15479
15479
|
await GitRefManager.deleteRef({ fs: fs2, gitdir, ref });
|
|
15480
15480
|
}
|
|
15481
|
-
async function deleteTag({ fs: fs2, dir, gitdir =
|
|
15481
|
+
async function deleteTag({ fs: fs2, dir, gitdir = join20(dir, ".git"), ref }) {
|
|
15482
15482
|
try {
|
|
15483
15483
|
assertParameter("fs", fs2);
|
|
15484
15484
|
assertParameter("ref", ref);
|
|
@@ -15507,7 +15507,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15507
15507
|
getExternalRefDelta
|
|
15508
15508
|
}) {
|
|
15509
15509
|
const results = [];
|
|
15510
|
-
let list3 = await fs2.readdir(
|
|
15510
|
+
let list3 = await fs2.readdir(join20(gitdir, "objects/pack"));
|
|
15511
15511
|
list3 = list3.filter((x2) => x2.endsWith(".idx"));
|
|
15512
15512
|
for (const filename of list3) {
|
|
15513
15513
|
const indexFile = `${gitdir}/objects/pack/${filename}`;
|
|
@@ -15550,7 +15550,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15550
15550
|
async function expandOid({
|
|
15551
15551
|
fs: fs2,
|
|
15552
15552
|
dir,
|
|
15553
|
-
gitdir =
|
|
15553
|
+
gitdir = join20(dir, ".git"),
|
|
15554
15554
|
oid,
|
|
15555
15555
|
cache = {}
|
|
15556
15556
|
}) {
|
|
@@ -15571,7 +15571,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15571
15571
|
throw err2;
|
|
15572
15572
|
}
|
|
15573
15573
|
}
|
|
15574
|
-
async function expandRef({ fs: fs2, dir, gitdir =
|
|
15574
|
+
async function expandRef({ fs: fs2, dir, gitdir = join20(dir, ".git"), ref }) {
|
|
15575
15575
|
try {
|
|
15576
15576
|
assertParameter("fs", fs2);
|
|
15577
15577
|
assertParameter("gitdir", gitdir);
|
|
@@ -15862,7 +15862,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15862
15862
|
onAuthSuccess,
|
|
15863
15863
|
onAuthFailure,
|
|
15864
15864
|
dir,
|
|
15865
|
-
gitdir =
|
|
15865
|
+
gitdir = join20(dir, ".git"),
|
|
15866
15866
|
ref,
|
|
15867
15867
|
url: url3,
|
|
15868
15868
|
remote,
|
|
@@ -15920,7 +15920,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15920
15920
|
onAuthSuccess,
|
|
15921
15921
|
onAuthFailure,
|
|
15922
15922
|
dir,
|
|
15923
|
-
gitdir =
|
|
15923
|
+
gitdir = join20(dir, ".git"),
|
|
15924
15924
|
ref,
|
|
15925
15925
|
remote,
|
|
15926
15926
|
remoteRef,
|
|
@@ -15976,7 +15976,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15976
15976
|
async function findMergeBase({
|
|
15977
15977
|
fs: fs2,
|
|
15978
15978
|
dir,
|
|
15979
|
-
gitdir =
|
|
15979
|
+
gitdir = join20(dir, ".git"),
|
|
15980
15980
|
oids,
|
|
15981
15981
|
cache = {}
|
|
15982
15982
|
}) {
|
|
@@ -15998,10 +15998,10 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
15998
15998
|
}
|
|
15999
15999
|
}
|
|
16000
16000
|
async function _findRoot({ fs: fs2, filepath }) {
|
|
16001
|
-
if (await fs2.exists(
|
|
16001
|
+
if (await fs2.exists(join20(filepath, ".git"))) {
|
|
16002
16002
|
return filepath;
|
|
16003
16003
|
} else {
|
|
16004
|
-
const parent =
|
|
16004
|
+
const parent = dirname16(filepath);
|
|
16005
16005
|
if (parent === filepath) {
|
|
16006
16006
|
throw new NotFoundError(`git root for ${filepath}`);
|
|
16007
16007
|
}
|
|
@@ -16018,7 +16018,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16018
16018
|
throw err2;
|
|
16019
16019
|
}
|
|
16020
16020
|
}
|
|
16021
|
-
async function getConfig({ fs: fs2, dir, gitdir =
|
|
16021
|
+
async function getConfig({ fs: fs2, dir, gitdir = join20(dir, ".git"), path }) {
|
|
16022
16022
|
try {
|
|
16023
16023
|
assertParameter("fs", fs2);
|
|
16024
16024
|
assertParameter("gitdir", gitdir);
|
|
@@ -16042,7 +16042,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16042
16042
|
async function getConfigAll({
|
|
16043
16043
|
fs: fs2,
|
|
16044
16044
|
dir,
|
|
16045
|
-
gitdir =
|
|
16045
|
+
gitdir = join20(dir, ".git"),
|
|
16046
16046
|
path
|
|
16047
16047
|
}) {
|
|
16048
16048
|
try {
|
|
@@ -16231,7 +16231,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16231
16231
|
filepath
|
|
16232
16232
|
}) {
|
|
16233
16233
|
try {
|
|
16234
|
-
filepath =
|
|
16234
|
+
filepath = join20(dir, filepath);
|
|
16235
16235
|
const pack = await fs2.read(filepath);
|
|
16236
16236
|
const getExternalRefDelta = (oid) => _readObject({ fs: fs2, cache, gitdir, oid });
|
|
16237
16237
|
const idx = await GitPackIndex.fromPack({
|
|
@@ -16252,7 +16252,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16252
16252
|
fs: fs2,
|
|
16253
16253
|
onProgress,
|
|
16254
16254
|
dir,
|
|
16255
|
-
gitdir =
|
|
16255
|
+
gitdir = join20(dir, ".git"),
|
|
16256
16256
|
filepath,
|
|
16257
16257
|
cache = {}
|
|
16258
16258
|
}) {
|
|
@@ -16280,7 +16280,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16280
16280
|
fs: fs2,
|
|
16281
16281
|
bare = false,
|
|
16282
16282
|
dir,
|
|
16283
|
-
gitdir = bare ? dir :
|
|
16283
|
+
gitdir = bare ? dir : join20(dir, ".git"),
|
|
16284
16284
|
defaultBranch = "master"
|
|
16285
16285
|
}) {
|
|
16286
16286
|
try {
|
|
@@ -16354,7 +16354,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16354
16354
|
async function isDescendent({
|
|
16355
16355
|
fs: fs2,
|
|
16356
16356
|
dir,
|
|
16357
|
-
gitdir =
|
|
16357
|
+
gitdir = join20(dir, ".git"),
|
|
16358
16358
|
oid,
|
|
16359
16359
|
ancestor,
|
|
16360
16360
|
depth = -1,
|
|
@@ -16383,7 +16383,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16383
16383
|
async function isIgnored({
|
|
16384
16384
|
fs: fs2,
|
|
16385
16385
|
dir,
|
|
16386
|
-
gitdir =
|
|
16386
|
+
gitdir = join20(dir, ".git"),
|
|
16387
16387
|
filepath
|
|
16388
16388
|
}) {
|
|
16389
16389
|
try {
|
|
@@ -16407,7 +16407,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16407
16407
|
async function listBranches({
|
|
16408
16408
|
fs: fs2,
|
|
16409
16409
|
dir,
|
|
16410
|
-
gitdir =
|
|
16410
|
+
gitdir = join20(dir, ".git"),
|
|
16411
16411
|
remote
|
|
16412
16412
|
}) {
|
|
16413
16413
|
try {
|
|
@@ -16464,17 +16464,17 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16464
16464
|
gitdir,
|
|
16465
16465
|
oid: entry.oid,
|
|
16466
16466
|
filenames,
|
|
16467
|
-
prefix:
|
|
16467
|
+
prefix: join20(prefix, entry.path)
|
|
16468
16468
|
});
|
|
16469
16469
|
} else {
|
|
16470
|
-
filenames.push(
|
|
16470
|
+
filenames.push(join20(prefix, entry.path));
|
|
16471
16471
|
}
|
|
16472
16472
|
}
|
|
16473
16473
|
}
|
|
16474
16474
|
async function listFiles({
|
|
16475
16475
|
fs: fs2,
|
|
16476
16476
|
dir,
|
|
16477
|
-
gitdir =
|
|
16477
|
+
gitdir = join20(dir, ".git"),
|
|
16478
16478
|
ref,
|
|
16479
16479
|
cache = {}
|
|
16480
16480
|
}) {
|
|
@@ -16518,7 +16518,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16518
16518
|
async function listNotes({
|
|
16519
16519
|
fs: fs2,
|
|
16520
16520
|
dir,
|
|
16521
|
-
gitdir =
|
|
16521
|
+
gitdir = join20(dir, ".git"),
|
|
16522
16522
|
ref = "refs/notes/commits",
|
|
16523
16523
|
cache = {}
|
|
16524
16524
|
}) {
|
|
@@ -16542,7 +16542,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16542
16542
|
async function listRefs({
|
|
16543
16543
|
fs: fs2,
|
|
16544
16544
|
dir,
|
|
16545
|
-
gitdir =
|
|
16545
|
+
gitdir = join20(dir, ".git"),
|
|
16546
16546
|
filepath
|
|
16547
16547
|
}) {
|
|
16548
16548
|
try {
|
|
@@ -16567,7 +16567,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16567
16567
|
);
|
|
16568
16568
|
return remotes;
|
|
16569
16569
|
}
|
|
16570
|
-
async function listRemotes({ fs: fs2, dir, gitdir =
|
|
16570
|
+
async function listRemotes({ fs: fs2, dir, gitdir = join20(dir, ".git") }) {
|
|
16571
16571
|
try {
|
|
16572
16572
|
assertParameter("fs", fs2);
|
|
16573
16573
|
assertParameter("gitdir", gitdir);
|
|
@@ -16666,7 +16666,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16666
16666
|
throw err2;
|
|
16667
16667
|
}
|
|
16668
16668
|
}
|
|
16669
|
-
async function listTags({ fs: fs2, dir, gitdir =
|
|
16669
|
+
async function listTags({ fs: fs2, dir, gitdir = join20(dir, ".git") }) {
|
|
16670
16670
|
try {
|
|
16671
16671
|
assertParameter("fs", fs2);
|
|
16672
16672
|
assertParameter("gitdir", gitdir);
|
|
@@ -16719,7 +16719,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16719
16719
|
const walks = tree.entries().map(function(entry) {
|
|
16720
16720
|
let result;
|
|
16721
16721
|
if (entry.oid === fileId) {
|
|
16722
|
-
result =
|
|
16722
|
+
result = join20(parentPath, entry.path);
|
|
16723
16723
|
filepaths.push(result);
|
|
16724
16724
|
} else if (entry.type === "tree") {
|
|
16725
16725
|
result = _readObject({
|
|
@@ -16736,7 +16736,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16736
16736
|
fileId,
|
|
16737
16737
|
oid,
|
|
16738
16738
|
filepaths,
|
|
16739
|
-
parentPath:
|
|
16739
|
+
parentPath: join20(parentPath, entry.path)
|
|
16740
16740
|
});
|
|
16741
16741
|
});
|
|
16742
16742
|
}
|
|
@@ -16911,7 +16911,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16911
16911
|
async function log({
|
|
16912
16912
|
fs: fs2,
|
|
16913
16913
|
dir,
|
|
16914
|
-
gitdir =
|
|
16914
|
+
gitdir = join20(dir, ".git"),
|
|
16915
16915
|
filepath,
|
|
16916
16916
|
ref = "HEAD",
|
|
16917
16917
|
depth,
|
|
@@ -16949,7 +16949,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
16949
16949
|
fs: _fs,
|
|
16950
16950
|
onSign,
|
|
16951
16951
|
dir,
|
|
16952
|
-
gitdir =
|
|
16952
|
+
gitdir = join20(dir, ".git"),
|
|
16953
16953
|
ours,
|
|
16954
16954
|
theirs,
|
|
16955
16955
|
fastForward: fastForward2 = true,
|
|
@@ -17026,7 +17026,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17026
17026
|
fs: fs2,
|
|
17027
17027
|
cache,
|
|
17028
17028
|
dir,
|
|
17029
|
-
gitdir =
|
|
17029
|
+
gitdir = join20(dir, ".git"),
|
|
17030
17030
|
oids
|
|
17031
17031
|
}) {
|
|
17032
17032
|
const hash2 = new Hash();
|
|
@@ -17069,7 +17069,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17069
17069
|
const packfileSha = packfile.slice(-20).toString("hex");
|
|
17070
17070
|
const filename = `pack-${packfileSha}.pack`;
|
|
17071
17071
|
if (write) {
|
|
17072
|
-
await fs2.write(
|
|
17072
|
+
await fs2.write(join20(gitdir, `objects/pack/${filename}`), packfile);
|
|
17073
17073
|
return { filename };
|
|
17074
17074
|
}
|
|
17075
17075
|
return {
|
|
@@ -17080,7 +17080,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17080
17080
|
async function packObjects({
|
|
17081
17081
|
fs: fs2,
|
|
17082
17082
|
dir,
|
|
17083
|
-
gitdir =
|
|
17083
|
+
gitdir = join20(dir, ".git"),
|
|
17084
17084
|
oids,
|
|
17085
17085
|
write = false,
|
|
17086
17086
|
cache = {}
|
|
@@ -17112,7 +17112,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17112
17112
|
onAuthSuccess,
|
|
17113
17113
|
onAuthFailure,
|
|
17114
17114
|
dir,
|
|
17115
|
-
gitdir =
|
|
17115
|
+
gitdir = join20(dir, ".git"),
|
|
17116
17116
|
ref,
|
|
17117
17117
|
url: url3,
|
|
17118
17118
|
remote,
|
|
@@ -17182,7 +17182,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17182
17182
|
fs: fs2,
|
|
17183
17183
|
cache,
|
|
17184
17184
|
dir,
|
|
17185
|
-
gitdir =
|
|
17185
|
+
gitdir = join20(dir, ".git"),
|
|
17186
17186
|
start,
|
|
17187
17187
|
finish
|
|
17188
17188
|
}) {
|
|
@@ -17230,7 +17230,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17230
17230
|
fs: fs2,
|
|
17231
17231
|
cache,
|
|
17232
17232
|
dir,
|
|
17233
|
-
gitdir =
|
|
17233
|
+
gitdir = join20(dir, ".git"),
|
|
17234
17234
|
oids
|
|
17235
17235
|
}) {
|
|
17236
17236
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -17533,7 +17533,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17533
17533
|
onAuthFailure,
|
|
17534
17534
|
onPrePush,
|
|
17535
17535
|
dir,
|
|
17536
|
-
gitdir =
|
|
17536
|
+
gitdir = join20(dir, ".git"),
|
|
17537
17537
|
ref,
|
|
17538
17538
|
remoteRef,
|
|
17539
17539
|
remote = "origin",
|
|
@@ -17609,7 +17609,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17609
17609
|
async function readBlob({
|
|
17610
17610
|
fs: fs2,
|
|
17611
17611
|
dir,
|
|
17612
|
-
gitdir =
|
|
17612
|
+
gitdir = join20(dir, ".git"),
|
|
17613
17613
|
oid,
|
|
17614
17614
|
filepath,
|
|
17615
17615
|
cache = {}
|
|
@@ -17635,7 +17635,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17635
17635
|
async function readCommit({
|
|
17636
17636
|
fs: fs2,
|
|
17637
17637
|
dir,
|
|
17638
|
-
gitdir =
|
|
17638
|
+
gitdir = join20(dir, ".git"),
|
|
17639
17639
|
oid,
|
|
17640
17640
|
cache = {}
|
|
17641
17641
|
}) {
|
|
@@ -17676,7 +17676,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17676
17676
|
async function readNote({
|
|
17677
17677
|
fs: fs2,
|
|
17678
17678
|
dir,
|
|
17679
|
-
gitdir =
|
|
17679
|
+
gitdir = join20(dir, ".git"),
|
|
17680
17680
|
ref = "refs/notes/commits",
|
|
17681
17681
|
oid,
|
|
17682
17682
|
cache = {}
|
|
@@ -17703,7 +17703,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17703
17703
|
async function readObject({
|
|
17704
17704
|
fs: _fs,
|
|
17705
17705
|
dir,
|
|
17706
|
-
gitdir =
|
|
17706
|
+
gitdir = join20(dir, ".git"),
|
|
17707
17707
|
oid,
|
|
17708
17708
|
format = "parsed",
|
|
17709
17709
|
filepath = void 0,
|
|
@@ -17792,7 +17792,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17792
17792
|
async function readTag({
|
|
17793
17793
|
fs: fs2,
|
|
17794
17794
|
dir,
|
|
17795
|
-
gitdir =
|
|
17795
|
+
gitdir = join20(dir, ".git"),
|
|
17796
17796
|
oid,
|
|
17797
17797
|
cache = {}
|
|
17798
17798
|
}) {
|
|
@@ -17816,7 +17816,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17816
17816
|
async function readTree({
|
|
17817
17817
|
fs: fs2,
|
|
17818
17818
|
dir,
|
|
17819
|
-
gitdir =
|
|
17819
|
+
gitdir = join20(dir, ".git"),
|
|
17820
17820
|
oid,
|
|
17821
17821
|
filepath = void 0,
|
|
17822
17822
|
cache = {}
|
|
@@ -17842,7 +17842,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17842
17842
|
async function remove2({
|
|
17843
17843
|
fs: _fs,
|
|
17844
17844
|
dir,
|
|
17845
|
-
gitdir =
|
|
17845
|
+
gitdir = join20(dir, ".git"),
|
|
17846
17846
|
filepath,
|
|
17847
17847
|
cache = {}
|
|
17848
17848
|
}) {
|
|
@@ -17915,7 +17915,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
17915
17915
|
fs: _fs,
|
|
17916
17916
|
onSign,
|
|
17917
17917
|
dir,
|
|
17918
|
-
gitdir =
|
|
17918
|
+
gitdir = join20(dir, ".git"),
|
|
17919
17919
|
ref = "refs/notes/commits",
|
|
17920
17920
|
oid,
|
|
17921
17921
|
author: _author,
|
|
@@ -18003,7 +18003,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18003
18003
|
async function renameBranch({
|
|
18004
18004
|
fs: fs2,
|
|
18005
18005
|
dir,
|
|
18006
|
-
gitdir =
|
|
18006
|
+
gitdir = join20(dir, ".git"),
|
|
18007
18007
|
ref,
|
|
18008
18008
|
oldref,
|
|
18009
18009
|
checkout: checkout2 = false
|
|
@@ -18033,7 +18033,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18033
18033
|
async function resetIndex({
|
|
18034
18034
|
fs: _fs,
|
|
18035
18035
|
dir,
|
|
18036
|
-
gitdir =
|
|
18036
|
+
gitdir = join20(dir, ".git"),
|
|
18037
18037
|
filepath,
|
|
18038
18038
|
ref,
|
|
18039
18039
|
cache = {}
|
|
@@ -18080,7 +18080,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18080
18080
|
gid: 0,
|
|
18081
18081
|
size: 0
|
|
18082
18082
|
};
|
|
18083
|
-
const object2 = dir && await fs2.read(
|
|
18083
|
+
const object2 = dir && await fs2.read(join20(dir, filepath));
|
|
18084
18084
|
if (object2) {
|
|
18085
18085
|
workdirOid = await hashObject$1({
|
|
18086
18086
|
gitdir: updatedGitdir,
|
|
@@ -18088,7 +18088,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18088
18088
|
object: object2
|
|
18089
18089
|
});
|
|
18090
18090
|
if (oid === workdirOid) {
|
|
18091
|
-
stats = await fs2.lstat(
|
|
18091
|
+
stats = await fs2.lstat(join20(dir, filepath));
|
|
18092
18092
|
}
|
|
18093
18093
|
}
|
|
18094
18094
|
await GitIndexManager.acquire(
|
|
@@ -18108,7 +18108,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18108
18108
|
async function resolveRef2({
|
|
18109
18109
|
fs: fs2,
|
|
18110
18110
|
dir,
|
|
18111
|
-
gitdir =
|
|
18111
|
+
gitdir = join20(dir, ".git"),
|
|
18112
18112
|
ref,
|
|
18113
18113
|
depth
|
|
18114
18114
|
}) {
|
|
@@ -18133,7 +18133,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18133
18133
|
async function setConfig({
|
|
18134
18134
|
fs: _fs,
|
|
18135
18135
|
dir,
|
|
18136
|
-
gitdir =
|
|
18136
|
+
gitdir = join20(dir, ".git"),
|
|
18137
18137
|
path,
|
|
18138
18138
|
value,
|
|
18139
18139
|
append = false
|
|
@@ -18201,7 +18201,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18201
18201
|
* @param {string} args.dir - The working directory.
|
|
18202
18202
|
* @param {string}[args.gitdir=join(dir, '.git')] - [required] The [git directory](dir-vs-gitdir.md) path
|
|
18203
18203
|
*/
|
|
18204
|
-
constructor({ fs: fs2, dir, gitdir =
|
|
18204
|
+
constructor({ fs: fs2, dir, gitdir = join20(dir, ".git") }) {
|
|
18205
18205
|
Object.assign(this, {
|
|
18206
18206
|
fs: fs2,
|
|
18207
18207
|
dir,
|
|
@@ -18231,7 +18231,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18231
18231
|
* @returns {string} - The file path for the stash reference.
|
|
18232
18232
|
*/
|
|
18233
18233
|
get refStashPath() {
|
|
18234
|
-
return
|
|
18234
|
+
return join20(this.gitdir, _GitStashManager.refStash);
|
|
18235
18235
|
}
|
|
18236
18236
|
/**
|
|
18237
18237
|
* Gets the file path for the stash reflogs.
|
|
@@ -18239,7 +18239,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18239
18239
|
* @returns {string} - The file path for the stash reflogs.
|
|
18240
18240
|
*/
|
|
18241
18241
|
get refLogsStashPath() {
|
|
18242
|
-
return
|
|
18242
|
+
return join20(this.gitdir, _GitStashManager.refLogsStash);
|
|
18243
18243
|
}
|
|
18244
18244
|
/**
|
|
18245
18245
|
* Retrieves the author information for the stash.
|
|
@@ -18545,7 +18545,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18545
18545
|
async function stash({
|
|
18546
18546
|
fs: fs2,
|
|
18547
18547
|
dir,
|
|
18548
|
-
gitdir =
|
|
18548
|
+
gitdir = join20(dir, ".git"),
|
|
18549
18549
|
op = "push",
|
|
18550
18550
|
message = "",
|
|
18551
18551
|
refIdx = 0
|
|
@@ -18568,7 +18568,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18568
18568
|
const _fs = new FileSystem(fs2);
|
|
18569
18569
|
const updatedGitdir = await discoverGitdir({ fsp: _fs, dotgit: gitdir });
|
|
18570
18570
|
const folders = ["refs", "logs", "logs/refs"];
|
|
18571
|
-
folders.map((f) =>
|
|
18571
|
+
folders.map((f) => join20(updatedGitdir, f)).forEach(async (folder) => {
|
|
18572
18572
|
if (!await _fs.exists(folder)) {
|
|
18573
18573
|
await _fs.mkdir(folder);
|
|
18574
18574
|
}
|
|
@@ -18598,7 +18598,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18598
18598
|
async function status({
|
|
18599
18599
|
fs: _fs,
|
|
18600
18600
|
dir,
|
|
18601
|
-
gitdir =
|
|
18601
|
+
gitdir = join20(dir, ".git"),
|
|
18602
18602
|
filepath,
|
|
18603
18603
|
cache = {},
|
|
18604
18604
|
refresh: refresh2 = true
|
|
@@ -18637,7 +18637,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18637
18637
|
return "ignored";
|
|
18638
18638
|
}
|
|
18639
18639
|
}
|
|
18640
|
-
const stats = await fs2.lstat(
|
|
18640
|
+
const stats = await fs2.lstat(join20(dir, filepath));
|
|
18641
18641
|
const H = treeOid !== null;
|
|
18642
18642
|
const I = indexEntry !== null;
|
|
18643
18643
|
const W = stats !== null;
|
|
@@ -18647,7 +18647,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18647
18647
|
} else {
|
|
18648
18648
|
const config2 = await GitConfigManager.get({ fs: fs2, gitdir: updatedGitdir });
|
|
18649
18649
|
const autocrlf = await config2.get("core.autocrlf");
|
|
18650
|
-
const object2 = await fs2.read(
|
|
18650
|
+
const object2 = await fs2.read(join20(dir, filepath), { autocrlf });
|
|
18651
18651
|
const workdirOid = await hashObject$1({
|
|
18652
18652
|
gitdir: updatedGitdir,
|
|
18653
18653
|
type: "blob",
|
|
@@ -18696,9 +18696,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18696
18696
|
}
|
|
18697
18697
|
async function getOidAtPath({ fs: fs2, cache, gitdir: updatedGitdir, tree, path }) {
|
|
18698
18698
|
if (typeof path === "string") path = path.split("/");
|
|
18699
|
-
const
|
|
18699
|
+
const dirname17 = path.shift();
|
|
18700
18700
|
for (const entry of tree) {
|
|
18701
|
-
if (entry.path ===
|
|
18701
|
+
if (entry.path === dirname17) {
|
|
18702
18702
|
if (path.length === 0) {
|
|
18703
18703
|
return entry.oid;
|
|
18704
18704
|
}
|
|
@@ -18738,7 +18738,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18738
18738
|
async function statusMatrix({
|
|
18739
18739
|
fs: _fs,
|
|
18740
18740
|
dir,
|
|
18741
|
-
gitdir =
|
|
18741
|
+
gitdir = join20(dir, ".git"),
|
|
18742
18742
|
ref = "HEAD",
|
|
18743
18743
|
filepaths = ["."],
|
|
18744
18744
|
filter,
|
|
@@ -18811,7 +18811,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18811
18811
|
async function tag({
|
|
18812
18812
|
fs: _fs,
|
|
18813
18813
|
dir,
|
|
18814
|
-
gitdir =
|
|
18814
|
+
gitdir = join20(dir, ".git"),
|
|
18815
18815
|
ref,
|
|
18816
18816
|
object: object2,
|
|
18817
18817
|
force = false
|
|
@@ -18843,7 +18843,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18843
18843
|
async function updateIndex$1({
|
|
18844
18844
|
fs: _fs,
|
|
18845
18845
|
dir,
|
|
18846
|
-
gitdir =
|
|
18846
|
+
gitdir = join20(dir, ".git"),
|
|
18847
18847
|
cache = {},
|
|
18848
18848
|
filepath,
|
|
18849
18849
|
oid,
|
|
@@ -18863,7 +18863,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18863
18863
|
{ fs: fs2, gitdir: updatedGitdir, cache },
|
|
18864
18864
|
async function(index3) {
|
|
18865
18865
|
if (!force) {
|
|
18866
|
-
const fileStats2 = await fs2.lstat(
|
|
18866
|
+
const fileStats2 = await fs2.lstat(join20(dir, filepath));
|
|
18867
18867
|
if (fileStats2) {
|
|
18868
18868
|
if (fileStats2.isDirectory()) {
|
|
18869
18869
|
throw new InvalidFilepathError("directory");
|
|
@@ -18881,7 +18881,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18881
18881
|
}
|
|
18882
18882
|
let fileStats;
|
|
18883
18883
|
if (!oid) {
|
|
18884
|
-
fileStats = await fs2.lstat(
|
|
18884
|
+
fileStats = await fs2.lstat(join20(dir, filepath));
|
|
18885
18885
|
if (!fileStats) {
|
|
18886
18886
|
throw new NotFoundError(
|
|
18887
18887
|
`file at "${filepath}" on disk and "remove" not set`
|
|
@@ -18902,7 +18902,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18902
18902
|
let stats;
|
|
18903
18903
|
if (!oid) {
|
|
18904
18904
|
stats = fileStats;
|
|
18905
|
-
const object2 = stats.isSymbolicLink() ? await fs2.readlink(
|
|
18905
|
+
const object2 = stats.isSymbolicLink() ? await fs2.readlink(join20(dir, filepath)) : await fs2.read(join20(dir, filepath));
|
|
18906
18906
|
oid = await _writeObject({
|
|
18907
18907
|
fs: fs2,
|
|
18908
18908
|
gitdir: updatedGitdir,
|
|
@@ -18946,7 +18946,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18946
18946
|
async function walk({
|
|
18947
18947
|
fs: fs2,
|
|
18948
18948
|
dir,
|
|
18949
|
-
gitdir =
|
|
18949
|
+
gitdir = join20(dir, ".git"),
|
|
18950
18950
|
trees,
|
|
18951
18951
|
map: map2,
|
|
18952
18952
|
reduce,
|
|
@@ -18974,7 +18974,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18974
18974
|
throw err2;
|
|
18975
18975
|
}
|
|
18976
18976
|
}
|
|
18977
|
-
async function writeBlob({ fs: fs2, dir, gitdir =
|
|
18977
|
+
async function writeBlob({ fs: fs2, dir, gitdir = join20(dir, ".git"), blob: blob2 }) {
|
|
18978
18978
|
try {
|
|
18979
18979
|
assertParameter("fs", fs2);
|
|
18980
18980
|
assertParameter("gitdir", gitdir);
|
|
@@ -18996,7 +18996,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
18996
18996
|
async function writeCommit({
|
|
18997
18997
|
fs: fs2,
|
|
18998
18998
|
dir,
|
|
18999
|
-
gitdir =
|
|
18999
|
+
gitdir = join20(dir, ".git"),
|
|
19000
19000
|
commit: commit2
|
|
19001
19001
|
}) {
|
|
19002
19002
|
try {
|
|
@@ -19018,7 +19018,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
19018
19018
|
async function writeObject({
|
|
19019
19019
|
fs: _fs,
|
|
19020
19020
|
dir,
|
|
19021
|
-
gitdir =
|
|
19021
|
+
gitdir = join20(dir, ".git"),
|
|
19022
19022
|
type,
|
|
19023
19023
|
object: object2,
|
|
19024
19024
|
format = "parsed",
|
|
@@ -19064,7 +19064,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
19064
19064
|
async function writeRef({
|
|
19065
19065
|
fs: _fs,
|
|
19066
19066
|
dir,
|
|
19067
|
-
gitdir =
|
|
19067
|
+
gitdir = join20(dir, ".git"),
|
|
19068
19068
|
ref,
|
|
19069
19069
|
value,
|
|
19070
19070
|
force = false,
|
|
@@ -19119,7 +19119,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
19119
19119
|
});
|
|
19120
19120
|
return oid;
|
|
19121
19121
|
}
|
|
19122
|
-
async function writeTag({ fs: fs2, dir, gitdir =
|
|
19122
|
+
async function writeTag({ fs: fs2, dir, gitdir = join20(dir, ".git"), tag: tag2 }) {
|
|
19123
19123
|
try {
|
|
19124
19124
|
assertParameter("fs", fs2);
|
|
19125
19125
|
assertParameter("gitdir", gitdir);
|
|
@@ -19136,7 +19136,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
19136
19136
|
throw err2;
|
|
19137
19137
|
}
|
|
19138
19138
|
}
|
|
19139
|
-
async function writeTree2({ fs: fs2, dir, gitdir =
|
|
19139
|
+
async function writeTree2({ fs: fs2, dir, gitdir = join20(dir, ".git"), tree }) {
|
|
19140
19140
|
try {
|
|
19141
19141
|
assertParameter("fs", fs2);
|
|
19142
19142
|
assertParameter("gitdir", gitdir);
|
|
@@ -19761,7 +19761,7 @@ var require_ignore2 = __commonJS({
|
|
|
19761
19761
|
// cli/package.json
|
|
19762
19762
|
var package_default = {
|
|
19763
19763
|
name: "@docyrus/animaguru",
|
|
19764
|
-
version: "0.
|
|
19764
|
+
version: "0.28.0",
|
|
19765
19765
|
description: "Agent-friendly AnimaGuru CLI built with CrustJS",
|
|
19766
19766
|
type: "module",
|
|
19767
19767
|
bin: {
|
|
@@ -19978,14 +19978,14 @@ function normalizeFlag(name2, def) {
|
|
|
19978
19978
|
name: name2,
|
|
19979
19979
|
reason: "empty-env"
|
|
19980
19980
|
});
|
|
19981
|
-
for (const [field,
|
|
19982
|
-
if (
|
|
19981
|
+
for (const [field, delimiter3] of [["delimiter", def.delimiter], ["env.delimiter", def.env?.delimiter]]) {
|
|
19982
|
+
if (delimiter3 === void 0) continue;
|
|
19983
19983
|
if (!def.multiple) throw new CrustError("DEFINITION", `Flag "${name2}" ${field} requires multiple: true`, {
|
|
19984
19984
|
subject: "flag",
|
|
19985
19985
|
name: name2,
|
|
19986
19986
|
reason: "delimiter-without-multiple"
|
|
19987
19987
|
});
|
|
19988
|
-
if (
|
|
19988
|
+
if (delimiter3 === "") throw new CrustError("DEFINITION", `Flag "${name2}" ${field} must be non-empty`, {
|
|
19989
19989
|
subject: "flag",
|
|
19990
19990
|
name: name2,
|
|
19991
19991
|
reason: "empty-delimiter"
|
|
@@ -20457,9 +20457,9 @@ function resolveAliases(tokens, spellings) {
|
|
|
20457
20457
|
}
|
|
20458
20458
|
return canonical;
|
|
20459
20459
|
}
|
|
20460
|
-
function splitOccurrences(values,
|
|
20461
|
-
if (
|
|
20462
|
-
return values.flatMap((value) => value.split(
|
|
20460
|
+
function splitOccurrences(values, delimiter3) {
|
|
20461
|
+
if (delimiter3 === void 0) return [...values];
|
|
20462
|
+
return values.flatMap((value) => value.split(delimiter3)).filter((value) => value !== "");
|
|
20463
20463
|
}
|
|
20464
20464
|
function envFlagValue(name2, def, raw) {
|
|
20465
20465
|
const occurrences = def.multiple ? splitOccurrences([raw], def.env?.delimiter) : [raw];
|
|
@@ -24295,8 +24295,8 @@ var version = defineExtension(VERSION).factory((extension, value, options = {})
|
|
|
24295
24295
|
|
|
24296
24296
|
// cli/src/commands.ts
|
|
24297
24297
|
import { spawn as spawn3 } from "node:child_process";
|
|
24298
|
-
import { mkdir as
|
|
24299
|
-
import { dirname as
|
|
24298
|
+
import { mkdir as mkdir16, readFile as readFile20, writeFile as writeFile16 } from "node:fs/promises";
|
|
24299
|
+
import { dirname as dirname15, resolve as resolve18 } from "node:path";
|
|
24300
24300
|
import { setTimeout as delay6 } from "node:timers/promises";
|
|
24301
24301
|
|
|
24302
24302
|
// node_modules/fflate/esm/index.mjs
|
|
@@ -27487,8 +27487,8 @@ function emoji2() {
|
|
|
27487
27487
|
}
|
|
27488
27488
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
27489
27489
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
27490
|
-
var mac = (
|
|
27491
|
-
const escapedDelim = escapeRegex(
|
|
27490
|
+
var mac = (delimiter3) => {
|
|
27491
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
27492
27492
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
27493
27493
|
};
|
|
27494
27494
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -30516,7 +30516,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
30516
30516
|
var NONE = 0;
|
|
30517
30517
|
var ASSUMED = 1;
|
|
30518
30518
|
var PROVEN = 2;
|
|
30519
|
-
function isRecursive(inst, stack,
|
|
30519
|
+
function isRecursive(inst, stack, resolve19) {
|
|
30520
30520
|
const cached2 = recursive.get(inst);
|
|
30521
30521
|
if (cached2 !== void 0)
|
|
30522
30522
|
return cached2 ? PROVEN : NONE;
|
|
@@ -30526,7 +30526,7 @@ function isRecursive(inst, stack, resolve18) {
|
|
|
30526
30526
|
let result = NONE;
|
|
30527
30527
|
const check2 = (child) => {
|
|
30528
30528
|
if (result !== PROVEN && child?._zod) {
|
|
30529
|
-
const answer = isRecursive(child, stack,
|
|
30529
|
+
const answer = isRecursive(child, stack, resolve19);
|
|
30530
30530
|
if (answer > result)
|
|
30531
30531
|
result = answer;
|
|
30532
30532
|
}
|
|
@@ -30537,7 +30537,7 @@ function isRecursive(inst, stack, resolve18) {
|
|
|
30537
30537
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
30538
30538
|
if (spread && !desc.enumerable)
|
|
30539
30539
|
continue;
|
|
30540
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
30540
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve19) : NONE;
|
|
30541
30541
|
if (child > answer)
|
|
30542
30542
|
answer = child;
|
|
30543
30543
|
}
|
|
@@ -30601,7 +30601,7 @@ function isRecursive(inst, stack, resolve18) {
|
|
|
30601
30601
|
break;
|
|
30602
30602
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
30603
30603
|
case "lazy": {
|
|
30604
|
-
const inner = def._cachedInner ?? (
|
|
30604
|
+
const inner = def._cachedInner ?? (resolve19 ? inst._zod.innerType : void 0);
|
|
30605
30605
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
30606
30606
|
break;
|
|
30607
30607
|
}
|
|
@@ -45293,10 +45293,62 @@ async function initializeSkill(directory = process.cwd()) {
|
|
|
45293
45293
|
return { path, created };
|
|
45294
45294
|
}
|
|
45295
45295
|
|
|
45296
|
+
// cli/src/skills.ts
|
|
45297
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
45298
|
+
import { access, mkdir as mkdir6, readFile as readFile4, readdir as readdir2, stat } from "node:fs/promises";
|
|
45299
|
+
import { delimiter, dirname as dirname5, join as join6, resolve as resolve5 } from "node:path";
|
|
45300
|
+
var SKILLS_CLI = "skills@1.7.4";
|
|
45301
|
+
var SKILL_AGENTS = { "claude-code": ".claude/skills", codex: ".agents/skills" };
|
|
45302
|
+
var skillsSource = (server) => `${new URL(server).origin}/cli/skills`;
|
|
45303
|
+
async function skillsInstallCommand(source, platform = process.platform, execPath = process.execPath) {
|
|
45304
|
+
const args = ["-y", SKILLS_CLI, "add", source, "--skill", "*", ...Object.keys(SKILL_AGENTS).flatMap((agent) => ["--agent", agent]), "--copy", "--yes"];
|
|
45305
|
+
const adjacentNpx = resolve5(dirname5(execPath), "../lib/node_modules/npm/bin/npx-cli.js");
|
|
45306
|
+
try {
|
|
45307
|
+
await access(adjacentNpx);
|
|
45308
|
+
return { command: execPath, args: [adjacentNpx, ...args], shell: false };
|
|
45309
|
+
} catch {
|
|
45310
|
+
return { command: platform === "win32" ? "npx.cmd" : "npx", args, shell: platform === "win32" };
|
|
45311
|
+
}
|
|
45312
|
+
}
|
|
45313
|
+
async function lockedSkills(directory, source) {
|
|
45314
|
+
try {
|
|
45315
|
+
const lock = JSON.parse(await readFile4(join6(directory, "skills-lock.json"), "utf8"));
|
|
45316
|
+
return Object.entries(lock.skills ?? {}).filter(([, skill]) => skill.sourceUrl === source).map(([name2]) => name2).sort();
|
|
45317
|
+
} catch {
|
|
45318
|
+
return [];
|
|
45319
|
+
}
|
|
45320
|
+
}
|
|
45321
|
+
async function installSkills(options) {
|
|
45322
|
+
const directory = resolve5(options.dir ?? ".");
|
|
45323
|
+
await mkdir6(directory, { recursive: true });
|
|
45324
|
+
if (!(await stat(directory)).isDirectory()) throw new Error(`${directory} is not a folder.`);
|
|
45325
|
+
const source = skillsSource(options.url);
|
|
45326
|
+
const { command, args, shell } = await skillsInstallCommand(source);
|
|
45327
|
+
options.log?.(`Installing AnimaGuru skills from ${source} into ${directory}\u2026`);
|
|
45328
|
+
await new Promise((done, reject) => {
|
|
45329
|
+
const child = (options.spawn ?? nodeSpawn)(command, args, {
|
|
45330
|
+
cwd: directory,
|
|
45331
|
+
signal: options.signal,
|
|
45332
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45333
|
+
shell,
|
|
45334
|
+
// The skills CLI reports installs to skills.sh unless told not to.
|
|
45335
|
+
env: { ...process.env, DISABLE_TELEMETRY: "1", DO_NOT_TRACK: "1", PATH: `${dirname5(process.execPath)}${delimiter}${process.env.PATH ?? ""}` }
|
|
45336
|
+
});
|
|
45337
|
+
child.stdout?.on("data", (chunk) => options.log?.(chunk.toString().trimEnd()));
|
|
45338
|
+
child.stderr?.on("data", (chunk) => options.log?.(chunk.toString().trimEnd()));
|
|
45339
|
+
child.once("error", (error62) => reject(error62.code === "ENOENT" ? new Error("Installing skills needs npx, which comes with npm and Node.js 24. Install Node.js, or run the AnimaGuru installer again.") : error62));
|
|
45340
|
+
child.once("close", (code) => code === 0 ? done() : reject(new Error(`npx ${SKILLS_CLI} add exited with code ${code}; see its output above.`)));
|
|
45341
|
+
});
|
|
45342
|
+
const installed = await lockedSkills(directory, source);
|
|
45343
|
+
const folders = await Promise.all(Object.values(SKILL_AGENTS).map(async (folder) => (await readdir2(join6(directory, folder)).catch(() => [])).length));
|
|
45344
|
+
if (!installed.length || folders.some((count) => count === 0)) throw new Error("The skills CLI finished without installing AnimaGuru skills; see its output above.");
|
|
45345
|
+
return { directory, source, skills: installed.length, installed, agents: SKILL_AGENTS, lockfile: join6(directory, "skills-lock.json"), update: "npx skills update --project --yes" };
|
|
45346
|
+
}
|
|
45347
|
+
|
|
45296
45348
|
// cli/src/create.ts
|
|
45297
45349
|
import { spawn } from "node:child_process";
|
|
45298
|
-
import { cp, mkdir as
|
|
45299
|
-
import { basename as basename2, dirname as
|
|
45350
|
+
import { cp, mkdir as mkdir7, readFile as readFile5, readdir as readdir3, access as access2, writeFile as writeFile6, rename as rename3 } from "node:fs/promises";
|
|
45351
|
+
import { basename as basename2, dirname as dirname6, delimiter as delimiter2, join as join7, resolve as resolve6 } from "node:path";
|
|
45300
45352
|
import { fileURLToPath } from "node:url";
|
|
45301
45353
|
|
|
45302
45354
|
// shared/locales/en/animation-styles.json
|
|
@@ -46275,6 +46327,74 @@ var animation_styles_default = {
|
|
|
46275
46327
|
previewCaption: "One champagne line draws a sun on the horizon, three arches and a woman's profile without lifting, closes a ring that fills with gold from the point where it met, then pulls back to the wordmark. Invented brand, drawn entirely in code.",
|
|
46276
46328
|
family: "graphic",
|
|
46277
46329
|
example: true
|
|
46330
|
+
},
|
|
46331
|
+
"product-turntable-3d": {
|
|
46332
|
+
name: "3D Product Turntable",
|
|
46333
|
+
description: "A real 3D product turns on a studio set while the camera orbits and pushes in, studio light slides across its materials and callouts stay pinned to its parts.",
|
|
46334
|
+
materials: [
|
|
46335
|
+
"Generated PBR product model",
|
|
46336
|
+
"Studio HDR reflections",
|
|
46337
|
+
"Shallow depth of field"
|
|
46338
|
+
],
|
|
46339
|
+
motion: [
|
|
46340
|
+
"Turntable orbit and push-in",
|
|
46341
|
+
"Rack focus between details",
|
|
46342
|
+
"Callouts that track parts"
|
|
46343
|
+
],
|
|
46344
|
+
previewCaption: "Generated headphones turn on a stone plinth as the camera pulls back from a macro of the brushed yoke, focus racking from part to part under pinned callouts, ending on a lockup for an invented brand. Model generated with Tripo H3.1, rendered in three.js.",
|
|
46345
|
+
family: "3d",
|
|
46346
|
+
example: true
|
|
46347
|
+
},
|
|
46348
|
+
"character-stage-3d": {
|
|
46349
|
+
name: "3D Character Stage",
|
|
46350
|
+
description: "A rigged 3D character walks, turns and gestures in front of a painted 2D backdrop, casting real shadows onto the painting while captions carry the story.",
|
|
46351
|
+
materials: [
|
|
46352
|
+
"Rigged character model",
|
|
46353
|
+
"Painted 2D backdrop",
|
|
46354
|
+
"Shadows cast onto the painting"
|
|
46355
|
+
],
|
|
46356
|
+
motion: [
|
|
46357
|
+
"Walk cycles at true speed",
|
|
46358
|
+
"Crossfaded gestures",
|
|
46359
|
+
"A camera that follows the character"
|
|
46360
|
+
],
|
|
46361
|
+
previewCaption: "A generated, auto-rigged baker walks across a painted square, turns to camera, waves and explains, his shadow falling over the painting. Character made with Tripo H3.1 and Meshy's auto-rig, rendered in three.js.",
|
|
46362
|
+
family: "3d",
|
|
46363
|
+
example: true
|
|
46364
|
+
},
|
|
46365
|
+
"toy-diorama-3d": {
|
|
46366
|
+
name: "3D Toy Diorama",
|
|
46367
|
+
description: "A miniature 3D world on a tabletop, seen through tilt-shift focus as a free camera glides over tiny props and characters going about their day.",
|
|
46368
|
+
materials: [
|
|
46369
|
+
"Toy-scale models",
|
|
46370
|
+
"Tilt-shift depth of field",
|
|
46371
|
+
"Warm tabletop light"
|
|
46372
|
+
],
|
|
46373
|
+
motion: [
|
|
46374
|
+
"Free camera glides",
|
|
46375
|
+
"Little cars and figures on loops",
|
|
46376
|
+
"Focus pulled through the scene"
|
|
46377
|
+
],
|
|
46378
|
+
previewCaption: "A camera glides over a toy harbour town as little cars and boats run their loops, everything sharp only in a thin band of focus. Props generated with Tripo H3.1, rendered in three.js.",
|
|
46379
|
+
family: "3d",
|
|
46380
|
+
example: true
|
|
46381
|
+
},
|
|
46382
|
+
"exploded-teardown-3d": {
|
|
46383
|
+
name: "3D Exploded Teardown",
|
|
46384
|
+
description: "A 3D product orbits and comes apart along its assembly axes, each part followed by a leader label that stays with it through the turn.",
|
|
46385
|
+
materials: [
|
|
46386
|
+
"Part-by-part 3D model",
|
|
46387
|
+
"Leader labels and callouts",
|
|
46388
|
+
"Clean studio grey"
|
|
46389
|
+
],
|
|
46390
|
+
motion: [
|
|
46391
|
+
"Orbit while the parts separate",
|
|
46392
|
+
"Parts sliding along their axes",
|
|
46393
|
+
"Labels that follow each part"
|
|
46394
|
+
],
|
|
46395
|
+
previewCaption: "An invented handheld console comes apart along its assembly axes as the camera orbits, every part keeping its label. Modelled and rendered in code.",
|
|
46396
|
+
family: "3d",
|
|
46397
|
+
example: true
|
|
46278
46398
|
}
|
|
46279
46399
|
},
|
|
46280
46400
|
browseStyles: "Browse animation styles",
|
|
@@ -46290,7 +46410,8 @@ var animation_styles_default = {
|
|
|
46290
46410
|
material: "Materials & depth",
|
|
46291
46411
|
cinematic: "Cinema & media",
|
|
46292
46412
|
evidence: "Evidence & data",
|
|
46293
|
-
documentary: "Documentary & broadcast"
|
|
46413
|
+
documentary: "Documentary & broadcast",
|
|
46414
|
+
"3d": "3D scenes"
|
|
46294
46415
|
},
|
|
46295
46416
|
searchLabel: "Search visual styles",
|
|
46296
46417
|
searchPlaceholder: "Try paper, product, typography\u2026",
|
|
@@ -46423,7 +46544,11 @@ var VIDEO_STYLE_IDS = [
|
|
|
46423
46544
|
"synthwave-y2k",
|
|
46424
46545
|
"sticker-explainer",
|
|
46425
46546
|
"variety-captions",
|
|
46426
|
-
"one-line-art"
|
|
46547
|
+
"one-line-art",
|
|
46548
|
+
"product-turntable-3d",
|
|
46549
|
+
"character-stage-3d",
|
|
46550
|
+
"toy-diorama-3d",
|
|
46551
|
+
"exploded-teardown-3d"
|
|
46427
46552
|
];
|
|
46428
46553
|
var VIDEO_WORKFLOW_IDS = [
|
|
46429
46554
|
"product-proof",
|
|
@@ -46483,10 +46608,10 @@ function listTemplates() {
|
|
|
46483
46608
|
return videoTemplateCatalog();
|
|
46484
46609
|
}
|
|
46485
46610
|
async function installDependencies(directory, options) {
|
|
46486
|
-
const adjacentNpm =
|
|
46611
|
+
const adjacentNpm = resolve6(dirname6(process.execPath), "../lib/node_modules/npm/bin/npm-cli.js");
|
|
46487
46612
|
let npmScript;
|
|
46488
46613
|
try {
|
|
46489
|
-
await
|
|
46614
|
+
await access2(adjacentNpm);
|
|
46490
46615
|
npmScript = adjacentNpm;
|
|
46491
46616
|
} catch {
|
|
46492
46617
|
}
|
|
@@ -46497,7 +46622,7 @@ async function installDependencies(directory, options) {
|
|
|
46497
46622
|
signal: options.signal,
|
|
46498
46623
|
stdio: ["ignore", "pipe", "pipe"],
|
|
46499
46624
|
shell: !npmScript && process.platform === "win32",
|
|
46500
|
-
env: { ...process.env, PATH: `${
|
|
46625
|
+
env: { ...process.env, PATH: `${dirname6(process.execPath)}${delimiter2}${process.env.PATH ?? ""}` }
|
|
46501
46626
|
});
|
|
46502
46627
|
child.stdout.on("data", (chunk) => options.log?.(chunk.toString().trimEnd()));
|
|
46503
46628
|
child.stderr.on("data", (chunk) => options.log?.(chunk.toString().trimEnd()));
|
|
@@ -46522,7 +46647,7 @@ var STARTER_STORY = {
|
|
|
46522
46647
|
{ id: "invitation", label: "The invitation", start: 16, end: 24, ending: "Your next story starts here" }
|
|
46523
46648
|
]
|
|
46524
46649
|
};
|
|
46525
|
-
var writeStarterStory = (directory) => writeFile6(
|
|
46650
|
+
var writeStarterStory = (directory) => writeFile6(join7(directory, "story.json"), JSON.stringify(STARTER_STORY, null, 2) + "\n", { flag: "wx" });
|
|
46526
46651
|
function starterQuiz(story = false) {
|
|
46527
46652
|
return {
|
|
46528
46653
|
version: 1,
|
|
@@ -46535,42 +46660,42 @@ function starterQuiz(story = false) {
|
|
|
46535
46660
|
] }
|
|
46536
46661
|
};
|
|
46537
46662
|
}
|
|
46538
|
-
var writeStarterQuiz = (directory, story = false) => writeFile6(
|
|
46663
|
+
var writeStarterQuiz = (directory, story = false) => writeFile6(join7(directory, "quiz.json"), JSON.stringify(starterQuiz(story), null, 2) + "\n", { flag: "wx" });
|
|
46539
46664
|
async function createVideoProject(options, installer = installDependencies) {
|
|
46540
46665
|
if (!options.directory.trim()) throw new Error("Choose a new project folder, for example: animaguru create my-video");
|
|
46541
|
-
const directory =
|
|
46666
|
+
const directory = resolve6(options.directory);
|
|
46542
46667
|
options.signal?.throwIfAborted();
|
|
46543
46668
|
try {
|
|
46544
|
-
await
|
|
46669
|
+
await mkdir7(directory);
|
|
46545
46670
|
} catch (error62) {
|
|
46546
46671
|
if (error62.code === "EEXIST") throw new Error(`Destination already exists: ${directory}. Choose a new folder; existing files were not changed.`);
|
|
46547
46672
|
throw error62;
|
|
46548
46673
|
}
|
|
46549
46674
|
options.log?.(`Creating a video workspace in ${directory}\u2026`);
|
|
46550
|
-
const templateRoot =
|
|
46551
|
-
for (const entry of await
|
|
46675
|
+
const templateRoot = join7(packageRoot, "templates/video");
|
|
46676
|
+
for (const entry of await readdir3(templateRoot)) {
|
|
46552
46677
|
if (entry === "WORKSPACE-AGENTS.md") continue;
|
|
46553
|
-
await cp(
|
|
46678
|
+
await cp(join7(templateRoot, entry), join7(directory, entry), { recursive: true, errorOnExist: true, force: false });
|
|
46554
46679
|
}
|
|
46555
|
-
await rename3(
|
|
46556
|
-
await
|
|
46557
|
-
await
|
|
46558
|
-
const packagePath =
|
|
46559
|
-
const manifest = JSON.parse(await
|
|
46680
|
+
await rename3(join7(directory, "gitignore"), join7(directory, ".gitignore"));
|
|
46681
|
+
await mkdir7(join7(directory, "public/assets"), { recursive: true });
|
|
46682
|
+
await mkdir7(join7(directory, "production"), { recursive: true });
|
|
46683
|
+
const packagePath = join7(directory, "package.json");
|
|
46684
|
+
const manifest = JSON.parse(await readFile5(packagePath, "utf8"));
|
|
46560
46685
|
manifest.name = basename2(directory).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 100) || "animaguru-video";
|
|
46561
46686
|
await writeFile6(packagePath, JSON.stringify(manifest, null, 2) + "\n");
|
|
46562
|
-
const skills = [.../* @__PURE__ */ new Set(["animaguru", "animaguru-video", "animaguru-brand-kit", "animaguru-cutcraft", "animaguru-art-motion", "animaguru-branching-story", "animaguru-quiz", ...VIDEO_PURPOSE_SKILLS, ...VIDEO_TEMPLATES.map((template) => template.skill)])];
|
|
46563
|
-
const pixiSkillsRoot =
|
|
46564
|
-
const pixiSkills = (await
|
|
46687
|
+
const skills = [.../* @__PURE__ */ new Set(["animaguru", "animaguru-video", "animaguru-brand-kit", "animaguru-cutcraft", "animaguru-art-motion", "animaguru-branching-story", "animaguru-quiz", "animaguru-3d-models", ...VIDEO_PURPOSE_SKILLS, ...VIDEO_TEMPLATES.map((template) => template.skill)])];
|
|
46688
|
+
const pixiSkillsRoot = join7(packageRoot, "vendor/pixijs-skills/skills");
|
|
46689
|
+
const pixiSkills = (await readdir3(pixiSkillsRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
46565
46690
|
for (const agent of [".agents", ".claude"]) {
|
|
46566
|
-
const skillRoot =
|
|
46567
|
-
await
|
|
46568
|
-
for (const skill of skills) await cp(
|
|
46569
|
-
for (const skill of pixiSkills) await cp(
|
|
46570
|
-
}
|
|
46571
|
-
await cp(
|
|
46572
|
-
await cp(
|
|
46573
|
-
await writeFile6(
|
|
46691
|
+
const skillRoot = join7(directory, agent, "skills");
|
|
46692
|
+
await mkdir7(skillRoot, { recursive: true });
|
|
46693
|
+
for (const skill of skills) await cp(join7(packageRoot, "skills", skill), join7(skillRoot, skill), { recursive: true });
|
|
46694
|
+
for (const skill of pixiSkills) await cp(join7(pixiSkillsRoot, skill), join7(skillRoot, skill), { recursive: true });
|
|
46695
|
+
}
|
|
46696
|
+
await cp(join7(packageRoot, "vendor/pixijs-skills/LICENSE"), join7(directory, "PIXIJS-SKILLS-LICENSE.txt"));
|
|
46697
|
+
await cp(join7(packageRoot, "vendor/pixijs-skills/provenance.json"), join7(directory, "production/pixijs-skills-provenance.json"));
|
|
46698
|
+
await writeFile6(join7(directory, "animaguru.project.json"), JSON.stringify({
|
|
46574
46699
|
schemaVersion: 3,
|
|
46575
46700
|
cliVersion: package_default.version,
|
|
46576
46701
|
category: null,
|
|
@@ -46582,7 +46707,7 @@ async function createVideoProject(options, installer = installDependencies) {
|
|
|
46582
46707
|
interview: "pending",
|
|
46583
46708
|
animaguruProjectId: null
|
|
46584
46709
|
}, null, 2) + "\n");
|
|
46585
|
-
await writeFile6(
|
|
46710
|
+
await writeFile6(join7(directory, "animaguru.templates.json"), JSON.stringify(listTemplates(), null, 2) + "\n");
|
|
46586
46711
|
if (options.story) await writeStarterStory(directory);
|
|
46587
46712
|
if (options.quiz) await writeStarterQuiz(directory, options.story);
|
|
46588
46713
|
if (options.install !== false) {
|
|
@@ -46609,28 +46734,28 @@ ${options.install === false ? "Run npm install, then " : "Run "}npm run dev insi
|
|
|
46609
46734
|
}
|
|
46610
46735
|
async function createWorkspace(options, installer = installDependencies) {
|
|
46611
46736
|
const result = await createVideoProject({ ...options, install: false, log: (message) => {
|
|
46612
|
-
if (message.startsWith("Creating")) options.log?.(`Creating a shared-brand workspace in ${
|
|
46737
|
+
if (message.startsWith("Creating")) options.log?.(`Creating a shared-brand workspace in ${resolve6(options.directory)}\u2026`);
|
|
46613
46738
|
} }, installer);
|
|
46614
46739
|
const directory = result.path;
|
|
46615
46740
|
const { rm: rm3 } = await import("node:fs/promises");
|
|
46616
|
-
await rename3(
|
|
46617
|
-
await
|
|
46618
|
-
await
|
|
46741
|
+
await rename3(join7(directory, "src"), join7(directory, "runtime"));
|
|
46742
|
+
await mkdir7(join7(directory, "templates/animation/src"), { recursive: true });
|
|
46743
|
+
await mkdir7(join7(directory, "templates/animation/shared/locales/en"), { recursive: true });
|
|
46619
46744
|
for (const file2 of ["film.ts", "film-resources.ts"]) {
|
|
46620
|
-
const original = await
|
|
46745
|
+
const original = await readFile5(join7(directory, "runtime", file2), "utf8");
|
|
46621
46746
|
const rewritten = original.replace('"./player-types"', '"../../../runtime/player-types"').replace('"./timeline-model"', '"../../../runtime/timeline-model"').replace('"./kit"', '"../../../runtime/kit"').replace('"../shared/locales/en/timeline.json"', '"../../../shared/locales/en/timeline.json"');
|
|
46622
|
-
await writeFile6(
|
|
46623
|
-
await rm3(
|
|
46747
|
+
await writeFile6(join7(directory, "templates/animation/src", file2), rewritten);
|
|
46748
|
+
await rm3(join7(directory, "runtime", file2));
|
|
46624
46749
|
}
|
|
46625
|
-
await rm3(
|
|
46626
|
-
await rename3(
|
|
46627
|
-
await rename3(
|
|
46750
|
+
await rm3(join7(directory, "runtime/main.ts"));
|
|
46751
|
+
await rename3(join7(directory, "film.config.json"), join7(directory, "templates/animation/film.config.json"));
|
|
46752
|
+
await rename3(join7(directory, "shared/locales/en/film.json"), join7(directory, "templates/animation/shared/locales/en/film.json"));
|
|
46628
46753
|
const { createHash: createHash7 } = await import("node:crypto");
|
|
46629
|
-
await writeFile6(
|
|
46630
|
-
await rm3(
|
|
46631
|
-
await
|
|
46632
|
-
await
|
|
46633
|
-
await writeFile6(
|
|
46754
|
+
await writeFile6(join7(directory, "templates/animation/starter-film.sha256"), createHash7("sha256").update(await readFile5(join7(directory, "templates/animation/src/film.ts"))).digest("hex") + "\n");
|
|
46755
|
+
await rm3(join7(directory, "animaguru.project.json"));
|
|
46756
|
+
await mkdir7(join7(directory, "animations"));
|
|
46757
|
+
await mkdir7(join7(directory, "branding"));
|
|
46758
|
+
await writeFile6(join7(directory, "branding/brand.json"), JSON.stringify({
|
|
46634
46759
|
name: "Your brand",
|
|
46635
46760
|
tagline: "Your next story starts here",
|
|
46636
46761
|
logo: null,
|
|
@@ -46638,18 +46763,18 @@ async function createWorkspace(options, installer = installDependencies) {
|
|
|
46638
46763
|
fonts: { heading: { family: "Arial, sans-serif", file: null }, body: { family: "Arial, sans-serif", file: null } },
|
|
46639
46764
|
assets: []
|
|
46640
46765
|
}, null, 2) + "\n");
|
|
46641
|
-
await writeFile6(
|
|
46642
|
-
await writeFile6(
|
|
46643
|
-
const pkg = JSON.parse(await
|
|
46766
|
+
await writeFile6(join7(directory, "branding/README.md"), "# Shared branding\n\nThe starter brand.json contains placeholders. On the first creative request, the agent asks for your official website or brand guide unless you already supplied one. It researches the identity and records sources and usage notes in brand-guide.md. You can also provide logos, fonts and guides here or proceed without a website. Register reusable web assets in brand.json with workspace-relative paths, such as branding/logo.svg. All animations inherit this brand. Only registered web assets are included in exports; guides and other local documents remain in this workspace.\n");
|
|
46767
|
+
await writeFile6(join7(directory, "animaguru.workspace.json"), JSON.stringify({ schemaVersion: 1, cliVersion: package_default.version, name: basename2(directory), animationsDirectory: "animations", branding: "branding/brand.json" }, null, 2) + "\n");
|
|
46768
|
+
const pkg = JSON.parse(await readFile5(join7(directory, "package.json"), "utf8"));
|
|
46644
46769
|
pkg.scripts.dev = "node scripts/dev.mjs";
|
|
46645
|
-
await writeFile6(
|
|
46646
|
-
const tsconfig = JSON.parse(await
|
|
46770
|
+
await writeFile6(join7(directory, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
|
|
46771
|
+
const tsconfig = JSON.parse(await readFile5(join7(directory, "tsconfig.json"), "utf8"));
|
|
46647
46772
|
tsconfig.include = ["runtime", "animations/*/src"];
|
|
46648
|
-
await writeFile6(
|
|
46649
|
-
await writeFile6(
|
|
46650
|
-
await writeFile6(
|
|
46651
|
-
await rm3(
|
|
46652
|
-
await writeFile6(
|
|
46773
|
+
await writeFile6(join7(directory, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
|
|
46774
|
+
await writeFile6(join7(directory, "AGENTS.md"), await readFile5(join7(packageRoot, "templates/video/WORKSPACE-AGENTS.md"), "utf8"));
|
|
46775
|
+
await writeFile6(join7(directory, "CLAUDE.md"), "# AnimaGuru workspace\n\nRead AGENTS.md for the multi-animation workflow, shared branding and commands. Claude skills are in .claude/skills. For an incomplete shared kit, read .claude/skills/animaguru-brand-kit/SKILL.md and ask for the official website or brand guide if the user did not supply one. Select the animation folder before editing; reuse shared runtime/ and scripts/.\n");
|
|
46776
|
+
await rm3(join7(directory, "WORKSPACE-AGENTS.md"), { force: true });
|
|
46777
|
+
await writeFile6(join7(directory, "README.md"), "# Your AnimaGuru workspace\n\nOpen this root folder in Codex or Claude Code and describe a film. If you have an official website or brand guide, include it; otherwise the agent asks for it while setting up the shared branding/ kit. You can also provide local brand assets or proceed without a website. Create a film with animaguru create animation my-video.\n\nRun npm run dev for the workspace hub. Run npm run build -- --animation my-video, npm run export:html -- --animation my-video, or npm run export:mp4 -- --animation my-video. Player code, dependencies, skills and export tools are shared once; animation folders contain only their own production files.\n");
|
|
46653
46778
|
if (options.install !== false) {
|
|
46654
46779
|
try {
|
|
46655
46780
|
await installer(directory, options);
|
|
@@ -46665,23 +46790,23 @@ async function createWorkspace(options, installer = installDependencies) {
|
|
|
46665
46790
|
skills: result.skills,
|
|
46666
46791
|
agents: result.agents,
|
|
46667
46792
|
installed: options.install !== false,
|
|
46668
|
-
branding:
|
|
46669
|
-
animations:
|
|
46793
|
+
branding: join7(directory, "branding"),
|
|
46794
|
+
animations: join7(directory, "animations"),
|
|
46670
46795
|
nextSteps: ["Open this workspace in Codex or Claude Code and provide your website or brand guide; the agent asks if it is missing.", "Build the shared brand kit in branding/.", "Run animaguru create animation my-video.", "Run npm run dev for the animation hub."]
|
|
46671
46796
|
};
|
|
46672
46797
|
}
|
|
46673
46798
|
async function findWorkspace(start = process.cwd()) {
|
|
46674
46799
|
const { realpath } = await import("node:fs/promises");
|
|
46675
|
-
let directory = await realpath(
|
|
46800
|
+
let directory = await realpath(resolve6(start));
|
|
46676
46801
|
while (true) {
|
|
46677
46802
|
try {
|
|
46678
|
-
const info = JSON.parse(await
|
|
46803
|
+
const info = JSON.parse(await readFile5(join7(directory, "animaguru.workspace.json"), "utf8"));
|
|
46679
46804
|
if (info.schemaVersion !== 1 || info.animationsDirectory !== "animations" || info.branding !== "branding/brand.json") throw new Error("Unsupported AnimaGuru workspace.");
|
|
46680
46805
|
return directory;
|
|
46681
46806
|
} catch (error62) {
|
|
46682
46807
|
if (error62.code !== "ENOENT") throw error62;
|
|
46683
46808
|
}
|
|
46684
|
-
const parent =
|
|
46809
|
+
const parent = dirname6(directory);
|
|
46685
46810
|
if (parent === directory) throw new Error("Run this inside an AnimaGuru workspace, or pass --workspace PATH. Create one with animaguru create workspace NAME.");
|
|
46686
46811
|
directory = parent;
|
|
46687
46812
|
}
|
|
@@ -46690,23 +46815,23 @@ async function createAnimation(options) {
|
|
|
46690
46815
|
if (!/^[a-z0-9][a-z0-9-]{0,79}$/.test(options.name)) throw new Error("Choose a lowercase, hyphenated animation name, such as product-launch.");
|
|
46691
46816
|
options.signal?.throwIfAborted();
|
|
46692
46817
|
const root = await findWorkspace(options.workspace);
|
|
46693
|
-
const directory =
|
|
46818
|
+
const directory = join7(root, "animations", options.name);
|
|
46694
46819
|
try {
|
|
46695
|
-
await
|
|
46820
|
+
await mkdir7(directory);
|
|
46696
46821
|
} catch (error62) {
|
|
46697
46822
|
if (error62.code === "EEXIST") throw new Error(`Animation already exists: ${options.name}. Existing files were not changed.`);
|
|
46698
46823
|
throw error62;
|
|
46699
46824
|
}
|
|
46700
|
-
for (const file2 of await
|
|
46701
|
-
if (file2 !== "starter-film.sha256") await cp(
|
|
46825
|
+
for (const file2 of await readdir3(join7(root, "templates/animation"))) {
|
|
46826
|
+
if (file2 !== "starter-film.sha256") await cp(join7(root, "templates/animation", file2), join7(directory, file2), { recursive: true, errorOnExist: true, force: false });
|
|
46702
46827
|
}
|
|
46703
|
-
const config2 = JSON.parse(await
|
|
46828
|
+
const config2 = JSON.parse(await readFile5(join7(directory, "film.config.json"), "utf8"));
|
|
46704
46829
|
config2.slug = options.name;
|
|
46705
46830
|
config2.title = options.name.replaceAll("-", " ").replace(/^./, (value) => value.toUpperCase());
|
|
46706
|
-
await writeFile6(
|
|
46707
|
-
await
|
|
46708
|
-
await
|
|
46709
|
-
await writeFile6(
|
|
46831
|
+
await writeFile6(join7(directory, "film.config.json"), JSON.stringify(config2, null, 2) + "\n");
|
|
46832
|
+
await mkdir7(join7(directory, "public/assets"), { recursive: true });
|
|
46833
|
+
await mkdir7(join7(directory, "production"), { recursive: true });
|
|
46834
|
+
await writeFile6(join7(directory, "animaguru.project.json"), JSON.stringify({ schemaVersion: 4, cliVersion: package_default.version, workspace: "../..", category: null, template: null, workflow: null, skill: null, setupStage: "category", galleryUrl: ANIMATION_STYLE_GALLERY_URL, interview: "pending", animaguruProjectId: null, branding: "inherit" }, null, 2) + "\n");
|
|
46710
46835
|
if (options.story) await writeStarterStory(directory);
|
|
46711
46836
|
if (options.quiz) await writeStarterQuiz(directory, options.story);
|
|
46712
46837
|
const kind = options.story && options.quiz ? "Branching story with a quiz" : options.story ? "Branching story" : options.quiz ? "Quiz film" : "Animation";
|
|
@@ -46725,8 +46850,65 @@ async function createAnimation(options) {
|
|
|
46725
46850
|
};
|
|
46726
46851
|
}
|
|
46727
46852
|
|
|
46853
|
+
// shared/model-assets.ts
|
|
46854
|
+
var MODEL_GENERATORS = [
|
|
46855
|
+
{
|
|
46856
|
+
id: "tripo-h3.1",
|
|
46857
|
+
label: "Tripo H3.1",
|
|
46858
|
+
endpoints: { image: "tripo3d/h3.1/image-to-3d", text: "tripo3d/h3.1/text-to-3d" },
|
|
46859
|
+
faces: { min: 1e3, max: 2e6 },
|
|
46860
|
+
/** The direction the generated model faces; saved models are turned to +Z. */
|
|
46861
|
+
facing: "+x"
|
|
46862
|
+
},
|
|
46863
|
+
{
|
|
46864
|
+
id: "hunyuan-3d-3.1-pro",
|
|
46865
|
+
label: "Hunyuan3D 3.1 Pro",
|
|
46866
|
+
endpoints: { image: "fal-ai/hunyuan-3d/v3.1/pro/image-to-3d", text: "fal-ai/hunyuan-3d/v3.1/pro/text-to-3d" },
|
|
46867
|
+
faces: { min: 4e4, max: 15e5 },
|
|
46868
|
+
facing: "+z"
|
|
46869
|
+
}
|
|
46870
|
+
];
|
|
46871
|
+
var MODEL_GENERATOR_IDS = MODEL_GENERATORS.map((m) => m.id);
|
|
46872
|
+
var DEFAULT_MODEL_GENERATOR = "tripo-h3.1";
|
|
46873
|
+
var modelGenerator = (id2) => MODEL_GENERATORS.find((m) => m.id === id2) ?? MODEL_GENERATORS[0];
|
|
46874
|
+
var MAX_MODEL_CLIPS = 10;
|
|
46875
|
+
var MAX_RIG_FACES = 3e5;
|
|
46876
|
+
var MAX_MESHY_ACTION = 696;
|
|
46877
|
+
var MAX_MODEL_PROMPT = 1e3;
|
|
46878
|
+
var MODEL_ANIMATIONS = [
|
|
46879
|
+
{ id: "idle", action: 0, label: "Idle" },
|
|
46880
|
+
{ id: "idle-2", action: 11, label: "Idle 2" },
|
|
46881
|
+
{ id: "idle-3", action: 12, label: "Idle 3" },
|
|
46882
|
+
{ id: "walk", action: 30, label: "Casual walk" },
|
|
46883
|
+
{ id: "walk-woman", action: 1, label: "Walking (woman)" },
|
|
46884
|
+
{ id: "stage-walk", action: 55, label: "Stage walk" },
|
|
46885
|
+
{ id: "thoughtful-walk", action: 121, label: "Thoughtful walk" },
|
|
46886
|
+
{ id: "run", action: 14, label: "Run" },
|
|
46887
|
+
{ id: "run-fast", action: 16, label: "Fast run" },
|
|
46888
|
+
{ id: "wave", action: 28, label: "Big wave hello" },
|
|
46889
|
+
{ id: "wave-one-hand", action: 290, label: "One-hand wave" },
|
|
46890
|
+
{ id: "cheer", action: 59, label: "Victory cheer" },
|
|
46891
|
+
{ id: "cheer-hands-up", action: 298, label: "Cheer with both hands up" },
|
|
46892
|
+
{ id: "fist-pump", action: 403, label: "Victory fist pump" },
|
|
46893
|
+
{ id: "talk", action: 313, label: "Talk with open hands" },
|
|
46894
|
+
{ id: "talk-passionately", action: 308, label: "Talk passionately" },
|
|
46895
|
+
{ id: "phone-call", action: 312, label: "Phone conversation" },
|
|
46896
|
+
{ id: "agree", action: 25, label: "Agree gesture" },
|
|
46897
|
+
{ id: "jump", action: 466, label: "Jump" },
|
|
46898
|
+
{ id: "jump-arms-open", action: 460, label: "Jump with arms open" },
|
|
46899
|
+
{ id: "dance", action: 22, label: "Funny dance" },
|
|
46900
|
+
{ id: "dance-2", action: 64, label: "All-night dance" },
|
|
46901
|
+
{ id: "shuffle", action: 63, label: "Arm-circle shuffle" }
|
|
46902
|
+
];
|
|
46903
|
+
var MODEL_ANIMATION_IDS = MODEL_ANIMATIONS.map((a) => a.id);
|
|
46904
|
+
var DEFAULT_MODEL_ANIMATIONS = ["idle", "walk"];
|
|
46905
|
+
var animationAction = (clip) => typeof clip === "number" ? clip : MODEL_ANIMATIONS.find((a) => a.id === clip).action;
|
|
46906
|
+
var generationCostUsd = (p) => p.model === "hunyuan-3d-3.1-pro" ? 0.375 + (p.texture && p.pbr ? 0.15 : 0) + (p.faces !== void 0 ? 0.15 : 0) : p.texture ? 0.3 : 0.2;
|
|
46907
|
+
var rigCostUsd = (clips2) => 0.2 + 0.12 * clips2;
|
|
46908
|
+
var modelCostUsd = (p) => generationCostUsd(p) + (p.rig ? rigCostUsd(p.animations.length) : 0);
|
|
46909
|
+
|
|
46728
46910
|
// shared/assets.ts
|
|
46729
|
-
var ASSET_TYPES = ["image", "video", "music", "speech", "sfx"];
|
|
46911
|
+
var ASSET_TYPES = ["image", "vector", "video", "music", "speech", "sfx", "model"];
|
|
46730
46912
|
var SPEECH_MODELS = [
|
|
46731
46913
|
{ id: "gemini-3.8-flash-tts", label: "Gemini 3.8 Flash TTS" },
|
|
46732
46914
|
{ id: "gemini-3.8-flash-lite-tts", label: "Gemini 3.8 Flash-Lite TTS" },
|
|
@@ -46979,6 +47161,86 @@ var imageAsset = external_exports.object({
|
|
|
46979
47161
|
var imageChecks = (p, ctx) => {
|
|
46980
47162
|
if (p.mask && !p.references.length) ctx.addIssue({ code: "custom", message: "A mask edits Image 1; add the image to edit as the first reference.", path: ["mask"] });
|
|
46981
47163
|
};
|
|
47164
|
+
var VECTOR_MODELS = [{ id: "fal/ideogram-vector", label: "Ideogram Vector (fal)" }];
|
|
47165
|
+
var VECTOR_WORKFLOWS = ["text-to-vector", "image-to-vector"];
|
|
47166
|
+
var VECTOR_QUALITIES = ["low", "medium", "high"];
|
|
47167
|
+
var VECTOR_ASPECT_RATIOS = ["auto", "1:1", "1:4", "1:3", "1:2", "9:16", "10:16", "2:3", "3:4", "4:5", "5:4", "4:3", "3:2", "16:10", "16:9", "2:1", "3:1", "4:1"];
|
|
47168
|
+
var VECTOR_SHAPES = ["detailed", "simple"];
|
|
47169
|
+
var MAX_VECTOR_REFERENCES = 5;
|
|
47170
|
+
var VECTOR_REFERENCE_MAX_BYTES = 10 * 1024 * 1024;
|
|
47171
|
+
var VECTOR_SOURCE_MAX_BYTES = 50 * 1024 * 1024;
|
|
47172
|
+
var vectorAsset = external_exports.object({
|
|
47173
|
+
name: base.name,
|
|
47174
|
+
/** Image-to-vector takes no prompt. */
|
|
47175
|
+
prompt: external_exports.string().trim().max(4e3).default(""),
|
|
47176
|
+
type: external_exports.literal("vector"),
|
|
47177
|
+
model: external_exports.literal("fal/ideogram-vector").default("fal/ideogram-vector"),
|
|
47178
|
+
workflow: external_exports.enum(VECTOR_WORKFLOWS).default("text-to-vector"),
|
|
47179
|
+
/** Text-to-vector; defaults to medium. */
|
|
47180
|
+
quality: external_exports.enum(VECTOR_QUALITIES).optional(),
|
|
47181
|
+
/** Text-to-vector; defaults to auto. */
|
|
47182
|
+
aspectRatio: external_exports.enum(VECTOR_ASPECT_RATIOS).optional(),
|
|
47183
|
+
/** Text-to-vector: saved images or sprite art to follow, the first being the main one. */
|
|
47184
|
+
references: external_exports.array(blob).max(MAX_VECTOR_REFERENCES).default([]),
|
|
47185
|
+
/** Image-to-vector: the saved image or sprite art to trace. */
|
|
47186
|
+
source: blob.optional(),
|
|
47187
|
+
/** Image-to-vector; defaults to detailed. */
|
|
47188
|
+
shapes: external_exports.enum(VECTOR_SHAPES).optional(),
|
|
47189
|
+
/** Text-to-vector. */
|
|
47190
|
+
seed: external_exports.number().int().min(0).max(2 ** 32 - 1).optional()
|
|
47191
|
+
});
|
|
47192
|
+
function vectorChecks(p, ctx) {
|
|
47193
|
+
const issue2 = (path, message) => ctx.addIssue({ code: "custom", message, path: [path] });
|
|
47194
|
+
if (new Set(p.references).size !== p.references.length) issue2("references", "Choose each reference image once.");
|
|
47195
|
+
if (p.workflow === "text-to-vector") {
|
|
47196
|
+
if (p.prompt.length < 3) issue2("prompt", "Describe the vector in at least 3 characters.");
|
|
47197
|
+
if (p.source) issue2("source", "Only image-to-vector traces a saved image; use references to guide text-to-vector.");
|
|
47198
|
+
if (p.shapes) issue2("shapes", "Only image-to-vector takes shapes.");
|
|
47199
|
+
return;
|
|
47200
|
+
}
|
|
47201
|
+
if (p.prompt) issue2("prompt", "image-to-vector takes no prompt; leave it out.");
|
|
47202
|
+
if (!p.source) issue2("source", "Choose a saved image or sprite to trace.");
|
|
47203
|
+
for (const field of ["quality", "aspectRatio", "seed"]) if (p[field] !== void 0) issue2(field, `image-to-vector doesn't take ${field === "aspectRatio" ? "an aspect ratio" : field === "seed" ? "a seed" : "a quality"}; the SVG follows the image.`);
|
|
47204
|
+
if (p.references.length) issue2("references", "image-to-vector traces its source alone and takes no references.");
|
|
47205
|
+
}
|
|
47206
|
+
var vectorDefaults = (p) => p.workflow === "text-to-vector" ? { ...p, quality: p.quality ?? "medium", aspectRatio: p.aspectRatio ?? "auto" } : { ...p, shapes: p.shapes ?? "detailed" };
|
|
47207
|
+
var animationClip = external_exports.union([external_exports.enum(MODEL_ANIMATION_IDS), external_exports.number().int().min(0).max(MAX_MESHY_ACTION)]);
|
|
47208
|
+
var modelAsset = external_exports.object({
|
|
47209
|
+
name: base.name,
|
|
47210
|
+
/** Describes the model for text-to-3D; with a reference image it is only a note. */
|
|
47211
|
+
prompt: external_exports.string().trim().max(4e3).default(""),
|
|
47212
|
+
type: external_exports.literal("model"),
|
|
47213
|
+
model: external_exports.enum(MODEL_GENERATOR_IDS).default(DEFAULT_MODEL_GENERATOR),
|
|
47214
|
+
/** A saved image or sprite art the model is built from. */
|
|
47215
|
+
reference: blob.optional(),
|
|
47216
|
+
/** Textured (default), or a plain white model. */
|
|
47217
|
+
texture: external_exports.boolean().default(true),
|
|
47218
|
+
/** Metallic, roughness and normal maps with the texture, so scene lights shape the surface. */
|
|
47219
|
+
pbr: external_exports.boolean().default(true),
|
|
47220
|
+
/** Target face count, within the generator's range; Hunyuan3D charges extra for it. */
|
|
47221
|
+
faces: external_exports.number().int().optional(),
|
|
47222
|
+
/** Auto-rig a humanoid character standing in a T- or A-pose. */
|
|
47223
|
+
rig: external_exports.boolean().default(false),
|
|
47224
|
+
/** Clips the rig gets (idle and walk when none are named). */
|
|
47225
|
+
animations: external_exports.array(animationClip).max(MAX_MODEL_CLIPS).default([]),
|
|
47226
|
+
/** The rigged character's height in metres (default 1.7). */
|
|
47227
|
+
height: external_exports.number().min(0.3).max(5).optional()
|
|
47228
|
+
});
|
|
47229
|
+
function modelChecks(p, ctx) {
|
|
47230
|
+
const issue2 = (path, message) => ctx.addIssue({ code: "custom", message, path: [path] });
|
|
47231
|
+
const generator = modelGenerator(p.model);
|
|
47232
|
+
if (!p.reference && p.prompt.length < 3) issue2("prompt", "Describe the model in at least 3 characters, or choose a saved image to build it from.");
|
|
47233
|
+
if (!p.reference && p.prompt.length > MAX_MODEL_PROMPT) issue2("prompt", `Describe the model in at most ${MAX_MODEL_PROMPT.toLocaleString("en-US")} characters.`);
|
|
47234
|
+
if (p.faces !== void 0 && (p.faces < generator.faces.min || p.faces > generator.faces.max)) issue2("faces", `${generator.label} makes ${generator.faces.min.toLocaleString("en-US")}\u2013${generator.faces.max.toLocaleString("en-US")} faces.`);
|
|
47235
|
+
if (!p.rig && p.animations.length) issue2("animations", "Animation clips need rig: true.");
|
|
47236
|
+
if (!p.rig && p.height !== void 0) issue2("height", "height is the rigged character's height; it needs rig: true.");
|
|
47237
|
+
if (!p.rig) return;
|
|
47238
|
+
if (p.faces === void 0 && p.model === "hunyuan-3d-3.1-pro") issue2("faces", `Rigging takes at most ${MAX_RIG_FACES.toLocaleString("en-US")} faces, and Hunyuan3D makes 500,000 unless you set faces.`);
|
|
47239
|
+
else if (p.faces !== void 0 && p.faces > MAX_RIG_FACES) issue2("faces", `Rigging takes at most ${MAX_RIG_FACES.toLocaleString("en-US")} faces.`);
|
|
47240
|
+
const actions2 = p.animations.map(animationAction);
|
|
47241
|
+
if (new Set(actions2).size !== actions2.length) issue2("animations", "Choose each clip once.");
|
|
47242
|
+
}
|
|
47243
|
+
var modelDefaults = (p) => ({ ...p, animations: p.rig && !p.animations.length ? [...DEFAULT_MODEL_ANIMATIONS] : p.animations });
|
|
46982
47244
|
var assetRequest = external_exports.discriminatedUnion("type", [
|
|
46983
47245
|
imageAsset.superRefine(imageChecks),
|
|
46984
47246
|
videoAsset.superRefine(videoChecks).transform(videoDefaults),
|
|
@@ -46987,7 +47249,9 @@ var assetRequest = external_exports.discriminatedUnion("type", [
|
|
|
46987
47249
|
if (p.voice && (isElevenLabsSpeech(p.model) ? !/^[a-zA-Z0-9]{20}$/.test(p.voice) : !SPEECH_VOICES.includes(p.voice))) ctx.addIssue({ code: "custom", message: "Choose a voice supported by the speech provider.", path: ["voice"] });
|
|
46988
47250
|
if (isElevenLabsSpeech(p.model) && p.delivery) ctx.addIssue({ code: "custom", message: "ElevenLabs uses audio tags in the transcript; separate delivery instructions are only supported by Gemini.", path: ["delivery"] });
|
|
46989
47251
|
}).transform((p) => ({ ...p, voice: p.voice || (isElevenLabsSpeech(p.model) ? DEFAULT_ELEVENLABS_VOICE : "Kore") })),
|
|
46990
|
-
external_exports.object({ ...base, type: external_exports.literal("sfx"), model: external_exports.literal("eleven_text_to_sound_v2").default("eleven_text_to_sound_v2"), seconds: external_exports.number().min(0.5).max(30).default(5), loop: external_exports.boolean().default(false), promptInfluence: external_exports.number().min(0).max(1).default(0.3) })
|
|
47252
|
+
external_exports.object({ ...base, type: external_exports.literal("sfx"), model: external_exports.literal("eleven_text_to_sound_v2").default("eleven_text_to_sound_v2"), seconds: external_exports.number().min(0.5).max(30).default(5), loop: external_exports.boolean().default(false), promptInfluence: external_exports.number().min(0).max(1).default(0.3) }),
|
|
47253
|
+
vectorAsset.superRefine(vectorChecks).transform(vectorDefaults),
|
|
47254
|
+
modelAsset.superRefine(modelChecks).transform(modelDefaults)
|
|
46991
47255
|
]);
|
|
46992
47256
|
var assetGenerationRequest = external_exports.discriminatedUnion("type", [imageAsset.omit({ model: true }).superRefine(imageChecks), ...assetRequest.options.slice(1)]);
|
|
46993
47257
|
var LIBRARY_AUDIO_MODEL = "library-audio";
|
|
@@ -46997,17 +47261,21 @@ var uploadedMedia = external_exports.object({ name: base.name, prompt: external_
|
|
|
46997
47261
|
var savedAssetOptions = external_exports.union([assetRequest, libraryAudio, uploadedMedia]);
|
|
46998
47262
|
var speechCharacters = (text2) => Array.from(text2).length;
|
|
46999
47263
|
var imageEstimate = (p) => Math.ceil((130 + 40 * p.references.length) * spriteImageModel(p.model).relCost);
|
|
47264
|
+
var vectorEstimate = (p) => p.workflow === "image-to-vector" ? 100 : p.quality === "low" ? 130 : p.quality === "high" ? p.references.length ? 320 : 200 : 160;
|
|
47000
47265
|
function videoExtras(p, facts = {}) {
|
|
47001
47266
|
const w = p.workflow;
|
|
47002
47267
|
if (w !== "reference-to-video" && w !== "insert-video" && w !== "3d-to-video") return {};
|
|
47003
47268
|
const images = (p.references ?? []).reduce((sum, sha2) => sum + imageReferenceTokens(facts.size?.(sha2)), 0);
|
|
47004
47269
|
if (w === "3d-to-video") return { referenceTokens: images + clipReferenceTokens(p.seconds, p.resolution), generatedReferences: p.references?.length ? 0 : p.generatedReferences ?? DEFAULT_GENERATED_REFERENCES };
|
|
47005
|
-
const
|
|
47270
|
+
const clips2 = Math.min(15, (p.referenceVideos ?? []).reduce((sum, sha2) => sum + Math.min(p.seconds, facts.seconds?.(sha2) ?? p.seconds), 0));
|
|
47006
47271
|
const audio = Math.min(15, p.audioReferences.reduce((sum, sha2) => sum + (facts.seconds?.(sha2) ?? 15), 0));
|
|
47007
|
-
return { referenceTokens: images + clipReferenceTokens(
|
|
47272
|
+
return { referenceTokens: images + clipReferenceTokens(clips2, p.resolution) + (w === "reference-to-video" ? audioReferenceTokens(audio) : 0) };
|
|
47008
47273
|
}
|
|
47274
|
+
var modelEstimate = (p) => Math.max(1, Math.ceil(modelCostUsd(p) / 1e-3));
|
|
47009
47275
|
function assetEstimate(p, now = Date.now()) {
|
|
47010
47276
|
if (p.type === "image") return imageEstimate(p);
|
|
47277
|
+
if (p.type === "vector") return vectorEstimate(p);
|
|
47278
|
+
if (p.type === "model") return modelEstimate(p);
|
|
47011
47279
|
if (p.type === "video") return spriteVideoEstimate(spriteVideoModel(p.model), p, videoExtras(p));
|
|
47012
47280
|
if (p.type === "music") return 80;
|
|
47013
47281
|
const units = (credits) => Math.max(1, Math.ceil(credits * UNITS_PER_CREDIT));
|
|
@@ -47024,8 +47292,8 @@ function assetEstimate(p, now = Date.now()) {
|
|
|
47024
47292
|
}
|
|
47025
47293
|
|
|
47026
47294
|
// cli/src/videos.ts
|
|
47027
|
-
import { open as open4, readFile as
|
|
47028
|
-
import { basename as basename4, join as
|
|
47295
|
+
import { open as open4, readFile as readFile9, stat as stat4 } from "node:fs/promises";
|
|
47296
|
+
import { basename as basename4, join as join10, resolve as resolve10 } from "node:path";
|
|
47029
47297
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
47030
47298
|
import { spawn as spawn2 } from "node:child_process";
|
|
47031
47299
|
import { createHash as createHash4 } from "node:crypto";
|
|
@@ -47121,12 +47389,12 @@ function parseSubtitles(input2, duration3) {
|
|
|
47121
47389
|
}
|
|
47122
47390
|
|
|
47123
47391
|
// cli/src/export-files.ts
|
|
47124
|
-
import { open as open2, readFile as
|
|
47125
|
-
import { basename as basename3, resolve as
|
|
47392
|
+
import { open as open2, readFile as readFile6, stat as stat2 } from "node:fs/promises";
|
|
47393
|
+
import { basename as basename3, resolve as resolve7 } from "node:path";
|
|
47126
47394
|
import { createHash as createHash2 } from "node:crypto";
|
|
47127
47395
|
async function exportReceipt(file2) {
|
|
47128
47396
|
try {
|
|
47129
|
-
const receipt = JSON.parse(await
|
|
47397
|
+
const receipt = JSON.parse(await readFile6(file2.replace(/\.mp4$/i, ".json"), "utf8"));
|
|
47130
47398
|
if (receipt.file !== basename3(file2)) return {};
|
|
47131
47399
|
return { title: typeof receipt.title === "string" ? receipt.title : void 0, language: typeof receipt.settings?.language === "string" ? receipt.settings.language : void 0 };
|
|
47132
47400
|
} catch {
|
|
@@ -47136,22 +47404,22 @@ async function exportReceipt(file2) {
|
|
|
47136
47404
|
async function readSubtitleFile(file2, maxBytes) {
|
|
47137
47405
|
let info;
|
|
47138
47406
|
try {
|
|
47139
|
-
info = await
|
|
47407
|
+
info = await stat2(file2);
|
|
47140
47408
|
} catch {
|
|
47141
47409
|
throw new Error(`Cannot read the subtitle file ${file2}.`);
|
|
47142
47410
|
}
|
|
47143
47411
|
if (!info.isFile() || !/\.(?:srt|vtt)$/i.test(file2) || info.size < 1 || info.size > maxBytes) throw new Error(`Use a .srt or .vtt subtitle file up to ${maxBytes / 1024 / 1024} MiB, such as the one npm run export:mp4 writes beside the MP4.`);
|
|
47144
|
-
const content = await
|
|
47412
|
+
const content = await readFile6(file2);
|
|
47145
47413
|
const text2 = content.toString("utf8");
|
|
47146
47414
|
if (text2.includes("\uFFFD") || !/\d\d:\d\d[,.]\d{3} --> /.test(text2)) throw new Error("Use a UTF-8 .srt or .vtt subtitle file with timed captions.");
|
|
47147
47415
|
return { content, sha256: createHash2("sha256").update(content).digest("hex"), language: /^\uFEFF?WEBVTT[^\n]*\n(?:[^\n]+\n)*?Language:[ \t]*([^\s]+)/.exec(text2)?.[1] };
|
|
47148
47416
|
}
|
|
47149
47417
|
async function subtitleFile(root, mp4, choice, extensions) {
|
|
47150
47418
|
if (choice === "none") return null;
|
|
47151
|
-
if (choice !== "auto") return { file:
|
|
47419
|
+
if (choice !== "auto") return { file: resolve7(root, choice), explicit: true };
|
|
47152
47420
|
for (const extension of extensions) {
|
|
47153
47421
|
const file2 = mp4.replace(/\.mp4$/i, extension);
|
|
47154
|
-
if (await
|
|
47422
|
+
if (await stat2(file2).then((info) => info.isFile(), () => false)) return { file: file2, explicit: false };
|
|
47155
47423
|
}
|
|
47156
47424
|
return null;
|
|
47157
47425
|
}
|
|
@@ -47226,10 +47494,10 @@ async function mp4Info(file2) {
|
|
|
47226
47494
|
}
|
|
47227
47495
|
|
|
47228
47496
|
// cli/src/local-project.ts
|
|
47229
|
-
import { readFile as
|
|
47230
|
-
import { join as
|
|
47497
|
+
import { readFile as readFile7, readdir as readdir4 } from "node:fs/promises";
|
|
47498
|
+
import { join as join8, relative, resolve as resolve8, sep } from "node:path";
|
|
47231
47499
|
async function localProject(directory, selected) {
|
|
47232
|
-
const root =
|
|
47500
|
+
const root = resolve8(directory);
|
|
47233
47501
|
let workspace3;
|
|
47234
47502
|
try {
|
|
47235
47503
|
workspace3 = await findWorkspace(root);
|
|
@@ -47241,10 +47509,10 @@ async function localProject(directory, selected) {
|
|
|
47241
47509
|
let animation = selected ?? (location[0] === "animations" ? location[1] : void 0);
|
|
47242
47510
|
if (!animation) {
|
|
47243
47511
|
const names = [];
|
|
47244
|
-
for (const entry of await
|
|
47512
|
+
for (const entry of await readdir4(join8(workspace3, "animations"), { withFileTypes: true })) {
|
|
47245
47513
|
if (!entry.isDirectory()) continue;
|
|
47246
47514
|
try {
|
|
47247
|
-
await
|
|
47515
|
+
await readFile7(join8(workspace3, "animations", entry.name, "animaguru.project.json"));
|
|
47248
47516
|
names.push(entry.name);
|
|
47249
47517
|
} catch (error62) {
|
|
47250
47518
|
if (error62.code !== "ENOENT") throw error62;
|
|
@@ -47254,17 +47522,17 @@ async function localProject(directory, selected) {
|
|
|
47254
47522
|
animation = names[0];
|
|
47255
47523
|
}
|
|
47256
47524
|
if (!/^[a-z0-9][a-z0-9-]{0,79}$/.test(animation)) throw new Error("Use a lowercase, hyphenated animation name.");
|
|
47257
|
-
const projectRoot =
|
|
47258
|
-
await
|
|
47525
|
+
const projectRoot = join8(workspace3, "animations", animation);
|
|
47526
|
+
await readFile7(join8(projectRoot, "animaguru.project.json"));
|
|
47259
47527
|
return { toolsRoot: workspace3, projectRoot, animation };
|
|
47260
47528
|
}
|
|
47261
47529
|
|
|
47262
47530
|
// cli/src/cloud-sync.ts
|
|
47263
47531
|
var import_isomorphic_git = __toESM(require_isomorphic_git(), 1);
|
|
47264
47532
|
import * as fs from "node:fs";
|
|
47265
|
-
import { chmod as chmod3, lstat, mkdir as
|
|
47533
|
+
import { chmod as chmod3, lstat, mkdir as mkdir8, open as open3, readFile as readFile8, readdir as readdir5, rename as rename4, rm as rm2, stat as stat3, writeFile as writeFile7 } from "node:fs/promises";
|
|
47266
47534
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
47267
|
-
import { dirname as
|
|
47535
|
+
import { dirname as dirname7, join as join9, resolve as resolve9 } from "node:path";
|
|
47268
47536
|
import { Readable } from "node:stream";
|
|
47269
47537
|
import { pipeline } from "node:stream/promises";
|
|
47270
47538
|
import { setTimeout as delay } from "node:timers/promises";
|
|
@@ -47483,37 +47751,37 @@ var list = (paths, limit2 = 200) => paths.length > limit2 ? [...paths.slice(0, l
|
|
|
47483
47751
|
var short = (oid) => oid.slice(0, 12);
|
|
47484
47752
|
var executable = (mode) => (mode & 73) !== 0;
|
|
47485
47753
|
async function cloudRootFor(start) {
|
|
47486
|
-
let directory =
|
|
47754
|
+
let directory = resolve9(start);
|
|
47487
47755
|
while (true) {
|
|
47488
|
-
if (await exists(
|
|
47756
|
+
if (await exists(join9(directory, LINK_FILE)) || await exists(join9(directory, "animaguru.workspace.json"))) return directory;
|
|
47489
47757
|
try {
|
|
47490
|
-
const project = JSON.parse(await
|
|
47758
|
+
const project = JSON.parse(await readFile8(join9(directory, "animaguru.project.json"), "utf8"));
|
|
47491
47759
|
if (!project.workspace) return directory;
|
|
47492
47760
|
} catch (error62) {
|
|
47493
47761
|
if (error62.code !== "ENOENT" && !(error62 instanceof SyntaxError)) throw error62;
|
|
47494
47762
|
}
|
|
47495
|
-
const parent =
|
|
47763
|
+
const parent = dirname7(directory);
|
|
47496
47764
|
if (parent === directory) throw new Error("Run this inside an AnimaGuru video workspace or project, or pass --dir. Create one with animaguru create workspace NAME.");
|
|
47497
47765
|
directory = parent;
|
|
47498
47766
|
}
|
|
47499
47767
|
}
|
|
47500
47768
|
async function readJson2(path) {
|
|
47501
47769
|
try {
|
|
47502
|
-
return JSON.parse(await
|
|
47770
|
+
return JSON.parse(await readFile8(path, "utf8"));
|
|
47503
47771
|
} catch (error62) {
|
|
47504
47772
|
if (error62.code === "ENOENT") return null;
|
|
47505
47773
|
throw error62;
|
|
47506
47774
|
}
|
|
47507
47775
|
}
|
|
47508
47776
|
async function writeJson2(path, value) {
|
|
47509
|
-
await
|
|
47777
|
+
await mkdir8(dirname7(path), { recursive: true });
|
|
47510
47778
|
const temp = `${path}.${randomUUID2()}.tmp`;
|
|
47511
47779
|
await writeFile7(temp, JSON.stringify(value, null, 2) + "\n", { mode: 384 });
|
|
47512
47780
|
await rename4(temp, path);
|
|
47513
47781
|
}
|
|
47514
47782
|
async function withLock(root, run) {
|
|
47515
|
-
const path =
|
|
47516
|
-
await
|
|
47783
|
+
const path = join9(root, SYNC_DIR, "lock");
|
|
47784
|
+
await mkdir8(dirname7(path), { recursive: true });
|
|
47517
47785
|
for (let attempt = 0; ; attempt++) {
|
|
47518
47786
|
try {
|
|
47519
47787
|
await writeFile7(path, JSON.stringify({ pid: process.pid, at: Date.now() }), { flag: "wx" });
|
|
@@ -47541,27 +47809,27 @@ async function withLock(root, run) {
|
|
|
47541
47809
|
}
|
|
47542
47810
|
async function openContext(dir, options, url3) {
|
|
47543
47811
|
const root = await cloudRootFor(dir);
|
|
47544
|
-
const link2 = await readJson2(
|
|
47812
|
+
const link2 = await readJson2(join9(root, LINK_FILE));
|
|
47545
47813
|
if (!link2) throw new Error("This folder is not linked to a project. Run animaguru cloud link, or animaguru cloud clone PROJECT_ID.");
|
|
47546
47814
|
if (link2.schemaVersion !== 1 || !cloudProjectId.safeParse(link2.projectId).success) throw new Error(`Unsupported cloud link in ${LINK_FILE}. Run animaguru cloud unlink and link again.`);
|
|
47547
|
-
const state = await readJson2(
|
|
47548
|
-
return { root, gitdir:
|
|
47815
|
+
const state = await readJson2(join9(root, STATE_FILE)) ?? { schemaVersion: 1, base: null, files: {} };
|
|
47816
|
+
return { root, gitdir: join9(root, GIT_DIR), link: link2, state, client: new Client(url3 ?? link2.origin, options.signal), options };
|
|
47549
47817
|
}
|
|
47550
47818
|
async function cloudLink(dir) {
|
|
47551
|
-
const link2 = await readJson2(
|
|
47819
|
+
const link2 = await readJson2(join9(await cloudRootFor(dir), LINK_FILE));
|
|
47552
47820
|
if (!link2) throw new Error("This folder is not linked to a project. Pass a project ID.");
|
|
47553
47821
|
return link2;
|
|
47554
47822
|
}
|
|
47555
|
-
var saveState = (context) => writeJson2(
|
|
47823
|
+
var saveState = (context) => writeJson2(join9(context.root, STATE_FILE), context.state);
|
|
47556
47824
|
async function scanFiles(root) {
|
|
47557
47825
|
const files = /* @__PURE__ */ new Map();
|
|
47558
47826
|
const skipped = [];
|
|
47559
47827
|
const tooLarge = [];
|
|
47560
47828
|
async function walk(directory, prefix, rules) {
|
|
47561
|
-
const entries = (await
|
|
47829
|
+
const entries = (await readdir5(directory, { withFileTypes: true })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
47562
47830
|
const scoped = [...rules];
|
|
47563
47831
|
for (const name2 of [".gitignore", ".animaguruignore"]) {
|
|
47564
|
-
if (entries.some((entry) => entry.name === name2 && entry.isFile())) scoped.push({ base: prefix, rules: (0, import_ignore.default)().add(await
|
|
47832
|
+
if (entries.some((entry) => entry.name === name2 && entry.isFile())) scoped.push({ base: prefix, rules: (0, import_ignore.default)().add(await readFile8(join9(directory, name2), "utf8")) });
|
|
47565
47833
|
}
|
|
47566
47834
|
for (const entry of entries) {
|
|
47567
47835
|
const path = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
@@ -47572,7 +47840,7 @@ async function scanFiles(root) {
|
|
|
47572
47840
|
continue;
|
|
47573
47841
|
}
|
|
47574
47842
|
if (entry.isDirectory()) {
|
|
47575
|
-
await walk(
|
|
47843
|
+
await walk(join9(directory, entry.name), path, scoped);
|
|
47576
47844
|
continue;
|
|
47577
47845
|
}
|
|
47578
47846
|
if (!entry.isFile()) continue;
|
|
@@ -47583,7 +47851,7 @@ async function scanFiles(root) {
|
|
|
47583
47851
|
skipped.push(`${path} (unsupported name)`);
|
|
47584
47852
|
continue;
|
|
47585
47853
|
}
|
|
47586
|
-
const info = await
|
|
47854
|
+
const info = await stat3(join9(directory, entry.name));
|
|
47587
47855
|
if (info.size > CLOUD_OBJECT_MAX_BYTES) {
|
|
47588
47856
|
skipped.push(`${path} (larger than ${CLOUD_OBJECT_MAX_BYTES / 1024 ** 3} GB)`);
|
|
47589
47857
|
continue;
|
|
@@ -47592,7 +47860,7 @@ async function scanFiles(root) {
|
|
|
47592
47860
|
tooLarge.push(safe);
|
|
47593
47861
|
continue;
|
|
47594
47862
|
}
|
|
47595
|
-
files.set(safe, { path: safe, absolute:
|
|
47863
|
+
files.set(safe, { path: safe, absolute: join9(directory, entry.name), size: info.size, mtimeMs: info.mtimeMs, mode: executable(info.mode) ? "100755" : "100644" });
|
|
47596
47864
|
if (files.size > CLOUD_MAX_FILES) throw new Error(`Cloud sync supports up to ${CLOUD_MAX_FILES} files. Add generated folders to .animaguruignore.`);
|
|
47597
47865
|
}
|
|
47598
47866
|
}
|
|
@@ -47624,7 +47892,7 @@ async function describeFiles(context, scanned) {
|
|
|
47624
47892
|
const sha256 = await fileSha256(file2.absolute);
|
|
47625
47893
|
local.set(file2.path, { oid: (await import_isomorphic_git.default.hashBlob({ object: cloudPointer(sha256, file2.size) })).oid, mode: file2.mode, size: file2.size, mtimeMs: file2.mtimeMs, sha256 });
|
|
47626
47894
|
} else {
|
|
47627
|
-
local.set(file2.path, { oid: (await import_isomorphic_git.default.hashBlob({ object: await
|
|
47895
|
+
local.set(file2.path, { oid: (await import_isomorphic_git.default.hashBlob({ object: await readFile8(file2.absolute) })).oid, mode: file2.mode, size: file2.size, mtimeMs: file2.mtimeMs });
|
|
47628
47896
|
}
|
|
47629
47897
|
}
|
|
47630
47898
|
return local;
|
|
@@ -47688,14 +47956,14 @@ ${entries.join(",\n")}
|
|
|
47688
47956
|
}}
|
|
47689
47957
|
`;
|
|
47690
47958
|
}
|
|
47691
|
-
async function token(context,
|
|
47692
|
-
const result = await context.client.request(`/api/v1/cloud/${context.link.projectId}/token`, { method: "POST", body: { access:
|
|
47959
|
+
async function token(context, access4) {
|
|
47960
|
+
const result = await context.client.request(`/api/v1/cloud/${context.link.projectId}/token`, { method: "POST", body: { access: access4 } });
|
|
47693
47961
|
const remote = new URL(result.remote);
|
|
47694
47962
|
if (remote.protocol !== "https:" && !(remote.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(remote.hostname))) throw new Error("The server returned an unsafe cloud remote.");
|
|
47695
47963
|
return { ...result, onAuth: () => ({ username: "x", password: result.token.split("?expires=")[0] }) };
|
|
47696
47964
|
}
|
|
47697
47965
|
async function ensureRepo(gitdir) {
|
|
47698
|
-
if (await exists(
|
|
47966
|
+
if (await exists(join9(gitdir, "HEAD"))) return;
|
|
47699
47967
|
await import_isomorphic_git.default.init({ fs, gitdir, bare: true, defaultBranch: CLOUD_BRANCH });
|
|
47700
47968
|
await import_isomorphic_git.default.setConfig({ fs, gitdir, path: "remote.origin.fetch", value: `+refs/heads/${CLOUD_BRANCH}:refs/remotes/origin/${CLOUD_BRANCH}` });
|
|
47701
47969
|
}
|
|
@@ -47761,12 +48029,12 @@ async function target(root, path) {
|
|
|
47761
48029
|
if (builtIn.ignores(path)) throw new Error(`Refusing to write ${path}: cloud sync never writes ignored or secret files.`);
|
|
47762
48030
|
let current = root;
|
|
47763
48031
|
for (const part of parts.slice(0, -1)) {
|
|
47764
|
-
current =
|
|
48032
|
+
current = join9(current, part);
|
|
47765
48033
|
const info2 = await lstat(current).catch(() => null);
|
|
47766
|
-
if (!info2) await
|
|
48034
|
+
if (!info2) await mkdir8(current);
|
|
47767
48035
|
else if (info2.isSymbolicLink() || !info2.isDirectory()) throw new Error(`Cannot write ${path}: ${part} is not a folder.`);
|
|
47768
48036
|
}
|
|
47769
|
-
const file2 =
|
|
48037
|
+
const file2 = join9(current, parts.at(-1));
|
|
47770
48038
|
const info = await lstat(file2).catch(() => null);
|
|
47771
48039
|
if (info && !info.isFile()) throw new Error(`Cannot replace ${path}: it is a link or folder.`);
|
|
47772
48040
|
return file2;
|
|
@@ -47792,7 +48060,7 @@ async function materialize(context, path, entry) {
|
|
|
47792
48060
|
} else await writeFile7(temp, blob2, { mode: 420 });
|
|
47793
48061
|
await chmod3(temp, entry.mode === "100755" ? 493 : 420);
|
|
47794
48062
|
await rename4(temp, file2);
|
|
47795
|
-
const info = await
|
|
48063
|
+
const info = await stat3(file2);
|
|
47796
48064
|
return { ...entry, size: info.size, mtimeMs: info.mtimeMs, ...pointer ? { sha256: pointer.sha256 } : {} };
|
|
47797
48065
|
} catch (error62) {
|
|
47798
48066
|
await rm2(temp, { force: true });
|
|
@@ -47800,10 +48068,10 @@ async function materialize(context, path, entry) {
|
|
|
47800
48068
|
}
|
|
47801
48069
|
}
|
|
47802
48070
|
async function backup(context, folder, path) {
|
|
47803
|
-
const source =
|
|
48071
|
+
const source = join9(context.root, path);
|
|
47804
48072
|
if (!await exists(source)) return;
|
|
47805
|
-
const destination =
|
|
47806
|
-
await
|
|
48073
|
+
const destination = join9(context.root, SYNC_DIR, "backups", folder, path);
|
|
48074
|
+
await mkdir8(dirname7(destination), { recursive: true });
|
|
47807
48075
|
await fs.promises.copyFile(source, destination);
|
|
47808
48076
|
}
|
|
47809
48077
|
async function remove(context, path) {
|
|
@@ -47823,24 +48091,24 @@ async function apply(context, local, writes, deletes) {
|
|
|
47823
48091
|
}
|
|
47824
48092
|
async function linkCloud(client, options) {
|
|
47825
48093
|
const root = await cloudRootFor(options.dir);
|
|
47826
|
-
if (await exists(
|
|
48094
|
+
if (await exists(join9(root, LINK_FILE))) throw new Error(`This folder is already linked. Run animaguru cloud status, or animaguru cloud unlink first.`);
|
|
47827
48095
|
const id2 = options.project ?? (await client.request("/api/v1/sprites", { method: "POST", body: { owner: options.workspace, name: (options.name ?? root.split(/[\\/]/).pop() ?? "Animations").slice(0, 80) } })).project.id;
|
|
47828
48096
|
const { project } = await client.request("/api/v1/cloud", { method: "POST", body: { project: id2 } });
|
|
47829
|
-
await writeJson2(
|
|
48097
|
+
await writeJson2(join9(root, LINK_FILE), { schemaVersion: 1, origin: client.origin, projectId: project.id, name: project.name, workspace: project.workspaceId });
|
|
47830
48098
|
await keepOutOfGit(root);
|
|
47831
48099
|
return { project, path: root, nextSteps: project.head ? ["Run animaguru cloud pull to combine the cloud versions with this folder."] : ['Run animaguru cloud push -m "First version" to save the first version.'] };
|
|
47832
48100
|
}
|
|
47833
48101
|
async function keepOutOfGit(root) {
|
|
47834
|
-
const path =
|
|
47835
|
-
const text2 = await
|
|
48102
|
+
const path = join9(root, ".gitignore");
|
|
48103
|
+
const text2 = await readFile8(path, "utf8").catch(() => null);
|
|
47836
48104
|
if (text2 !== null && !/^\/?\.animaguru\/(?:sync\/?)?$/m.test(text2)) await writeFile7(path, `${text2}${text2.endsWith("\n") || !text2 ? "" : "\n"}.animaguru/sync/
|
|
47837
48105
|
`);
|
|
47838
48106
|
}
|
|
47839
48107
|
async function unlinkCloud(options) {
|
|
47840
48108
|
const root = await cloudRootFor(options.dir);
|
|
47841
|
-
if (!await exists(
|
|
48109
|
+
if (!await exists(join9(root, LINK_FILE))) throw new Error("This folder is not linked to a project.");
|
|
47842
48110
|
await withLock(root, async () => {
|
|
47843
|
-
for (const name2 of ["link.json", "state.json", "repo.git"]) await rm2(
|
|
48111
|
+
for (const name2 of ["link.json", "state.json", "repo.git"]) await rm2(join9(root, SYNC_DIR, name2), { recursive: true, force: true });
|
|
47844
48112
|
});
|
|
47845
48113
|
return { unlinked: true, path: root, note: "The project's animations and versions were not changed." };
|
|
47846
48114
|
}
|
|
@@ -47890,13 +48158,13 @@ async function pushCloud(options) {
|
|
|
47890
48158
|
if (!local.size) throw new Error("There are no files to save.");
|
|
47891
48159
|
for (const [path, entry] of local) {
|
|
47892
48160
|
if (base2.get(path)?.oid === entry.oid) continue;
|
|
47893
|
-
const bytes = entry.sha256 ? new TextEncoder().encode(cloudPointer(entry.sha256, entry.size)) : await
|
|
48161
|
+
const bytes = entry.sha256 ? new TextEncoder().encode(cloudPointer(entry.sha256, entry.size)) : await readFile8(join9(context.root, path));
|
|
47894
48162
|
if (await import_isomorphic_git.default.writeBlob({ fs, gitdir: context.gitdir, blob: bytes }) !== entry.oid) throw new Error(`${path} changed while saving. Run the push again.`);
|
|
47895
48163
|
}
|
|
47896
|
-
const uploaded = await uploadObjects(context, local, (path) =>
|
|
48164
|
+
const uploaded = await uploadObjects(context, local, (path) => join9(context.root, path));
|
|
47897
48165
|
for (const [path, entry] of local) {
|
|
47898
48166
|
if (!entry.sha256 || base2.get(path)?.oid === entry.oid) continue;
|
|
47899
|
-
const info = await
|
|
48167
|
+
const info = await stat3(join9(context.root, path));
|
|
47900
48168
|
if (info.size !== entry.size || info.mtimeMs !== entry.mtimeMs) throw new Error(`${path} changed while saving. Run the push again.`);
|
|
47901
48169
|
}
|
|
47902
48170
|
const tree = await writeTree(context.gitdir, local, manifestText(local));
|
|
@@ -47971,10 +48239,10 @@ async function pullCloud(options) {
|
|
|
47971
48239
|
async function cloneCloud(client, options) {
|
|
47972
48240
|
const { project } = await client.request(`/api/v1/cloud/${encodeURIComponent(options.id)}`);
|
|
47973
48241
|
if (!project) throw new Error("This project has no synced animations yet. Link a folder with animaguru cloud link --project ID, then push.");
|
|
47974
|
-
const root =
|
|
47975
|
-
if (await exists(root) && (await
|
|
47976
|
-
await
|
|
47977
|
-
await writeJson2(
|
|
48242
|
+
const root = resolve9(options.dir ?? (project.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || project.id));
|
|
48243
|
+
if (await exists(root) && (await readdir5(root)).length) throw new Error(`Destination is not empty: ${root}. Choose a new folder; existing files were not changed.`);
|
|
48244
|
+
await mkdir8(root, { recursive: true });
|
|
48245
|
+
await writeJson2(join9(root, LINK_FILE), { schemaVersion: 1, origin: client.origin, projectId: project.id, name: project.name, workspace: project.workspaceId });
|
|
47978
48246
|
const pulled = await pullCloud({ ...options, dir: root });
|
|
47979
48247
|
return { project, path: root, version: pulled.version, files: "written" in pulled ? pulled.written : 0, nextSteps: ["Run npm install in the folder before previewing or exporting."] };
|
|
47980
48248
|
}
|
|
@@ -48024,8 +48292,8 @@ function sharingEmails(value) {
|
|
|
48024
48292
|
return value ? value.split(",").map((email3) => email3.trim()).filter(Boolean) : [];
|
|
48025
48293
|
}
|
|
48026
48294
|
async function exportHtml(root, animation, signal, log) {
|
|
48027
|
-
const script =
|
|
48028
|
-
await
|
|
48295
|
+
const script = join10(root, "scripts/export-html.mjs");
|
|
48296
|
+
await stat4(script).catch(() => {
|
|
48029
48297
|
throw new Error("Choose an AnimaGuru video project, or pass --file for an exported HTML5 ZIP or MP4.");
|
|
48030
48298
|
});
|
|
48031
48299
|
log?.("Building the portable HTML5 animation\u2026");
|
|
@@ -48058,23 +48326,23 @@ async function exportHtml(root, animation, signal, log) {
|
|
|
48058
48326
|
async function submitVideo(client, options) {
|
|
48059
48327
|
if (!options.yes && !options["dry-run"]) throw new Error("Pass --yes to authorize uploading and sharing this animation, or --dry-run to inspect the submission.");
|
|
48060
48328
|
const workspace3 = options.workspace === void 0 ? void 0 : libraryWorkspace(options.workspace);
|
|
48061
|
-
const root =
|
|
48329
|
+
const root = resolve10(options.directory ?? ".");
|
|
48062
48330
|
const context = await localProject(root, options.animation);
|
|
48063
|
-
const file2 = options.file ?
|
|
48064
|
-
const info = await
|
|
48331
|
+
const file2 = options.file ? resolve10(root, options.file) : await exportHtml(context.toolsRoot, context.animation, options.signal, options.log);
|
|
48332
|
+
const info = await stat4(file2);
|
|
48065
48333
|
const format = file2.toLowerCase().endsWith(".zip") ? "html5" : file2.toLowerCase().endsWith(".mp4") ? "mp4" : null;
|
|
48066
48334
|
if (!info.isFile() || !format) throw new Error("Submit an AnimaGuru HTML5 .zip export or an .mp4 file.");
|
|
48067
48335
|
videoSubmission.parse({ title: options.title ?? "Video", format, bytes: info.size });
|
|
48068
48336
|
let metadata = {};
|
|
48069
48337
|
let receipt = {};
|
|
48070
48338
|
if (format === "html5") {
|
|
48071
|
-
const files = unzipSync(new Uint8Array(await
|
|
48339
|
+
const files = unzipSync(new Uint8Array(await readFile9(file2)), { filter: (entry) => entry.name === "manifest.json" && entry.originalSize <= 256 * 1024 });
|
|
48072
48340
|
if (!files["manifest.json"]) throw new Error("Use an AnimaGuru HTML5 export with manifest.json.");
|
|
48073
48341
|
metadata = JSON.parse(strFromU8(files["manifest.json"]));
|
|
48074
48342
|
if (metadata.format !== "spriteguru-html5" || metadata.version !== 1) throw new Error("Use an AnimaGuru HTML5 export.");
|
|
48075
48343
|
} else {
|
|
48076
48344
|
try {
|
|
48077
|
-
metadata = JSON.parse(await
|
|
48345
|
+
metadata = JSON.parse(await readFile9(join10(context.projectRoot, "film.config.json"), "utf8"));
|
|
48078
48346
|
} catch {
|
|
48079
48347
|
}
|
|
48080
48348
|
const handle2 = await open4(file2, "r");
|
|
@@ -48117,10 +48385,10 @@ async function submitVideo(client, options) {
|
|
|
48117
48385
|
}
|
|
48118
48386
|
let poster;
|
|
48119
48387
|
if (options.poster) {
|
|
48120
|
-
const path =
|
|
48121
|
-
const info2 = await
|
|
48388
|
+
const path = resolve10(root, options.poster);
|
|
48389
|
+
const info2 = await stat4(path);
|
|
48122
48390
|
if (!info2.isFile() || info2.size > 2 * 1024 * 1024) throw new Error("Poster must be a PNG, JPEG or WebP up to 2 MiB.");
|
|
48123
|
-
poster = await
|
|
48391
|
+
poster = await readFile9(path);
|
|
48124
48392
|
videoPosterType(poster);
|
|
48125
48393
|
}
|
|
48126
48394
|
if (options["dry-run"]) return { dryRun: true, file: file2, submission: body, poster: options.poster ?? null, subtitles: subtitles && { file: subtitles.file, language: subtitles.language } };
|
|
@@ -48170,7 +48438,7 @@ async function changeVideoSubtitles(client, id2, options) {
|
|
|
48170
48438
|
return client.request(path + encodeURIComponent(options.remove), { method: "DELETE" });
|
|
48171
48439
|
}
|
|
48172
48440
|
if (!options.file) throw new Error("Pass --file with a .srt or .vtt subtitle file, or --remove LANGUAGE.");
|
|
48173
|
-
const file2 =
|
|
48441
|
+
const file2 = resolve10(options.file);
|
|
48174
48442
|
const { content, language: header } = await readSubtitleFile(file2, SUBTITLE_MAX_BYTES);
|
|
48175
48443
|
const language = subtitleLanguage.safeParse(options.language ?? header ?? (await exportReceipt(file2.replace(/\.(?:srt|vtt)$/i, ".mp4"))).language);
|
|
48176
48444
|
if (!language.success) throw new Error("Pass --language with the subtitles' language code, such as en or tr.");
|
|
@@ -48204,8 +48472,8 @@ async function moveVideos(client, ids, options) {
|
|
|
48204
48472
|
}
|
|
48205
48473
|
|
|
48206
48474
|
// cli/src/assets.ts
|
|
48207
|
-
import { mkdir as
|
|
48208
|
-
import { dirname as
|
|
48475
|
+
import { mkdir as mkdir9, readFile as readFile10, stat as stat5, writeFile as writeFile8 } from "node:fs/promises";
|
|
48476
|
+
import { dirname as dirname8, join as join11, resolve as resolve11 } from "node:path";
|
|
48209
48477
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
48210
48478
|
var extras = {
|
|
48211
48479
|
image: ["aspect-ratio", "transparent", "references", "mask"],
|
|
@@ -48242,7 +48510,9 @@ var extras = {
|
|
|
48242
48510
|
],
|
|
48243
48511
|
music: [],
|
|
48244
48512
|
speech: ["voice", "delivery"],
|
|
48245
|
-
sfx: ["seconds", "loop", "prompt-influence"]
|
|
48513
|
+
sfx: ["seconds", "loop", "prompt-influence"],
|
|
48514
|
+
model: ["reference", "texture", "pbr", "faces", "rig", "animations", "height"],
|
|
48515
|
+
vector: ["workflow", "references", "source", "aspect-ratio", "quality", "shapes", "seed"]
|
|
48246
48516
|
};
|
|
48247
48517
|
var list2 = (items) => items.length < 2 ? items.join("") : `${items.slice(0, -1).join(", ")} and ${items.at(-1)}`;
|
|
48248
48518
|
function accepted(type) {
|
|
@@ -48263,6 +48533,7 @@ var regions = (value) => value?.split(";").filter((region) => region.trim()).map
|
|
|
48263
48533
|
if (rest.length || [x2, y, width, height].some((n) => !Number.isFinite(n))) throw new Error(`--mask regions are x,y,width,height in fractions of Image 1, separated by semicolons; "${region.trim()}" is not.`);
|
|
48264
48534
|
return { x: x2, y, width, height };
|
|
48265
48535
|
});
|
|
48536
|
+
var clips = (value) => value?.split(",").map((clip) => clip.trim()).filter(Boolean).map((clip) => /^\d+$/.test(clip) ? Number(clip) : clip);
|
|
48266
48537
|
var cameraKeyframes = (value) => value?.split(";").filter((frame) => frame.trim()).map((frame) => {
|
|
48267
48538
|
const [time3, azimuth, elevation, distance, ...rest] = frame.split(",").map((n) => n.trim() ? Number(n) : NaN);
|
|
48268
48539
|
if (rest.length || [time3, azimuth, elevation, distance].some((n) => !Number.isFinite(n))) throw new Error(`--camera keyframes are time,azimuth,elevation,distance (time 0\u20131, angles in degrees), separated by semicolons; "${frame.trim()}" is not.`);
|
|
@@ -48277,9 +48548,10 @@ function assetFromFlags(flags) {
|
|
|
48277
48548
|
if (flags.type === "image" && flags.model) throw new Error("Image models are managed by staff. Omit --model.");
|
|
48278
48549
|
for (const name2 of Object.values(extras).flat()) {
|
|
48279
48550
|
const value = flags[name2];
|
|
48280
|
-
|
|
48551
|
+
const given2 = value !== void 0 && (value !== false || (name2 === "texture" || name2 === "pbr") && flags.type !== "model");
|
|
48552
|
+
if (given2 && !extras[flags.type]?.includes(name2)) throw new Error(`--${name2} is not an option for ${flags.type} assets. ${accepted(flags.type)}`.trim());
|
|
48281
48553
|
}
|
|
48282
|
-
if (flags.type !== "video" && flags.prompt === void 0) throw new Error(`--prompt is required for ${flags.type} assets.`);
|
|
48554
|
+
if (flags.type !== "video" && flags.type !== "vector" && !(flags.type === "model" && flags.reference) && flags.prompt === void 0) throw new Error(`--prompt is required for ${flags.type} assets${flags.type === "model" ? " unless --reference names an image to build from" : ""}.`);
|
|
48283
48555
|
const base2 = { type: flags.type, name: flags.name, prompt: flags.prompt, model: flags.model };
|
|
48284
48556
|
if (flags.type === "image") return parseAsset({ ...base2, aspectRatio: flags["aspect-ratio"], transparent: flags.transparent, references: shas(flags.references), mask: regions(flags.mask) });
|
|
48285
48557
|
if (flags.type === "video") {
|
|
@@ -48317,10 +48589,12 @@ function assetFromFlags(flags) {
|
|
|
48317
48589
|
});
|
|
48318
48590
|
}
|
|
48319
48591
|
if (flags.type === "sfx") return parseAsset({ ...base2, seconds: flags.seconds, loop: flags.loop, promptInfluence: flags["prompt-influence"] });
|
|
48592
|
+
if (flags.type === "model") return parseAsset({ ...base2, reference: flags.reference, texture: flags.texture, pbr: flags.pbr, faces: flags.faces, rig: flags.rig, animations: clips(flags.animations), height: flags.height });
|
|
48593
|
+
if (flags.type === "vector") return parseAsset({ ...base2, workflow: flags.workflow, quality: flags.quality, aspectRatio: flags["aspect-ratio"], references: shas(flags.references), source: flags.source, shapes: flags.shapes, seed: flags.seed });
|
|
48320
48594
|
return parseAsset({ ...base2, ...flags.type === "speech" ? { voice: flags.voice, delivery: flags.delivery } : {} });
|
|
48321
48595
|
}
|
|
48322
48596
|
async function assetFromFile(file2, model) {
|
|
48323
|
-
const input2 = JSON.parse(await
|
|
48597
|
+
const input2 = JSON.parse(await readFile10(file2, "utf8"));
|
|
48324
48598
|
if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) throw new Error("The asset file must contain a JSON object.");
|
|
48325
48599
|
return parseAsset({ ...input2, ...model ? { model } : {} });
|
|
48326
48600
|
}
|
|
@@ -48328,7 +48602,7 @@ var MAX_BATCH = 50;
|
|
|
48328
48602
|
var isObject2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
48329
48603
|
var fileName = (name2) => name2.normalize("NFKD").replace(/[^\w.-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
|
|
48330
48604
|
async function assetsFromBatchFile(file2, model) {
|
|
48331
|
-
const input2 = JSON.parse(await
|
|
48605
|
+
const input2 = JSON.parse(await readFile10(file2, "utf8"));
|
|
48332
48606
|
let defaults = {};
|
|
48333
48607
|
let items;
|
|
48334
48608
|
if (Array.isArray(input2)) items = input2;
|
|
@@ -48412,19 +48686,21 @@ var MIME_EXTENSIONS = {
|
|
|
48412
48686
|
"image/png": "png",
|
|
48413
48687
|
"image/jpeg": "jpg",
|
|
48414
48688
|
"image/webp": "webp",
|
|
48689
|
+
"image/svg+xml": "svg",
|
|
48415
48690
|
"video/mp4": "mp4",
|
|
48416
|
-
"video/webm": "webm"
|
|
48691
|
+
"video/webm": "webm",
|
|
48692
|
+
"model/gltf-binary": "glb"
|
|
48417
48693
|
};
|
|
48418
48694
|
var extensionFor = (asset) => MIME_EXTENSIONS[asset.mimeType?.split(";")[0].trim().toLowerCase()] ?? /\.([a-z0-9]{1,5})$/i.exec(asset.file ?? "")?.[1]?.toLowerCase() ?? "bin";
|
|
48419
48695
|
async function downloadTarget(output2, asset, folder = false) {
|
|
48420
|
-
const path =
|
|
48421
|
-
const isFolder = folder || /[\\/]$/.test(output2) || await
|
|
48696
|
+
const path = resolve11(output2);
|
|
48697
|
+
const isFolder = folder || /[\\/]$/.test(output2) || await stat5(path).then((info) => info.isDirectory(), () => false);
|
|
48422
48698
|
if (!isFolder) {
|
|
48423
|
-
await
|
|
48699
|
+
await mkdir9(dirname8(path), { recursive: true });
|
|
48424
48700
|
return path;
|
|
48425
48701
|
}
|
|
48426
|
-
await
|
|
48427
|
-
return
|
|
48702
|
+
await mkdir9(path, { recursive: true });
|
|
48703
|
+
return join11(path, `${fileName(asset.name) || asset.id}.${extensionFor(asset)}`);
|
|
48428
48704
|
}
|
|
48429
48705
|
async function saveAsset(client, library, asset, path) {
|
|
48430
48706
|
if (!library.ownerId || !/^[a-f0-9]{64}$/.test(asset.file)) throw new Error("Invalid asset download metadata.");
|
|
@@ -48448,7 +48724,7 @@ async function downloadAsset(client, project, assetId, output2) {
|
|
|
48448
48724
|
const library = await client.request(assetsPath(project));
|
|
48449
48725
|
const asset = library.assets.find((a) => a.id === assetId);
|
|
48450
48726
|
if (!asset) throw new Error("Asset not found in this project. Run assets list to find its id.");
|
|
48451
|
-
return saveAsset(client, library, asset,
|
|
48727
|
+
return saveAsset(client, library, asset, resolve11(output2));
|
|
48452
48728
|
}
|
|
48453
48729
|
async function generateAsset(client, project, body, options, signal) {
|
|
48454
48730
|
const waiting = !options["dry-run"] && Boolean(options.wait || options.download);
|
|
@@ -48525,7 +48801,7 @@ async function submitAssetBatch(client, project, requests, options, signal) {
|
|
|
48525
48801
|
}
|
|
48526
48802
|
|
|
48527
48803
|
// cli/src/avatars.ts
|
|
48528
|
-
import { readFile as
|
|
48804
|
+
import { readFile as readFile11, stat as stat6 } from "node:fs/promises";
|
|
48529
48805
|
import { extname } from "node:path";
|
|
48530
48806
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
48531
48807
|
|
|
@@ -48631,8 +48907,8 @@ async function avatarFile2(value) {
|
|
|
48631
48907
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value)) throw new Error("Use an HTTPS URL, a project file SHA or a local file.");
|
|
48632
48908
|
const mediaType = MEDIA_TYPES[extname(value).toLowerCase()];
|
|
48633
48909
|
if (!mediaType) throw new Error("Use a PNG, JPEG or WebP image, or MP4, MOV or WebM footage.");
|
|
48634
|
-
if ((await
|
|
48635
|
-
return { type: "base64", mediaType, data: (await
|
|
48910
|
+
if ((await stat6(value)).size > AVATAR_INLINE_MAX_BYTES) throw new Error("Local files must be at most 8 MB. Use an HTTPS URL for larger footage.");
|
|
48911
|
+
return { type: "base64", mediaType, data: (await readFile11(value)).toString("base64") };
|
|
48636
48912
|
}
|
|
48637
48913
|
async function avatarFromFlags(flags) {
|
|
48638
48914
|
const prompt = flags.type === "prompt";
|
|
@@ -48680,11 +48956,11 @@ async function waitForLook(client, project, lookId, timeout, signal, interval =
|
|
|
48680
48956
|
// cli/src/youtube-auth.ts
|
|
48681
48957
|
import { createServer } from "node:http";
|
|
48682
48958
|
import { randomBytes, createHash as createHash5, timingSafeEqual } from "node:crypto";
|
|
48683
|
-
import { readFile as
|
|
48959
|
+
import { readFile as readFile13, stat as stat7 } from "node:fs/promises";
|
|
48684
48960
|
|
|
48685
48961
|
// cli/src/youtube-store.ts
|
|
48686
|
-
import { chmod as chmod4, lstat as lstat2, mkdir as
|
|
48687
|
-
import { dirname as
|
|
48962
|
+
import { chmod as chmod4, lstat as lstat2, mkdir as mkdir10, open as open5, readFile as readFile12, readdir as readdir6, rename as rename5, unlink, writeFile as writeFile9 } from "node:fs/promises";
|
|
48963
|
+
import { dirname as dirname9, join as join12 } from "node:path";
|
|
48688
48964
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
48689
48965
|
function refuseInAnimator() {
|
|
48690
48966
|
if (process.env.ANIMAGURU_CLOUD_WORKSPACE) throw new Error("YouTube uploads are not available in the cloud Animator. The user exports the MP4 from the draft page in their browser, then uploads it under Publishing \u2192 YouTube.");
|
|
@@ -48742,14 +49018,14 @@ var youtubeJob = external_exports.object({
|
|
|
48742
49018
|
captions: youtubeCaptions.optional(),
|
|
48743
49019
|
thumbnail: youtubeThumbnail.optional()
|
|
48744
49020
|
}).strict();
|
|
48745
|
-
var youtubeDirectory = () =>
|
|
48746
|
-
var credentialFile = () =>
|
|
49021
|
+
var youtubeDirectory = () => join12(dirname9(credentialsPath()), "youtube");
|
|
49022
|
+
var credentialFile = () => join12(youtubeDirectory(), "credentials.json");
|
|
48747
49023
|
function jobFile(id2) {
|
|
48748
49024
|
if (!external_exports.uuid().safeParse(id2).success) throw new Error("Use an upload ID returned by animaguru youtube uploads list.");
|
|
48749
|
-
return
|
|
49025
|
+
return join12(youtubeDirectory(), "uploads", `${id2}.json`);
|
|
48750
49026
|
}
|
|
48751
49027
|
async function privateDirectory(directory) {
|
|
48752
|
-
await
|
|
49028
|
+
await mkdir10(directory, { recursive: true, mode: 448 });
|
|
48753
49029
|
const info = await lstat2(directory);
|
|
48754
49030
|
if (info.isSymbolicLink() || !info.isDirectory()) throw new Error("YouTube configuration must use a real directory.");
|
|
48755
49031
|
await chmod4(directory, 448);
|
|
@@ -48766,11 +49042,11 @@ async function existingDirectory(directory) {
|
|
|
48766
49042
|
}
|
|
48767
49043
|
async function readPrivate(file2) {
|
|
48768
49044
|
try {
|
|
48769
|
-
if (!await existingDirectory(youtubeDirectory()) || !await existingDirectory(
|
|
49045
|
+
if (!await existingDirectory(youtubeDirectory()) || !await existingDirectory(dirname9(file2))) return null;
|
|
48770
49046
|
const info = await lstat2(file2);
|
|
48771
49047
|
if (info.isSymbolicLink() || !info.isFile() || info.size > 65536) throw new Error("Invalid local YouTube state file.");
|
|
48772
49048
|
await chmod4(file2, 384);
|
|
48773
|
-
return JSON.parse(await
|
|
49049
|
+
return JSON.parse(await readFile12(file2, "utf8"));
|
|
48774
49050
|
} catch (error62) {
|
|
48775
49051
|
if (error62.code === "ENOENT") return null;
|
|
48776
49052
|
throw new Error("Cannot read local YouTube state. Check your AnimaGuru configuration directory.");
|
|
@@ -48778,7 +49054,7 @@ async function readPrivate(file2) {
|
|
|
48778
49054
|
}
|
|
48779
49055
|
async function writePrivate(file2, value) {
|
|
48780
49056
|
await privateDirectory(youtubeDirectory());
|
|
48781
|
-
await privateDirectory(
|
|
49057
|
+
await privateDirectory(dirname9(file2));
|
|
48782
49058
|
const temporary = `${file2}.${randomUUID3()}.tmp`;
|
|
48783
49059
|
try {
|
|
48784
49060
|
await writeFile9(temporary, JSON.stringify(value) + "\n", { flag: "wx", mode: 384 });
|
|
@@ -48810,11 +49086,11 @@ function youtubeJobSummary(job) {
|
|
|
48810
49086
|
return { id: job.id, file: job.file, title: job.metadata.title, channelId: job.channelId, status: job.status, bytes: job.bytes, bytesUploaded: job.bytesUploaded, privacy: job.privacy, youtubeId: job.youtubeId, url: job.youtubeId ? `https://www.youtube.com/watch?v=${job.youtubeId}` : null, createdAt: job.createdAt, captions: job.captions ? { file: job.captions.file, language: job.captions.language, name: job.captions.name, status: job.captions.status } : null, thumbnail: job.thumbnail ? { file: job.thumbnail.file, status: job.thumbnail.status } : null };
|
|
48811
49087
|
}
|
|
48812
49088
|
async function localYouTubeJobs() {
|
|
48813
|
-
const directory =
|
|
49089
|
+
const directory = join12(youtubeDirectory(), "uploads");
|
|
48814
49090
|
if (!await existingDirectory(directory)) return [];
|
|
48815
49091
|
let files;
|
|
48816
49092
|
try {
|
|
48817
|
-
files = await
|
|
49093
|
+
files = await readdir6(directory);
|
|
48818
49094
|
} catch (error62) {
|
|
48819
49095
|
if (error62.code === "ENOENT") return [];
|
|
48820
49096
|
throw error62;
|
|
@@ -48831,10 +49107,10 @@ async function clearYouTubeData() {
|
|
|
48831
49107
|
await unlink(credentialFile()).catch((error62) => {
|
|
48832
49108
|
if (error62.code !== "ENOENT") throw error62;
|
|
48833
49109
|
});
|
|
48834
|
-
if (!await existingDirectory(
|
|
49110
|
+
if (!await existingDirectory(join12(youtubeDirectory(), "uploads"))) return;
|
|
48835
49111
|
let files;
|
|
48836
49112
|
try {
|
|
48837
|
-
files = await
|
|
49113
|
+
files = await readdir6(join12(youtubeDirectory(), "uploads"));
|
|
48838
49114
|
} catch (error62) {
|
|
48839
49115
|
if (error62.code === "ENOENT") return;
|
|
48840
49116
|
throw error62;
|
|
@@ -48844,7 +49120,7 @@ async function clearYouTubeData() {
|
|
|
48844
49120
|
async function withYouTubeLock(operation) {
|
|
48845
49121
|
refuseInAnimator();
|
|
48846
49122
|
await privateDirectory(youtubeDirectory());
|
|
48847
|
-
const file2 =
|
|
49123
|
+
const file2 = join12(youtubeDirectory(), "operation.lock");
|
|
48848
49124
|
const lock = await open5(file2, "wx", 384).catch((error62) => {
|
|
48849
49125
|
if (error62.code === "EEXIST") throw new Error(`Another YouTube command is running. If a previous command was killed, verify it has stopped before removing ${file2}.`);
|
|
48850
49126
|
throw error62;
|
|
@@ -48992,11 +49268,11 @@ async function youtubeLogin(options) {
|
|
|
48992
49268
|
if (existing && options.captions && !canAddCaptions(existing)) throw new Error("A YouTube channel is already connected without caption permission. Run youtube auth logout --yes, then youtube auth login --captions.");
|
|
48993
49269
|
if (existing) throw new Error("A YouTube channel is already connected. Run youtube auth logout --yes before switching channels.");
|
|
48994
49270
|
const file2 = options["client-file"];
|
|
48995
|
-
const info = await
|
|
49271
|
+
const info = await stat7(file2);
|
|
48996
49272
|
if (!info.isFile() || info.size > 65536) throw new Error("Use Google's downloaded Desktop app OAuth client JSON.");
|
|
48997
49273
|
let installed;
|
|
48998
49274
|
try {
|
|
48999
|
-
installed = JSON.parse(await
|
|
49275
|
+
installed = JSON.parse(await readFile13(file2, "utf8")).installed;
|
|
49000
49276
|
} catch {
|
|
49001
49277
|
}
|
|
49002
49278
|
if (!installed || typeof installed.client_id !== "string" || !installed.client_id.endsWith(".apps.googleusercontent.com") || installed.client_secret !== void 0 && typeof installed.client_secret !== "string") throw new Error("Use Google's Desktop app OAuth client JSON (installed), not a web client or API key.");
|
|
@@ -49006,8 +49282,8 @@ async function youtubeLogin(options) {
|
|
|
49006
49282
|
let receive;
|
|
49007
49283
|
let fail;
|
|
49008
49284
|
let used = false;
|
|
49009
|
-
const callback = new Promise((
|
|
49010
|
-
receive =
|
|
49285
|
+
const callback = new Promise((resolve19, reject) => {
|
|
49286
|
+
receive = resolve19;
|
|
49011
49287
|
fail = reject;
|
|
49012
49288
|
});
|
|
49013
49289
|
void callback.catch(() => {
|
|
@@ -49045,9 +49321,9 @@ async function youtubeLogin(options) {
|
|
|
49045
49321
|
response.end("Authorization received. Return to your AnimaGuru terminal.");
|
|
49046
49322
|
receive(code);
|
|
49047
49323
|
});
|
|
49048
|
-
await new Promise((
|
|
49324
|
+
await new Promise((resolve19, reject) => {
|
|
49049
49325
|
server.once("error", reject);
|
|
49050
|
-
server.listen(0, "127.0.0.1",
|
|
49326
|
+
server.listen(0, "127.0.0.1", resolve19);
|
|
49051
49327
|
});
|
|
49052
49328
|
const address = server.address();
|
|
49053
49329
|
if (!address || typeof address === "string") throw new Error("Cannot open the local YouTube authorization listener.");
|
|
@@ -49082,7 +49358,7 @@ async function youtubeLogin(options) {
|
|
|
49082
49358
|
clearTimeout(timer);
|
|
49083
49359
|
options.signal?.removeEventListener("abort", abort);
|
|
49084
49360
|
server.closeAllConnections();
|
|
49085
|
-
await new Promise((
|
|
49361
|
+
await new Promise((resolve19) => server.close(() => resolve19()));
|
|
49086
49362
|
}
|
|
49087
49363
|
});
|
|
49088
49364
|
}
|
|
@@ -49113,8 +49389,8 @@ async function youtubeLogout(options) {
|
|
|
49113
49389
|
|
|
49114
49390
|
// cli/src/youtube-upload.ts
|
|
49115
49391
|
import { createHash as createHash6, randomUUID as randomUUID4 } from "node:crypto";
|
|
49116
|
-
import { open as open6, readFile as
|
|
49117
|
-
import { basename as basename5, join as
|
|
49392
|
+
import { open as open6, readFile as readFile14, stat as stat8 } from "node:fs/promises";
|
|
49393
|
+
import { basename as basename5, join as join13, resolve as resolve12 } from "node:path";
|
|
49118
49394
|
import { setTimeout as delay5 } from "node:timers/promises";
|
|
49119
49395
|
var YOUTUBE_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
49120
49396
|
function safeYouTubeSession(value) {
|
|
@@ -49165,23 +49441,23 @@ async function planCaptions(root, mp4, options, fallbackLanguage) {
|
|
|
49165
49441
|
async function readThumbnail(file2) {
|
|
49166
49442
|
let info;
|
|
49167
49443
|
try {
|
|
49168
|
-
info = await
|
|
49444
|
+
info = await stat8(file2);
|
|
49169
49445
|
} catch {
|
|
49170
49446
|
throw new Error(`Cannot read the thumbnail ${file2}.`);
|
|
49171
49447
|
}
|
|
49172
49448
|
if (!info.isFile() || info.size < 8 || info.size > 2 * 1024 * 1024) throw new Error("Use a JPEG or PNG thumbnail up to 2 MiB, such as the one npm run export:mp4 saves beside the MP4.");
|
|
49173
|
-
const content = await
|
|
49449
|
+
const content = await readFile14(file2);
|
|
49174
49450
|
const type = content[0] === 255 && content[1] === 216 && content[2] === 255 ? "image/jpeg" : content.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) ? "image/png" : null;
|
|
49175
49451
|
if (!type) throw new Error("Use a JPEG or PNG thumbnail.");
|
|
49176
49452
|
return { content, type, sha256: createHash6("sha256").update(content).digest("hex") };
|
|
49177
49453
|
}
|
|
49178
49454
|
async function planThumbnail(root, mp4, choice = "auto") {
|
|
49179
49455
|
if (choice === "none") return null;
|
|
49180
|
-
let file2 = choice === "auto" ? void 0 :
|
|
49456
|
+
let file2 = choice === "auto" ? void 0 : resolve12(root, choice);
|
|
49181
49457
|
if (!file2) {
|
|
49182
49458
|
for (const extension of [".jpg", ".jpeg", ".png"]) {
|
|
49183
49459
|
const candidate = mp4.replace(/\.mp4$/i, extension);
|
|
49184
|
-
if (await
|
|
49460
|
+
if (await stat8(candidate).then((info) => info.isFile(), () => false)) {
|
|
49185
49461
|
file2 = candidate;
|
|
49186
49462
|
break;
|
|
49187
49463
|
}
|
|
@@ -49366,12 +49642,12 @@ async function uploadYouTube(options) {
|
|
|
49366
49642
|
refuseInAnimator();
|
|
49367
49643
|
if (!options.yes && !options["dry-run"]) throw new Error("Pass --yes to authorize the YouTube upload, or --dry-run to inspect it locally.");
|
|
49368
49644
|
if (!["yes", "no"].includes(options["made-for-kids"]) || !["yes", "no"].includes(options["synthetic-media"])) throw new Error("Set --made-for-kids yes|no and --synthetic-media yes|no explicitly.");
|
|
49369
|
-
const root =
|
|
49370
|
-
const file2 =
|
|
49645
|
+
const root = resolve12(options.directory ?? ".");
|
|
49646
|
+
const file2 = resolve12(root, options.file);
|
|
49371
49647
|
const context = await localProject(root, options.animation);
|
|
49372
49648
|
let config2 = {};
|
|
49373
49649
|
try {
|
|
49374
|
-
config2 = JSON.parse(await
|
|
49650
|
+
config2 = JSON.parse(await readFile14(join13(context.projectRoot, "film.config.json"), "utf8"));
|
|
49375
49651
|
} catch {
|
|
49376
49652
|
}
|
|
49377
49653
|
const receipt = await exportReceipt(file2);
|
|
@@ -49448,8 +49724,8 @@ async function resumeYouTube(id2, options) {
|
|
|
49448
49724
|
var listYouTubeUploads = () => withYouTubeLock(async () => ({ uploads: (await localYouTubeJobs()).map(youtubeJobSummary) }));
|
|
49449
49725
|
|
|
49450
49726
|
// cli/src/motion.ts
|
|
49451
|
-
import { access as
|
|
49452
|
-
import { dirname as
|
|
49727
|
+
import { access as access3, mkdir as mkdir11, writeFile as writeFile10 } from "node:fs/promises";
|
|
49728
|
+
import { dirname as dirname10, join as join14, relative as relative2, resolve as resolve13, sep as sep2 } from "node:path";
|
|
49453
49729
|
|
|
49454
49730
|
// shared/motion-library.ts
|
|
49455
49731
|
var MOTION_CATEGORIES = [
|
|
@@ -49498,18 +49774,18 @@ async function searchMotion(client, query, flags) {
|
|
|
49498
49774
|
if (flags.code) params.set("include_code", "true");
|
|
49499
49775
|
return client.request(`/api/v1/motion-library/search?${params}`);
|
|
49500
49776
|
}
|
|
49501
|
-
var exists2 = (path) =>
|
|
49777
|
+
var exists2 = (path) => access3(path).then(() => true, () => false);
|
|
49502
49778
|
async function workspaceRoot(start) {
|
|
49503
|
-
for (let directory = start; ; directory =
|
|
49504
|
-
if (await exists2(
|
|
49505
|
-
if (
|
|
49779
|
+
for (let directory = start; ; directory = dirname10(directory)) {
|
|
49780
|
+
if (await exists2(join14(directory, "animaguru.workspace.json"))) return directory;
|
|
49781
|
+
if (dirname10(directory) === directory) return null;
|
|
49506
49782
|
}
|
|
49507
49783
|
}
|
|
49508
49784
|
async function writeMotionExample(example, directory, { force = false } = {}) {
|
|
49509
|
-
const target2 =
|
|
49785
|
+
const target2 = resolve13(directory);
|
|
49510
49786
|
const workspace3 = await workspaceRoot(target2);
|
|
49511
49787
|
const inAnimation = Boolean(workspace3 && relative2(workspace3, target2).split(sep2)[0] === "animations");
|
|
49512
|
-
const files = example.files.map((file2) => ({ path:
|
|
49788
|
+
const files = example.files.map((file2) => ({ path: join14(target2, safeProjectPath(file2.path)), code: inAnimation ? motionCodeForWorkspace(file2.code) : file2.code }));
|
|
49513
49789
|
if (!force) {
|
|
49514
49790
|
const clashes = [];
|
|
49515
49791
|
for (const [index2, file2] of files.entries()) if (index2 === 0 && await exists2(file2.path)) clashes.push(file2.path);
|
|
@@ -49521,7 +49797,7 @@ async function writeMotionExample(example, directory, { force = false } = {}) {
|
|
|
49521
49797
|
kept.push(file2.path);
|
|
49522
49798
|
continue;
|
|
49523
49799
|
}
|
|
49524
|
-
await
|
|
49800
|
+
await mkdir11(dirname10(file2.path), { recursive: true });
|
|
49525
49801
|
await writeFile10(file2.path, file2.code);
|
|
49526
49802
|
written.push(file2.path);
|
|
49527
49803
|
}
|
|
@@ -49529,8 +49805,8 @@ async function writeMotionExample(example, directory, { force = false } = {}) {
|
|
|
49529
49805
|
}
|
|
49530
49806
|
|
|
49531
49807
|
// cli/src/library.ts
|
|
49532
|
-
import { mkdir as
|
|
49533
|
-
import { dirname as
|
|
49808
|
+
import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
49809
|
+
import { dirname as dirname11, join as join15, resolve as resolve14 } from "node:path";
|
|
49534
49810
|
|
|
49535
49811
|
// shared/asset-library.ts
|
|
49536
49812
|
var LIBRARY_ASSET_TYPES = ["sprite", "image", "video", "music", "speech", "sfx"];
|
|
@@ -49617,23 +49893,23 @@ function searchLibrary(client, query, flags) {
|
|
|
49617
49893
|
var getLibraryAsset = (client, id2) => client.request(libraryPath(id2));
|
|
49618
49894
|
async function downloadLibraryAsset(client, id2, output2, { force = false } = {}) {
|
|
49619
49895
|
const asset = await getLibraryAsset(client, id2);
|
|
49620
|
-
const root =
|
|
49896
|
+
const root = resolve14(output2, asset.type === "sprite" ? safeProjectPath(asset.id) : ".");
|
|
49621
49897
|
const written = [];
|
|
49622
49898
|
for (const file2 of asset.files) {
|
|
49623
|
-
const path =
|
|
49899
|
+
const path = join15(root, safeProjectPath(file2.path));
|
|
49624
49900
|
const response = await client.request(`${libraryPath(asset.id)}/files/${file2.path.split("/").map(encodeURIComponent).join("/")}?download=1`, { raw: true, timeout: 3e5 });
|
|
49625
49901
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
49626
|
-
await
|
|
49902
|
+
await mkdir12(dirname11(path), { recursive: true });
|
|
49627
49903
|
await writeFile11(path, bytes, { flag: force ? "w" : "wx" }).catch((error62) => {
|
|
49628
49904
|
throw error62.code === "EEXIST" ? new Error(`Already exists: ${path}. Pass --force to replace it.`) : error62;
|
|
49629
49905
|
});
|
|
49630
49906
|
written.push({ path, size: bytes.byteLength, mimeType: file2.mimeType });
|
|
49631
49907
|
}
|
|
49632
|
-
return { id: asset.id, type: asset.type, files: written, ...asset.type === "sprite" ? { animations: asset.details.animations?.map(({ action, sheet, data, frames, fps, loop }) => ({ action, sheet:
|
|
49908
|
+
return { id: asset.id, type: asset.type, files: written, ...asset.type === "sprite" ? { animations: asset.details.animations?.map(({ action, sheet, data, frames, fps, loop }) => ({ action, sheet: join15(root, sheet), data: join15(root, data), frames, fps, loop })) } : {} };
|
|
49633
49909
|
}
|
|
49634
49910
|
var importLibraryAsset = (client, id2, project, name2) => client.request(`${libraryPath(id2)}/import`, { method: "POST", body: { projectId: project, ...name2 ? { name: name2 } : {} } });
|
|
49635
49911
|
async function words(flags) {
|
|
49636
|
-
const input2 = flags.file ? JSON.parse(await
|
|
49912
|
+
const input2 = flags.file ? JSON.parse(await readFile15(flags.file, "utf8")) : {};
|
|
49637
49913
|
if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) throw new Error("The file must contain a JSON object.");
|
|
49638
49914
|
return {
|
|
49639
49915
|
...input2,
|
|
@@ -49678,8 +49954,8 @@ async function moveWork(client, project, flags) {
|
|
|
49678
49954
|
}
|
|
49679
49955
|
|
|
49680
49956
|
// cli/src/release.ts
|
|
49681
|
-
import { mkdir as
|
|
49682
|
-
import { dirname as
|
|
49957
|
+
import { mkdir as mkdir13, readFile as readFile16, rename as rename6, unlink as unlink2, writeFile as writeFile12 } from "node:fs/promises";
|
|
49958
|
+
import { dirname as dirname12, join as join16 } from "node:path";
|
|
49683
49959
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
49684
49960
|
var releaseUrl = "https://animaguru.com/cli/release.json";
|
|
49685
49961
|
function versionParts(version3) {
|
|
@@ -49700,10 +49976,10 @@ function parseRelease(value) {
|
|
|
49700
49976
|
versionParts(value.version);
|
|
49701
49977
|
return { name: value.name, version: value.version };
|
|
49702
49978
|
}
|
|
49703
|
-
var cachePath = () =>
|
|
49979
|
+
var cachePath = () => join16(dirname12(credentialsPath()), "cli-release.json");
|
|
49704
49980
|
async function cachedRelease() {
|
|
49705
49981
|
try {
|
|
49706
|
-
return parseRelease(JSON.parse(await
|
|
49982
|
+
return parseRelease(JSON.parse(await readFile16(cachePath(), "utf8")));
|
|
49707
49983
|
} catch {
|
|
49708
49984
|
return void 0;
|
|
49709
49985
|
}
|
|
@@ -49719,7 +49995,7 @@ async function latestRelease(signal) {
|
|
|
49719
49995
|
const path = cachePath();
|
|
49720
49996
|
const temp = `${path}.${randomUUID5()}.tmp`;
|
|
49721
49997
|
try {
|
|
49722
|
-
await
|
|
49998
|
+
await mkdir13(dirname12(path), { recursive: true, mode: 448 });
|
|
49723
49999
|
await writeFile12(temp, JSON.stringify(release) + "\n", { flag: "wx", mode: 384 });
|
|
49724
50000
|
await rename6(temp, path);
|
|
49725
50001
|
} catch {
|
|
@@ -49761,8 +50037,8 @@ async function requireCurrentRelease(argv, stderr) {
|
|
|
49761
50037
|
}
|
|
49762
50038
|
|
|
49763
50039
|
// cli/src/brands.ts
|
|
49764
|
-
import { lstat as lstat3, mkdir as
|
|
49765
|
-
import { basename as basename6, dirname as
|
|
50040
|
+
import { lstat as lstat3, mkdir as mkdir14, readFile as readFile17, stat as stat9, writeFile as writeFile13 } from "node:fs/promises";
|
|
50041
|
+
import { basename as basename6, dirname as dirname13, extname as extname2, join as join17, resolve as resolve15 } from "node:path";
|
|
49766
50042
|
|
|
49767
50043
|
// shared/brands.ts
|
|
49768
50044
|
var brandId = external_exports.string().regex(/^br_[a-f0-9]{24}$/);
|
|
@@ -49881,7 +50157,7 @@ async function listBrands(client, selected) {
|
|
|
49881
50157
|
}
|
|
49882
50158
|
var getBrand = (client, id2) => client.request(brandPath(id2));
|
|
49883
50159
|
async function jsonObject(file2) {
|
|
49884
|
-
const value = JSON.parse(await
|
|
50160
|
+
const value = JSON.parse(await readFile17(file2, "utf8"));
|
|
49885
50161
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("The file must contain a JSON object.");
|
|
49886
50162
|
return value;
|
|
49887
50163
|
}
|
|
@@ -49908,12 +50184,12 @@ async function uploadBrandFile(client, id2, file2, flags) {
|
|
|
49908
50184
|
const path = brandPath(id2);
|
|
49909
50185
|
if (!flags.yes) throw new Error("Pass --yes to authorize uploading this file to the brand.");
|
|
49910
50186
|
if (flags.kind && !BRAND_FILE_KINDS.includes(flags.kind)) throw new Error("Unknown brand file kind.");
|
|
49911
|
-
const info = await
|
|
50187
|
+
const info = await stat9(file2);
|
|
49912
50188
|
if (!info.isFile() || !info.size || info.size > BRAND_FILE_BYTES) throw new Error("A brand file must be between 1 byte and 32 MiB.");
|
|
49913
50189
|
const extension = extname2(file2).slice(1).toLowerCase().replace(/^jpeg$/, "jpg");
|
|
49914
50190
|
const mimeType = flags["mime-type"] ?? Object.entries(BRAND_FILE_TYPES).find(([, ext]) => ext === extension)?.[0];
|
|
49915
50191
|
if (!mimeType || !BRAND_FILE_TYPES[mimeType]) throw new Error("Unsupported brand file type. Use a web image, font, audio or video file, or specify --mime-type.");
|
|
49916
|
-
const bytes = new Uint8Array(await
|
|
50192
|
+
const bytes = new Uint8Array(await readFile17(file2));
|
|
49917
50193
|
if (!bytes.byteLength || bytes.byteLength > BRAND_FILE_BYTES) throw new Error("A brand file must be between 1 byte and 32 MiB.");
|
|
49918
50194
|
const form = new FormData();
|
|
49919
50195
|
form.set("file", new File([bytes], basename6(file2), { type: mimeType }));
|
|
@@ -49931,22 +50207,22 @@ async function downloadBrand(client, id2, output2, flags = {}) {
|
|
|
49931
50207
|
`, mimeType: "application/json" },
|
|
49932
50208
|
{ path: "branding/brand-guide.md", content: brandGuide(brand), mimeType: "text/markdown" }
|
|
49933
50209
|
];
|
|
49934
|
-
const root =
|
|
49935
|
-
const targets = [...textFiles.map((file2) => file2.path), ...files.map(brandFilePath)].map((path) =>
|
|
50210
|
+
const root = resolve15(output2);
|
|
50211
|
+
const targets = [...textFiles.map((file2) => file2.path), ...files.map(brandFilePath)].map((path) => join17(root, safeProjectPath(path)));
|
|
49936
50212
|
if (new Set(targets).size !== targets.length) throw new Error("The brand contains conflicting file names.");
|
|
49937
|
-
for (const path of [
|
|
50213
|
+
for (const path of [join17(root, "branding"), ...targets]) {
|
|
49938
50214
|
const info = await lstat3(path).catch((error62) => {
|
|
49939
50215
|
if (error62.code !== "ENOENT") throw error62;
|
|
49940
50216
|
return null;
|
|
49941
50217
|
});
|
|
49942
50218
|
if (info?.isSymbolicLink()) throw new Error(`Refusing to write through a symbolic link: ${path}`);
|
|
49943
|
-
if (path !==
|
|
50219
|
+
if (path !== join17(root, "branding") && info && (!flags.force || !info.isFile())) throw new Error(`Already exists: ${path}. Pass --force to replace files.`);
|
|
49944
50220
|
}
|
|
49945
|
-
await
|
|
50221
|
+
await mkdir14(join17(root, "branding"), { recursive: true });
|
|
49946
50222
|
const written = [];
|
|
49947
50223
|
const save = async (path, bytes, mimeType) => {
|
|
49948
|
-
const target2 =
|
|
49949
|
-
await
|
|
50224
|
+
const target2 = join17(root, safeProjectPath(path));
|
|
50225
|
+
await mkdir14(dirname13(target2), { recursive: true });
|
|
49950
50226
|
await writeFile13(target2, bytes, { flag: flags.force ? "w" : "wx" });
|
|
49951
50227
|
written.push({ path: target2, size: bytes.byteLength, mimeType });
|
|
49952
50228
|
};
|
|
@@ -49959,8 +50235,8 @@ async function downloadBrand(client, id2, output2, flags = {}) {
|
|
|
49959
50235
|
}
|
|
49960
50236
|
|
|
49961
50237
|
// cli/src/review-check.ts
|
|
49962
|
-
import { readFile as
|
|
49963
|
-
import { join as
|
|
50238
|
+
import { readFile as readFile18, readdir as readdir7, stat as stat10, writeFile as writeFile14 } from "node:fs/promises";
|
|
50239
|
+
import { join as join18 } from "node:path";
|
|
49964
50240
|
|
|
49965
50241
|
// shared/frame-checks.ts
|
|
49966
50242
|
var FRAME_CHECK_MAX_FRAMES = 12;
|
|
@@ -50004,17 +50280,17 @@ var frameCheckRequest = external_exports.object({
|
|
|
50004
50280
|
// cli/src/review-check.ts
|
|
50005
50281
|
async function framesToCheck(projectRoot, source, report2) {
|
|
50006
50282
|
if (source === "frames") {
|
|
50007
|
-
const folder2 =
|
|
50008
|
-
const names2 = await
|
|
50009
|
-
const frames = names2.map((name2) => /^frame-([\d.]+)s\.jpg$/.exec(name2)).filter((match) => match !== null).map((match) => ({ file:
|
|
50283
|
+
const folder2 = join18(projectRoot, "production/review/frames");
|
|
50284
|
+
const names2 = await readdir7(folder2).catch(() => []);
|
|
50285
|
+
const frames = names2.map((name2) => /^frame-([\d.]+)s\.jpg$/.exec(name2)).filter((match) => match !== null).map((match) => ({ file: join18(folder2, match[0]), time: Number(match[1]) })).sort((a, b) => a.time - b.time);
|
|
50010
50286
|
if (!frames.length) throw new Error("No full-size frames found. Run npm run frames -- --full (with --at TIMES for the moments to check) first.");
|
|
50011
50287
|
return frames;
|
|
50012
50288
|
}
|
|
50013
|
-
const folder =
|
|
50289
|
+
const folder = join18(projectRoot, "production/review");
|
|
50014
50290
|
const times = [...report2.seekMatches ?? []].map((match) => match.time).sort((a, b) => a - b);
|
|
50015
|
-
const names = (await
|
|
50291
|
+
const names = (await readdir7(folder)).filter((name2) => /^frame-\d{2}\.jpg$/.test(name2)).sort();
|
|
50016
50292
|
if (!names.length || names.length !== times.length) throw new Error("The review frames do not match report.json. Run npm run review again.");
|
|
50017
|
-
return names.map((name2, index2) => ({ file:
|
|
50293
|
+
return names.map((name2, index2) => ({ file: join18(folder, name2), time: times[index2] }));
|
|
50018
50294
|
}
|
|
50019
50295
|
function filmContext(report2, brief, extra) {
|
|
50020
50296
|
const config2 = report2.config ?? {};
|
|
@@ -50029,29 +50305,29 @@ function compact(answers) {
|
|
|
50029
50305
|
async function reviewCheck(client, options) {
|
|
50030
50306
|
if (!options.yes && !options["dry-run"]) throw new Error("Pass --yes to authorize spending credits on the check, or --dry-run for its most.");
|
|
50031
50307
|
const context = await localProject(options.directory, options.animation);
|
|
50032
|
-
const reportFile =
|
|
50033
|
-
const report2 = JSON.parse(await
|
|
50308
|
+
const reportFile = join18(context.projectRoot, "production/review/report.json");
|
|
50309
|
+
const report2 = JSON.parse(await readFile18(reportFile, "utf8").catch(() => {
|
|
50034
50310
|
throw new Error("Run npm run review first: production/review/report.json is missing.");
|
|
50035
50311
|
}));
|
|
50036
50312
|
const frames = await framesToCheck(context.projectRoot, options.source ?? "review", report2);
|
|
50037
50313
|
if (frames.length > FRAME_CHECK_MAX_FRAMES) throw new Error(`Check at most ${FRAME_CHECK_MAX_FRAMES} frames at once; run npm run frames -- --full --at with fewer times.`);
|
|
50038
|
-
const sizes = await Promise.all(frames.map(async (frame) => (await
|
|
50314
|
+
const sizes = await Promise.all(frames.map(async (frame) => (await stat10(frame.file)).size));
|
|
50039
50315
|
if (sizes.reduce((sum, size) => sum + size, 0) > FRAME_CHECK_TOTAL_BYTES) throw new Error("These frames total over 8 MiB. Check fewer at once.");
|
|
50040
|
-
const questions = options.questions ? frameCheckQuestions.parse(JSON.parse(await
|
|
50041
|
-
const brief = await
|
|
50316
|
+
const questions = options.questions ? frameCheckQuestions.parse(JSON.parse(await readFile18(options.questions, "utf8"))) : void 0;
|
|
50317
|
+
const brief = await readFile18(join18(context.projectRoot, "production/brief.md"), "utf8").catch(() => "");
|
|
50042
50318
|
const link2 = await cloudLink(context.toolsRoot).catch(() => null);
|
|
50043
50319
|
const body = {
|
|
50044
50320
|
...link2?.origin === client.origin ? { projectId: link2.projectId } : { workspace: await selectedWorkspace(client.origin) },
|
|
50045
50321
|
context: filmContext(report2, brief, options.context),
|
|
50046
50322
|
...report2.config?.duration ? { duration: report2.config.duration } : {},
|
|
50047
|
-
frames: await Promise.all(frames.map(async (frame) => ({ time: Math.round(frame.time * 1e3) / 1e3, image: `data:image/jpeg;base64,${(await
|
|
50323
|
+
frames: await Promise.all(frames.map(async (frame) => ({ time: Math.round(frame.time * 1e3) / 1e3, image: `data:image/jpeg;base64,${(await readFile18(frame.file)).toString("base64")}` }))),
|
|
50048
50324
|
...questions ? { questions } : {},
|
|
50049
50325
|
...options["dry-run"] ? { dryRun: true } : {}
|
|
50050
50326
|
};
|
|
50051
50327
|
if (options["dry-run"]) return client.request("/api/v1/frame-checks", { method: "POST", body, timeout: 12e4 });
|
|
50052
50328
|
const result = await client.request("/api/v1/frame-checks", { method: "POST", body, timeout: 12e4 });
|
|
50053
50329
|
const fileAt = (time3) => frames.find((frame) => Math.abs(frame.time - time3) < 1e-3)?.file.slice(context.projectRoot.length + 1);
|
|
50054
|
-
const saved =
|
|
50330
|
+
const saved = join18(context.projectRoot, "production/review/check.json");
|
|
50055
50331
|
await writeFile14(saved, `${JSON.stringify({ ...result, frames: result.frames.map((frame) => ({ file: fileAt(frame.time), ...frame })) }, null, 2)}
|
|
50056
50332
|
`);
|
|
50057
50333
|
return {
|
|
@@ -50065,8 +50341,8 @@ async function reviewCheck(client, options) {
|
|
|
50065
50341
|
|
|
50066
50342
|
// cli/src/reference.ts
|
|
50067
50343
|
import { openAsBlob } from "node:fs";
|
|
50068
|
-
import { mkdir as
|
|
50069
|
-
import { basename as basename7, dirname as
|
|
50344
|
+
import { mkdir as mkdir15, stat as stat11, writeFile as writeFile15 } from "node:fs/promises";
|
|
50345
|
+
import { basename as basename7, dirname as dirname14, extname as extname3, join as join19, relative as relative3, resolve as resolve16 } from "node:path";
|
|
50070
50346
|
|
|
50071
50347
|
// shared/video-analysis.ts
|
|
50072
50348
|
var VIDEO_ANALYSIS_MAX_BYTES = 100 * 1024 * 1024;
|
|
@@ -50097,11 +50373,11 @@ var TYPES = { ".mp4": "video/mp4", ".m4v": "video/mp4", ".mov": "video/quicktime
|
|
|
50097
50373
|
var POLL_MS = 1e4;
|
|
50098
50374
|
var WAIT_LIMIT_MS = 70 * 6e4;
|
|
50099
50375
|
async function briefFile(options, name2) {
|
|
50100
|
-
if (options.out) return
|
|
50376
|
+
if (options.out) return resolve16(options.out);
|
|
50101
50377
|
const slug2 = name2.replace(/\.[a-z0-9]{2,4}$/i, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60) || "reference";
|
|
50102
50378
|
const project = await localProject(options.directory ?? ".", options.animation).catch(() => null);
|
|
50103
|
-
const film = project && await
|
|
50104
|
-
return film ?
|
|
50379
|
+
const film = project && await stat11(join19(project.projectRoot, "animaguru.project.json")).then(() => true, () => false);
|
|
50380
|
+
return film ? join19(project.projectRoot, "production/references", `${slug2}.json`) : resolve16(options.directory ?? ".", `${slug2}.analysis.json`);
|
|
50105
50381
|
}
|
|
50106
50382
|
var pause = (ms, signal) => new Promise((done, fail) => {
|
|
50107
50383
|
signal?.throwIfAborted();
|
|
@@ -50140,7 +50416,7 @@ async function report(analysis, options) {
|
|
|
50140
50416
|
if (analysis.status === "failed") throw new Error(analysis.error ?? "The analysis failed.");
|
|
50141
50417
|
if (analysis.status !== "completed") return { id: analysis.id, status: analysis.status, next: `animaguru reference get ${analysis.id} --wait` };
|
|
50142
50418
|
const file2 = await briefFile(options, sourceName(analysis));
|
|
50143
|
-
await
|
|
50419
|
+
await mkdir15(dirname14(file2), { recursive: true });
|
|
50144
50420
|
await writeFile15(file2, `${JSON.stringify(analysis, null, 2)}
|
|
50145
50421
|
`);
|
|
50146
50422
|
const brief = analysis.result?.brief;
|
|
@@ -50165,8 +50441,8 @@ async function referenceAnalyze(client, options) {
|
|
|
50165
50441
|
if (!options.video.startsWith("https://")) throw new Error("Use an HTTPS link to the video file.");
|
|
50166
50442
|
started = await client.request("/api/v1/video-analyses", { method: "POST", body: { ...settings2, url: options.video, ...dryRun ? { dryRun: true } : {} }, timeout: 12e4 });
|
|
50167
50443
|
} else {
|
|
50168
|
-
const file2 =
|
|
50169
|
-
const info = await
|
|
50444
|
+
const file2 = resolve16(options.video);
|
|
50445
|
+
const info = await stat11(file2).catch(() => null);
|
|
50170
50446
|
if (!info?.isFile()) throw new Error(`No video file at ${options.video}. Give a file path, or an HTTPS link to the video file itself.`);
|
|
50171
50447
|
const type = TYPES[extname3(file2).toLowerCase()];
|
|
50172
50448
|
if (!type) throw new Error("Analyse an MP4, MOV or WebM video.");
|
|
@@ -50188,8 +50464,8 @@ async function referenceGet(client, id2, options) {
|
|
|
50188
50464
|
|
|
50189
50465
|
// cli/src/curl.ts
|
|
50190
50466
|
import { createWriteStream as createWriteStream2, openAsBlob as openAsBlob2 } from "node:fs";
|
|
50191
|
-
import { readFile as
|
|
50192
|
-
import { extname as extname4, resolve as
|
|
50467
|
+
import { readFile as readFile19, unlink as unlink3 } from "node:fs/promises";
|
|
50468
|
+
import { extname as extname4, resolve as resolve17 } from "node:path";
|
|
50193
50469
|
import { Readable as Readable2 } from "node:stream";
|
|
50194
50470
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
50195
50471
|
function curlUrl(server, target2) {
|
|
@@ -50229,7 +50505,7 @@ var readStdin = async () => {
|
|
|
50229
50505
|
};
|
|
50230
50506
|
async function bodyValue(value, io) {
|
|
50231
50507
|
if (value === "@-") return (io.stdin ?? readStdin)();
|
|
50232
|
-
return value.startsWith("@") ?
|
|
50508
|
+
return value.startsWith("@") ? readFile19(resolve17(value.slice(1))) : value;
|
|
50233
50509
|
}
|
|
50234
50510
|
var parsesAsJson = (body) => {
|
|
50235
50511
|
try {
|
|
@@ -50245,7 +50521,7 @@ async function curl(options, io) {
|
|
|
50245
50521
|
if ([options.data, options.json, options.uploadFile].filter((value) => value !== void 0).length > 1) throw new Error("Use one of --data, --json and --upload-file.");
|
|
50246
50522
|
let body;
|
|
50247
50523
|
if (options.uploadFile !== void 0) {
|
|
50248
|
-
const file2 =
|
|
50524
|
+
const file2 = resolve17(options.uploadFile);
|
|
50249
50525
|
body = await openAsBlob2(file2);
|
|
50250
50526
|
if (!headers.has("content-type")) headers.set("Content-Type", UPLOAD_TYPES[extname4(file2).toLowerCase()] ?? "application/octet-stream");
|
|
50251
50527
|
} else if (options.json !== void 0) {
|
|
@@ -50265,7 +50541,7 @@ async function curl(options, io) {
|
|
|
50265
50541
|
const type = response.headers.get("content-type") ?? "";
|
|
50266
50542
|
const failed = options.fail && response.status >= 400;
|
|
50267
50543
|
if (options.output !== void 0 && !failed) {
|
|
50268
|
-
const file2 =
|
|
50544
|
+
const file2 = resolve17(options.output);
|
|
50269
50545
|
let bytes = 0;
|
|
50270
50546
|
try {
|
|
50271
50547
|
await pipeline2(
|
|
@@ -50295,7 +50571,7 @@ async function curl(options, io) {
|
|
|
50295
50571
|
}
|
|
50296
50572
|
|
|
50297
50573
|
// cli/src/commands.ts
|
|
50298
|
-
var assetModelIds = [...SPRITE_VIDEO_MODEL_IDS, ...MUSIC_MODELS.map((m) => m.id), ...SPEECH_MODELS.map((m) => m.id), ...SFX_MODELS.map((m) => m.id)];
|
|
50574
|
+
var assetModelIds = [...SPRITE_VIDEO_MODEL_IDS, ...MUSIC_MODELS.map((m) => m.id), ...SPEECH_MODELS.map((m) => m.id), ...SFX_MODELS.map((m) => m.id), ...VECTOR_MODELS.map((m) => m.id), ...MODEL_GENERATOR_IDS];
|
|
50299
50575
|
var assetAuthorizationFlags = [
|
|
50300
50576
|
{ name: "yes", type: "boolean", description: "Authorize spending credits" },
|
|
50301
50577
|
{ name: "dry-run", type: "boolean", description: "Validate and estimate locally without submitting a paid job" }
|
|
@@ -50307,13 +50583,15 @@ var assetWaitFlags = [
|
|
|
50307
50583
|
var catalogSections = {
|
|
50308
50584
|
sprites: ["styles", "kinds", "actions", "videoModels"],
|
|
50309
50585
|
image: ["assetTypes"],
|
|
50586
|
+
vector: ["assetTypes", "vectorModels", "vectorOptions"],
|
|
50310
50587
|
video: ["assetTypes", "videoModels", "videoProfiles"],
|
|
50311
50588
|
music: ["assetTypes", "musicModels"],
|
|
50312
50589
|
speech: ["assetTypes", "speechModels", "voices", "elevenLabsVoices"],
|
|
50313
50590
|
sfx: ["assetTypes", "sfxModels"],
|
|
50591
|
+
model: ["assetTypes", "modelGenerators", "modelAnimations"],
|
|
50314
50592
|
avatars: ["avatarTypes", "avatarLookTypes"]
|
|
50315
50593
|
};
|
|
50316
|
-
var catalog = () => ({ styles: SPRITE_STYLES, kinds: SPRITE_KINDS, actions: ALL_SPRITE_ACTIONS, videoModels: SPRITE_VIDEO_MODEL_IDS, assetTypes: ASSET_TYPES, musicModels: MUSIC_MODELS.map((m) => m.id), speechModels: SPEECH_MODELS.map((m) => m.id), sfxModels: SFX_MODELS.map((m) => m.id), elevenLabsVoices: ELEVENLABS_VOICES, voices: SPEECH_VOICES, videoProfiles: SPRITE_VIDEO_MODELS, avatarTypes: AVATAR_CREATE_TYPES, avatarLookTypes: AVATAR_LOOK_TYPES });
|
|
50594
|
+
var catalog = () => ({ styles: SPRITE_STYLES, kinds: SPRITE_KINDS, actions: ALL_SPRITE_ACTIONS, videoModels: SPRITE_VIDEO_MODEL_IDS, assetTypes: ASSET_TYPES, musicModels: MUSIC_MODELS.map((m) => m.id), speechModels: SPEECH_MODELS.map((m) => m.id), sfxModels: SFX_MODELS.map((m) => m.id), modelGenerators: MODEL_GENERATORS.map(({ id: id2, label: label3, faces }) => ({ id: id2, label: label3, faces })), modelAnimations: MODEL_ANIMATIONS, vectorModels: VECTOR_MODELS.map((m) => m.id), vectorOptions: { workflows: VECTOR_WORKFLOWS, qualities: VECTOR_QUALITIES, aspectRatios: VECTOR_ASPECT_RATIOS, shapes: VECTOR_SHAPES, maxReferences: MAX_VECTOR_REFERENCES }, elevenLabsVoices: ELEVENLABS_VOICES, voices: SPEECH_VOICES, videoProfiles: SPRITE_VIDEO_MODELS, avatarTypes: AVATAR_CREATE_TYPES, avatarLookTypes: AVATAR_LOOK_TYPES });
|
|
50317
50595
|
var modelFlags = [
|
|
50318
50596
|
{ name: "video-model", type: "string", choices: SPRITE_VIDEO_MODEL_IDS, description: "Video model override for this operation" }
|
|
50319
50597
|
];
|
|
@@ -50344,12 +50622,12 @@ var workspaceQuery = async (client) => {
|
|
|
50344
50622
|
async function openBrowser(url3) {
|
|
50345
50623
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "rundll32" : "xdg-open";
|
|
50346
50624
|
const args = process.platform === "win32" ? ["url.dll,FileProtocolHandler", url3] : [url3];
|
|
50347
|
-
await new Promise((
|
|
50625
|
+
await new Promise((resolve19) => {
|
|
50348
50626
|
const child = spawn3(command, args, { stdio: "ignore", detached: true });
|
|
50349
|
-
child.once("error", () =>
|
|
50627
|
+
child.once("error", () => resolve19());
|
|
50350
50628
|
child.once("spawn", () => {
|
|
50351
50629
|
child.unref();
|
|
50352
|
-
|
|
50630
|
+
resolve19();
|
|
50353
50631
|
});
|
|
50354
50632
|
});
|
|
50355
50633
|
}
|
|
@@ -50375,7 +50653,10 @@ function createCli() {
|
|
|
50375
50653
|
{ name: "thumbnail", type: "string", default: "auto", description: "JPEG or PNG thumbnail up to 2 MiB to set after the upload; auto uses FILM.jpg beside FILM.mp4; none skips" },
|
|
50376
50654
|
{ name: "yes", type: "boolean", description: "Authorize sending this video, its subtitles and thumbnail to the selected channel and privacy; confirm upload rights" },
|
|
50377
50655
|
{ name: "dry-run", type: "boolean", description: "Inspect MP4 and metadata locally without Google authorization or network calls" }
|
|
50378
|
-
).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await uploadYouTube({ ...flags, directory: args.directory, log: stderr, signal }))))).command("uploads", (uploads) => uploads.add(defineCommand("list", { description: "List local upload receipts without tokens or session URLs" }, (command) => command.action(async ({ stdout }) => out(stdout, await listYouTubeUploads())))).add(defineCommand("resume", { description: "Resume the same local MP4 and Google upload session after an interruption" }, (command) => command.args({ name: "id", type: "string", required: true, description: "Upload ID returned by youtube uploads list" }).flags({ name: "yes", type: "boolean", description: "Authorize resuming the saved upload and visibility" }).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await resumeYouTube(args.id, { ...flags, log: stderr, signal }))))))).add(defineCommand("init", { description: "Install or refresh the AnimaGuru agent skill in the current folder" }, (command) => command.action(async ({ stdout }) => out(stdout, await initializeSkill())))).
|
|
50656
|
+
).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await uploadYouTube({ ...flags, directory: args.directory, log: stderr, signal }))))).command("uploads", (uploads) => uploads.add(defineCommand("list", { description: "List local upload receipts without tokens or session URLs" }, (command) => command.action(async ({ stdout }) => out(stdout, await listYouTubeUploads())))).add(defineCommand("resume", { description: "Resume the same local MP4 and Google upload session after an interruption" }, (command) => command.args({ name: "id", type: "string", required: true, description: "Upload ID returned by youtube uploads list" }).flags({ name: "yes", type: "boolean", description: "Authorize resuming the saved upload and visibility" }).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await resumeYouTube(args.id, { ...flags, log: stderr, signal }))))))).add(defineCommand("init", { description: "Install or refresh the core AnimaGuru agent skill in the current folder; skills install adds every skill" }, (command) => command.action(async ({ stdout }) => out(stdout, await initializeSkill())))).command("skills", (skills) => skills.add(defineCommand("install", { description: "Install the latest AnimaGuru and PixiJS agent skills into a folder for Claude Code (.claude/skills) and Codex (.agents/skills), with npx skills; npx skills update refreshes them" }, (command) => command.flags(
|
|
50657
|
+
{ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin whose skills to install" },
|
|
50658
|
+
{ name: "dir", type: "string", default: ".", description: "Folder to install into (created if missing)" }
|
|
50659
|
+
).action(async ({ flags, stdout, stderr, signal }) => out(stdout, await installSkills({ url: flags.url, dir: flags.dir, signal, log: stderr })))))).add(defineCommand("templates", { description: "List video categories and available starter templates" }, (command) => command.action(({ stdout }) => out(stdout, listTemplates())))).command("review", (review) => review.add(defineCommand("check", { description: "Check a film's review frames for visual faults with AnimaGuru's frame checker (Clef-omni): empty frames, cut-off or overlapping text, broken letters, hard-to-read text and a polish score. Run npm run review first; open the flagged frames first. Charges a fraction of a credit per frame" }, (command) => command.args({ name: "directory", type: "string", default: ".", description: "Video workspace or animation folder" }).flags(
|
|
50379
50660
|
{ name: "animation", type: "string", description: "Animation in a multi-animation workspace" },
|
|
50380
50661
|
{ name: "source", type: "string", choices: ["review", "frames"], default: "review", description: "review: npm run review's five frames; frames: the full-size frames of npm run frames -- --full" },
|
|
50381
50662
|
{ name: "context", type: "string", description: "What the film should show, added to its title, format and brief" },
|
|
@@ -50542,7 +50823,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50542
50823
|
})))).add(defineCommand("credits", { description: "Show the selected workspace's remaining credit balance" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).action(async ({ flags, stdout, signal }) => {
|
|
50543
50824
|
const client = new Client(flags.url, signal);
|
|
50544
50825
|
out(stdout, await client.request(`/api/v1/credits${await workspaceQuery(client)}`));
|
|
50545
|
-
}))).add(defineCommand("catalog", { description: "List styles, kinds, actions, asset types, models, video settings, speech voices and avatar types" }, (command) => command.flags({ name: "type", type: "string", choices: Object.keys(catalogSections), description: "Only one part: sprites, image, video, music, speech, sfx or avatars" }).action(({ flags, stdout }) => {
|
|
50826
|
+
}))).add(defineCommand("catalog", { description: "List styles, kinds, actions, asset types, models, video settings, speech voices and avatar types" }, (command) => command.flags({ name: "type", type: "string", choices: Object.keys(catalogSections), description: "Only one part: sprites, image, vector, video, music, speech, sfx, model or avatars" }).action(({ flags, stdout }) => {
|
|
50546
50827
|
const full = catalog();
|
|
50547
50828
|
const section = flags.type;
|
|
50548
50829
|
out(stdout, section ? Object.fromEntries(catalogSections[section].map((key) => [key, full[key]])) : full);
|
|
@@ -50609,21 +50890,21 @@ Confirm code: ${device.user_code}`);
|
|
|
50609
50890
|
).action(async ({ args, flags, stdout, signal }) => out(stdout, await moveWork(new Client(flags.url, signal), args.id, flags))))).add(defineCommand("delete", { description: "Delete a project; requires --yes" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).flags({ name: "yes", type: "boolean", required: true }).action(async ({ args, flags, stdout, signal }) => {
|
|
50610
50891
|
if (!flags.yes) throw new Error("Pass --yes to delete this project.");
|
|
50611
50892
|
out(stdout, await new Client(flags.url, signal).request(`/api/v1/projects/${encodeURIComponent(args.id)}`, { method: "DELETE" }));
|
|
50612
|
-
})))).command("assets", (assets) => assets.add(defineCommand("list", { description: "List saved assets, their blob hashes, and configured generation models" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).args(id).action(async ({ args, flags, stdout, signal }) => out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/assets`))))).add(defineCommand("generate", { description: "Generate an image, video, music, speech
|
|
50893
|
+
})))).command("assets", (assets) => assets.add(defineCommand("list", { description: "List saved assets, their blob hashes, and configured generation models" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).args(id).action(async ({ args, flags, stdout, signal }) => out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/assets`))))).add(defineCommand("generate", { description: "Generate an image, vector (SVG), video, music, speech, sound-effect or 3D model asset; --yes authorizes credits" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).args(id).flags(
|
|
50613
50894
|
{ name: "type", type: "string", required: true, choices: ASSET_TYPES },
|
|
50614
50895
|
{ name: "name", type: "string", required: true },
|
|
50615
|
-
{ name: "prompt", type: "string", description: "Description to generate, or verbatim transcript for speech; video lip-sync and relight take none, and camera-controls, insert-video, recast and 3d-to-video may leave it out" },
|
|
50896
|
+
{ name: "prompt", type: "string", description: "Description to generate, or verbatim transcript for speech; video lip-sync and relight and vector image-to-vector take none, and camera-controls, insert-video, recast and 3d-to-video may leave it out" },
|
|
50616
50897
|
{ name: "model", type: "string", choices: assetModelIds, description: "Model for the chosen asset type" },
|
|
50617
|
-
{ name: "aspect-ratio", type: "string", choices: [.../* @__PURE__ */ new Set([...IMAGE_ASPECT_RATIOS, "auto", ...VIDEO_ASPECT_RATIOS])], description: "Image: 1:1 (default), 3:2, 2:3, 16:9 or 9:16; a masked edit keeps Image 1's shape. Video from text or a style without --reference: 21:9\u20139:16 (default 16:9). Extension, reference-to-video, relight and keyframes-to-video: auto (default, the inputs' shape) or a ratio to crop to" },
|
|
50898
|
+
{ name: "aspect-ratio", type: "string", choices: [.../* @__PURE__ */ new Set([...IMAGE_ASPECT_RATIOS, "auto", ...VIDEO_ASPECT_RATIOS, ...VECTOR_ASPECT_RATIOS])], description: "Image: 1:1 (default), 3:2, 2:3, 16:9 or 9:16; a masked edit keeps Image 1's shape. Video from text or a style without --reference: 21:9\u20139:16 (default 16:9). Extension, reference-to-video, relight and keyframes-to-video: auto (default, the inputs' shape) or a ratio to crop to. Vector from text: auto (default, the model's choice) or 1:4\u20134:1" },
|
|
50618
50899
|
{ name: "transparent", type: "boolean", description: "Image: transparent background" },
|
|
50619
|
-
{ name: "references", type: "string", description: "Comma-separated blob SHAs of this project's images or sprite art, named Image 1, Image 2\u2026 in the prompt. Image: up to 4 to follow, such as a character sheet. Video: subjects or looks to keep (reference-to-video and insert-video up to 9, 3d-to-video up to 8), or recast's new people, one photo each (up to 4)" },
|
|
50900
|
+
{ name: "references", type: "string", description: "Comma-separated blob SHAs of this project's images or sprite art, named Image 1, Image 2\u2026 in the prompt. Image: up to 4 to follow, such as a character sheet. Vector from text: up to 5, the first leading. Video: subjects or looks to keep (reference-to-video and insert-video up to 9, 3d-to-video up to 8), or recast's new people, one photo each (up to 4)" },
|
|
50620
50901
|
{ name: "mask", type: "string", description: "Image: edit only these rectangles of Image 1 (the first --references image), as x,y,width,height fractions of its size from the top left, up to 8 separated by semicolons; the rest is kept" },
|
|
50621
|
-
{ name: "workflow", type: "string", choices: VIDEO_WORKFLOWS, description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, FLUX 3 Max keyframes-to-video, as the model's videoProfiles allow" },
|
|
50622
|
-
{ name: "reference", type: "string", description: "Video: starting image blob SHA from this project's assets or sprites; the speaking face for lip-sync, the image the camera moves around for camera-controls" },
|
|
50902
|
+
{ name: "workflow", type: "string", choices: [...VIDEO_WORKFLOWS, ...VECTOR_WORKFLOWS], description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, FLUX 3 Max keyframes-to-video, as the model's videoProfiles allow. Vector: text-to-vector (default) or image-to-vector, which traces --source" },
|
|
50903
|
+
{ name: "reference", type: "string", description: "Video: starting image blob SHA from this project's assets or sprites; the speaking face for lip-sync, the image the camera moves around for camera-controls. Model: the image or sprite art to build it from (image-to-3D); without one the prompt describes it" },
|
|
50623
50904
|
{ name: "end-reference", type: "string", description: "Video: ending image blob SHA; models with endFrameOnly accept it without --reference" },
|
|
50624
50905
|
{ name: "middle-reference", type: "string", description: "Reference-to-video: image blob SHA reached at --middle-seconds; needs --reference and --end-reference, 480p or 768p" },
|
|
50625
50906
|
{ name: "middle-seconds", type: "number", description: "Reference-to-video: when the middle image is reached, in seconds" },
|
|
50626
|
-
{ name: "source", type: "string", description: "Blob SHA of a video asset in this project: the clip to extend, insert a scene into, recast or relight, or the 3D render 3d-to-video turns into footage" },
|
|
50907
|
+
{ name: "source", type: "string", description: "Blob SHA of a video asset in this project: the clip to extend, insert a scene into, recast or relight, or the 3D render 3d-to-video turns into footage. Vector image-to-vector: the image or sprite art to trace" },
|
|
50627
50908
|
{ name: "soundtrack", type: "string", description: "Video from an image or text: blob SHA of a music, speech or SFX asset pinned as the soundtrack (2 s or longer). Lip-sync: the speech to say (5 s\u201315 min), which sets the length" },
|
|
50628
50909
|
{ name: "audio-references", type: "string", description: "Extension or reference-to-video: up to 3 comma-separated audio asset blob SHAs (2\u201315 s each, 15 s total) guiding the sound; refer to them as Audio 1, Audio 2\u2026 in the prompt" },
|
|
50629
50910
|
{ name: "reference-videos", type: "string", description: "Reference-to-video or insert-video: up to 3 comma-separated video asset blob SHAs (2\u201315 s each, 15 s total) guiding motion, named Video 1, Video 2\u2026 in the prompt" },
|
|
@@ -50643,12 +50924,20 @@ Confirm code: ${device.user_code}`);
|
|
|
50643
50924
|
{ name: "resolution", type: "string", choices: VIDEO_RESOLUTIONS, description: "Video resolution supported by the selected model and workflow (default its first)" },
|
|
50644
50925
|
{ name: "mode", type: "string", choices: ["cost", "speed", "quality"], description: "Video generation mode supported by the selected model (default its first)" },
|
|
50645
50926
|
{ name: "prompt-expansion", type: "string", choices: PROMPT_EXPANSION_MODES, description: "Video: how much the model may rewrite the prompt (default disabled); extensions treat any other value as on. FLUX 3 Max always reasons about the prompt: quality thoroughly, any other value lightly" },
|
|
50646
|
-
{ name: "seed", type: "number", description: "Video: seed for repeatable results, where the model takes one" },
|
|
50927
|
+
{ name: "seed", type: "number", description: "Video or vector from text: seed for repeatable results, where the model takes one" },
|
|
50647
50928
|
{ name: "extend-output", type: "string", choices: EXTEND_OUTPUTS, description: "Extension: extended (default, source plus new footage) or continuation (a 1.625 s overlap, then the new footage)" },
|
|
50648
50929
|
{ name: "voice", type: "string", description: "Gemini voice name or ElevenLabs voice ID (defaults: Kore / George)" },
|
|
50649
50930
|
{ name: "delivery", type: "string", description: "Gemini speech delivery instructions; ElevenLabs uses audio tags in the transcript" },
|
|
50650
50931
|
{ name: "loop", type: "boolean", description: "SFX: create a seamless loop" },
|
|
50932
|
+
{ name: "texture", type: "boolean", description: "Model: textured (default on); --no-texture makes a plain white model" },
|
|
50933
|
+
{ name: "pbr", type: "boolean", description: "Model: metallic, roughness and normal maps with the texture (default on); --no-pbr leaves them out" },
|
|
50934
|
+
{ name: "faces", type: "number", description: "Model: target face count; Tripo H3.1 1,000\u20132,000,000, Hunyuan3D 40,000\u20131,500,000 (charged extra). Rigged models take at most 300,000" },
|
|
50935
|
+
{ name: "rig", type: "boolean", description: "Model: auto-rig a humanoid character standing in a T- or A-pose, with animation clips" },
|
|
50936
|
+
{ name: "animations", type: "string", description: "Model with --rig: up to 10 comma-separated clips, by name (catalog --type model) or Meshy library number 0\u2013696; default idle,walk" },
|
|
50937
|
+
{ name: "height", type: "number", description: "Model with --rig: the character's height in metres (default 1.7)" },
|
|
50651
50938
|
{ name: "prompt-influence", type: "number", description: "SFX: prompt adherence, 0\u20131 (default 0.3)" },
|
|
50939
|
+
{ name: "quality", type: "string", choices: VECTOR_QUALITIES, description: "Vector from text: low (fastest, 13 credits), medium (default, 16) or high (20, or 32 with --references)" },
|
|
50940
|
+
{ name: "shapes", type: "string", choices: VECTOR_SHAPES, description: "Vector image-to-vector (10 credits): detailed (default) keeps fine detail, simple uses fewer, simpler shapes" },
|
|
50652
50941
|
...assetAuthorizationFlags,
|
|
50653
50942
|
...assetWaitFlags,
|
|
50654
50943
|
{ name: "download", type: "string", description: "Wait, then save the result to this file, or into this folder (existing, or ending in /) as NAME.EXT; never overwrites" }
|
|
@@ -50694,7 +50983,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50694
50983
|
out(stdout, await new Client(flags.url, signal).request(flags.look ? `${avatarsPath(args.id)}/looks/${encodeURIComponent(flags.look)}` : `${avatarsPath(args.id)}/${encodeURIComponent(flags.group)}`, { method: "DELETE" }));
|
|
50695
50984
|
})))).command("jobs", (jobs) => jobs.add(defineCommand("list", { description: "List the latest generation jobs" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).action(async ({ args, flags, stdout, signal }) => out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/jobs`))))).add(defineCommand("submit", { description: "Submit a typed JSON job: character, animate, custom or redraw; spends credits" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).flags(...modelFlags).flags({ name: "file", type: "string", required: true, description: "JSON job file" }, { name: "yes", type: "boolean", required: true, description: "Authorize spending credits" }).action(async ({ args, flags, stdout, signal }) => {
|
|
50696
50985
|
if (!flags.yes) throw new Error("Pass --yes to authorize spending credits.");
|
|
50697
|
-
const body = spriteJobBody.parse({ ...JSON.parse(await
|
|
50986
|
+
const body = spriteJobBody.parse({ ...JSON.parse(await readFile20(flags.file, "utf8")), ...selectedModels(flags) });
|
|
50698
50987
|
out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/jobs`, { method: "POST", body }));
|
|
50699
50988
|
}))).add(defineCommand("wait", { description: "Wait for a specific job; fail if generation fails or times out" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id, { name: "job", type: "string", required: true }).flags({ name: "timeout", type: "number", default: 600, description: "Maximum seconds to wait" }).action(async ({ args, flags, stdout, signal }) => out(stdout, { job: await waitForJob(new Client(flags.url, signal), args.id, args.job, flags.timeout, signal) }))))).add(defineCommand("models", { description: "Set the default video model for future project jobs" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).flags(...modelFlags).action(async ({ args, flags, stdout, signal }) => {
|
|
50700
50989
|
const body = selectedModels(flags);
|
|
@@ -50709,7 +50998,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50709
50998
|
const extension = flags.file.split(".").at(-1)?.toLowerCase();
|
|
50710
50999
|
const type = extension === "png" ? "image/png" : extension === "jpg" || extension === "jpeg" ? "image/jpeg" : extension === "webp" ? "image/webp" : void 0;
|
|
50711
51000
|
if (!type) throw new Error("Use a PNG, JPEG or WebP image.");
|
|
50712
|
-
const bytes = await
|
|
51001
|
+
const bytes = await readFile20(flags.file);
|
|
50713
51002
|
if (bytes.length > 10 * 1024 * 1024) throw new Error("Image must be at most 10 MB.");
|
|
50714
51003
|
const form = new FormData();
|
|
50715
51004
|
form.set("image", new Blob([bytes], { type }), `reference.${extension}`);
|
|
@@ -50725,8 +51014,8 @@ Confirm code: ${device.user_code}`);
|
|
|
50725
51014
|
if (!file2) throw new Error(`No file at ${args.path} in this project. List them with animaguru files list.`);
|
|
50726
51015
|
if (!/^[a-f0-9]{64}$/.test(file2.sha)) throw new Error("Invalid blob hash in manifest.");
|
|
50727
51016
|
const response = await client.request(`/api/v1/blobs/${encodeURIComponent(manifest.ownerId)}/${file2.sha}`, { raw: true });
|
|
50728
|
-
const path =
|
|
50729
|
-
await
|
|
51017
|
+
const path = resolve18(flags.output);
|
|
51018
|
+
await mkdir16(dirname15(path), { recursive: true });
|
|
50730
51019
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
50731
51020
|
await writeFile16(path, bytes, { flag: "wx" });
|
|
50732
51021
|
out(stdout, { path, bytes: bytes.length });
|
|
@@ -50740,7 +51029,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50740
51029
|
const response = await client.request(`/api/v1/blobs/${encodeURIComponent(manifest.ownerId)}/${file2.sha}`, { raw: true });
|
|
50741
51030
|
entries[path2] = new Uint8Array(await response.arrayBuffer());
|
|
50742
51031
|
}
|
|
50743
|
-
const path =
|
|
51032
|
+
const path = resolve18(flags.output);
|
|
50744
51033
|
await writeFile16(path, zipSync(entries, { level: 0 }), { flag: "wx" });
|
|
50745
51034
|
out(stdout, { path, files: manifest.files.length });
|
|
50746
51035
|
})))).extend(version(package_default.version, { format: "plain" })).extend(help()).extend(completion());
|