@hypit/hypit 0.1.10 → 0.1.12
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 +9 -3
- package/package.json +1 -1
- package/packages/package-loader-node/src/location.ts +8 -2
- package/packages/provider-hyperframes-local/src/capture-bootstrap.ts +25 -0
- package/packages/provider-hyperframes-local/src/capture-process.ts +25 -18
- package/packages/seedance/src/index.ts +18 -1
- package/packages/seedance/src/surface.ts +3 -0
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ The `/hypit` skill is available to coding agents. Start a session in any empty o
|
|
|
76
76
|
directory and ask it to create videos for you:
|
|
77
77
|
|
|
78
78
|
```text
|
|
79
|
-
/hypit Clone this video: /path/to/video
|
|
79
|
+
/hypit Clone this video: /path/to/video.mp4, and replace the ranking content with a comparison of Hypit (official website: hypit.ai) with other AI video products.
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Or start without a reference video:
|
|
@@ -132,11 +132,11 @@ commands and the repository layout.
|
|
|
132
132
|
<table>
|
|
133
133
|
<tr>
|
|
134
134
|
<td>Bug reports</td>
|
|
135
|
-
<td><a href="https://github.com/hypit-ai/hypit/issues/new?
|
|
135
|
+
<td><a href="https://github.com/hypit-ai/hypit/issues/new?template=bug_report.yml">Open an issue</a></td>
|
|
136
136
|
</tr>
|
|
137
137
|
<tr>
|
|
138
138
|
<td>Feature requests</td>
|
|
139
|
-
<td><a href="https://github.com/hypit-ai/hypit/issues/new?
|
|
139
|
+
<td><a href="https://github.com/hypit-ai/hypit/issues/new?template=feature_request.yml">Open an issue</a></td>
|
|
140
140
|
</tr>
|
|
141
141
|
<tr>
|
|
142
142
|
<td>Questions</td>
|
|
@@ -148,6 +148,12 @@ commands and the repository layout.
|
|
|
148
148
|
|
|
149
149
|
[](https://www.star-history.com/#hypit-ai/hypit&Date)
|
|
150
150
|
|
|
151
|
+
## Contributors
|
|
152
|
+
|
|
153
|
+
<a href="https://github.com/hypit-ai/hypit/graphs/contributors">
|
|
154
|
+
<img alt="Contributors" src="https://contrib.rocks/image?repo=hypit-ai/hypit">
|
|
155
|
+
</a>
|
|
156
|
+
|
|
151
157
|
## License
|
|
152
158
|
|
|
153
159
|
Hypit is released under the [Hypit Open Source License](https://github.com/hypit-ai/hypit/blob/main/LICENSE). The videos and other outputs you create belong to you; third-party models and services may have their own terms.
|
package/package.json
CHANGED
|
@@ -81,8 +81,14 @@ export function declaredExternalPackageRoot(root: string, from: string | URL, na
|
|
|
81
81
|
while (true) {
|
|
82
82
|
const manifest = join(cursor, "package.json");
|
|
83
83
|
if (existsSync(manifest)) {
|
|
84
|
-
const value = JSON.parse(readFileSync(manifest, "utf8")) as {
|
|
85
|
-
|
|
84
|
+
const value = JSON.parse(readFileSync(manifest, "utf8")) as {
|
|
85
|
+
dependencies?: Record<string, string>;
|
|
86
|
+
optionalDependencies?: Record<string, string>;
|
|
87
|
+
};
|
|
88
|
+
// An upstream asset a package ships as optional is still selected by one exact version here.
|
|
89
|
+
// `hypit packages install` places it under the machine npm root named by this selection, so
|
|
90
|
+
// reading only the required map makes the documented repair unusable for every optional asset.
|
|
91
|
+
const version = value.dependencies?.[name] ?? value.optionalDependencies?.[name];
|
|
86
92
|
return version === undefined ? undefined : externalPackageInstallRoot(root, name, version);
|
|
87
93
|
}
|
|
88
94
|
const parent = dirname(cursor);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preloaded into the disposable capture process, which never enters `bin/hypit.mjs`.
|
|
3
|
+
*
|
|
4
|
+
* `module.registerHooks` is process-local, so the resolver the launcher installs does not
|
|
5
|
+
* reach a child that Node starts directly. This registers the same resolution environment
|
|
6
|
+
* in the child, so its view of `@hypit/*` and of the machine packages those modules declare
|
|
7
|
+
* is identical to its parent's.
|
|
8
|
+
*
|
|
9
|
+
* Only relative paths can be used here: no hook exists yet, and a Distribution ships its
|
|
10
|
+
* package sources without any `node_modules` link between them.
|
|
11
|
+
*/
|
|
12
|
+
import { resolve } from "node:path";
|
|
13
|
+
|
|
14
|
+
// `bin/hypit.mjs` publishes this for every process it starts; the fallback mirrors
|
|
15
|
+
// `packages/video-cli/src/distribution.ts` for callers that import a Distribution directly.
|
|
16
|
+
const distributionRoot = resolve(
|
|
17
|
+
process.env.HYPIT_DISTRIBUTION_ROOT ?? resolve(import.meta.dirname, "../../.."),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const { installDistributionPackageResolution, installExternalPackageResolution } =
|
|
21
|
+
await import("../../package-loader-node/src/distribution-resolution.js");
|
|
22
|
+
installDistributionPackageResolution([distributionRoot]);
|
|
23
|
+
|
|
24
|
+
const { hypitHostPackageRoot } = await import("../../runtime-host-node/src/index.js");
|
|
25
|
+
installExternalPackageResolution([hypitHostPackageRoot()]);
|
|
@@ -25,30 +25,31 @@ async function killRenderTree(pid: number): Promise<void> {
|
|
|
25
25
|
}
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
const { stdout } = await exec("ps", ["-A", "-o", "pid=,ppid="], { timeout: cleanupMs });
|
|
29
|
-
const rows = stdout.trim().split("\n").map((line) => line.trim().split(/\s+/u).map(Number));
|
|
30
28
|
const descendants = [pid];
|
|
31
29
|
for (let i = 0; i < descendants.length; i++) {
|
|
32
|
-
|
|
30
|
+
const children = await exec("pgrep", ["-P", String(descendants[i])], { timeout: cleanupMs })
|
|
31
|
+
.then(({ stdout }) => stdout.trim().split(/\s+/u).filter(Boolean).map(Number),
|
|
32
|
+
(error) => { if ((error as { code?: unknown }).code === 1) return []; throw error; });
|
|
33
|
+
for (const child of children) if (!descendants.includes(child)) descendants.push(child);
|
|
33
34
|
}
|
|
35
|
+
// Kill the whole tree before waiting: only after every ancestor is dead are
|
|
36
|
+
// orphaned descendants reparented and reaped, making kill(pid, 0) read ESRCH.
|
|
34
37
|
for (const child of descendants.reverse()) {
|
|
35
38
|
for (const target of [-child, child]) {
|
|
36
39
|
try { process.kill(target, "SIGKILL"); }
|
|
37
40
|
catch (error) { if ((error as NodeJS.ErrnoException).code !== "ESRCH") throw error; }
|
|
38
41
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
await delay(20);
|
|
51
|
-
}
|
|
42
|
+
}
|
|
43
|
+
const deadline = Date.now() + cleanupMs;
|
|
44
|
+
let remaining = descendants;
|
|
45
|
+
while (remaining.length > 0) {
|
|
46
|
+
remaining = remaining.filter((child) => {
|
|
47
|
+
try { process.kill(child, 0); return true; }
|
|
48
|
+
catch (error) { if ((error as NodeJS.ErrnoException).code === "ESRCH") return false; throw error; }
|
|
49
|
+
});
|
|
50
|
+
if (remaining.length === 0) break;
|
|
51
|
+
if (Date.now() >= deadline) throw new Error(`Render process ${remaining[0]} did not stop after SIGKILL`);
|
|
52
|
+
await delay(20);
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -62,7 +63,13 @@ export async function runCaptureProcess(
|
|
|
62
63
|
): Promise<void> {
|
|
63
64
|
signal.throwIfAborted();
|
|
64
65
|
await new Promise<void>((resolve, reject) => {
|
|
65
|
-
|
|
66
|
+
// The launcher's resolver hooks are process-local, so this child preloads the same
|
|
67
|
+
// environment before it imports any package the Distribution owns.
|
|
68
|
+
const child = spawn(process.execPath, [
|
|
69
|
+
"--import", import.meta.resolve("tsx"),
|
|
70
|
+
"--import", new URL("./capture-bootstrap.ts", import.meta.url).href,
|
|
71
|
+
fileURLToPath(entry),
|
|
72
|
+
], {
|
|
66
73
|
detached: process.platform !== "win32", windowsHide: true,
|
|
67
74
|
stdio: ["ignore", "pipe", "pipe", "ipc"],
|
|
68
75
|
});
|
|
@@ -76,7 +83,7 @@ export async function runCaptureProcess(
|
|
|
76
83
|
const kill = () => {
|
|
77
84
|
if (grace !== undefined) clearTimeout(grace);
|
|
78
85
|
killing ??= (child.pid === undefined ? Promise.resolve() : killRenderTree(child.pid)).catch((error) => {
|
|
79
|
-
failure = new Error(`${failure?.message ?? "Render cleanup failed"}; ${String(error)}`);
|
|
86
|
+
if (!completed) failure = new Error(`${failure?.message ?? "Render cleanup failed"}; ${String(error)}`);
|
|
80
87
|
child.kill("SIGKILL");
|
|
81
88
|
});
|
|
82
89
|
return killing;
|
|
@@ -326,7 +326,24 @@ export const seedanceMarkupSurfaces = [
|
|
|
326
326
|
|
|
327
327
|
/** The duration is an author literal on every Seedance Surface, so the manifest is the exact-model module's own. */
|
|
328
328
|
export const seedanceManifest = seedanceBaseDefinition.manifest;
|
|
329
|
-
|
|
329
|
+
|
|
330
|
+
const referenceAudioProducers = new Set(Object.values(seedanceEndpoints)
|
|
331
|
+
.map((endpoint) => endpoint.mediaBindings["referenceAudio"]!.producer.name));
|
|
332
|
+
|
|
333
|
+
export const seedanceComponent = {
|
|
334
|
+
...seedanceBaseDefinition.component,
|
|
335
|
+
producers: seedanceBaseDefinition.component.producers.map((facet) =>
|
|
336
|
+
referenceAudioProducers.has(facet.producer.name) ? {
|
|
337
|
+
...facet,
|
|
338
|
+
handler: (context: Parameters<typeof facet.handler>[0]) => {
|
|
339
|
+
const artifact = context.inputs.artifact?.value;
|
|
340
|
+
if (artifact?.kind === "blob" && ["audio/mp4", "audio/x-m4a"].includes(artifact.mediaType)) {
|
|
341
|
+
throw new Error("Seedance reference audio does not accept m4a; convert to wav or mp3");
|
|
342
|
+
}
|
|
343
|
+
return facet.handler(context);
|
|
344
|
+
},
|
|
345
|
+
} : facet),
|
|
346
|
+
};
|
|
330
347
|
export const seedanceDefinition = seedanceBaseDefinition;
|
|
331
348
|
|
|
332
349
|
export {
|
|
@@ -109,6 +109,9 @@ function mediaReference(
|
|
|
109
109
|
if (value !== undefined && (value.kind !== "blob" || !value.mediaType.startsWith(`${role}/`))) {
|
|
110
110
|
throw new Error(`${subject} must reference ${role} media`);
|
|
111
111
|
}
|
|
112
|
+
if (value !== undefined && value.kind === "blob" && role === "audio" && ["audio/mp4", "audio/x-m4a"].includes(value.mediaType)) {
|
|
113
|
+
throw new Error(`${subject} references m4a audio, which Seedance does not accept; convert to wav or mp3 and admit that file`);
|
|
114
|
+
}
|
|
112
115
|
return reference;
|
|
113
116
|
}
|
|
114
117
|
|