@hypit/hypit 0.1.11 → 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 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?labels=bug">Open an issue</a></td>
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?labels=enhancement">Open an issue</a></td>
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
  [![Star History Chart](https://api.star-history.com/svg?repos=hypit-ai/hypit&type=Date)](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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypit/hypit",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "homepage": "https://hypit.ai",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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
- for (const [child, parent] of rows) if (parent === descendants[i] && child !== undefined) descendants.push(child);
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
- // Signal delivery is asynchronous. Wait for execution to stop while the
40
- // parent is still alive to reap its child; zombies no longer hold resources.
41
- const deadline = Date.now() + cleanupMs;
42
- while (true) {
43
- const state = await exec("ps", ["-p", String(child), "-o", "stat="], { timeout: cleanupMs })
44
- .then(({ stdout }) => stdout.trim(), (error) => {
45
- if (error.code === 1 && !error.stdout?.trim()) return "";
46
- throw error;
47
- });
48
- if (state === "" || state.startsWith("Z")) break;
49
- if (Date.now() >= deadline) throw new Error(`Render process ${child} did not stop after SIGKILL`);
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
 
@@ -82,7 +83,7 @@ export async function runCaptureProcess(
82
83
  const kill = () => {
83
84
  if (grace !== undefined) clearTimeout(grace);
84
85
  killing ??= (child.pid === undefined ? Promise.resolve() : killRenderTree(child.pid)).catch((error) => {
85
- failure = new Error(`${failure?.message ?? "Render cleanup failed"}; ${String(error)}`);
86
+ if (!completed) failure = new Error(`${failure?.message ?? "Render cleanup failed"}; ${String(error)}`);
86
87
  child.kill("SIGKILL");
87
88
  });
88
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
- export const seedanceComponent = seedanceBaseDefinition.component;
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