ossclip 0.1.27 → 0.1.28

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>ossclip editor</title>
7
- <script type="module" crossorigin src="/assets/index-CWIUcpJC.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-BBJKC2Z2.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-Bx2VQLP8.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ossclip",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "Local-first CLI video producer: cuts silence and fillers, word-timed captions, face-aware framing, and LLM-planned code-rendered graphics — transcription and rendering never leave your machine",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,9 +36,9 @@
36
36
  "commander": "^12.1.0",
37
37
  "tsx": "^4.19.0",
38
38
  "zod": "^3.25.76",
39
- "@ossclip/core": "0.1.27",
40
- "@ossclip/scenes": "0.1.27",
41
- "@ossclip/renderer": "0.1.27"
39
+ "@ossclip/core": "0.1.28",
40
+ "@ossclip/scenes": "0.1.28",
41
+ "@ossclip/renderer": "0.1.28"
42
42
  },
43
43
  "homepage": "https://github.com/AhsanAyaz/ossclip#readme",
44
44
  "bugs": {
package/src/edit.ts CHANGED
@@ -30,6 +30,8 @@ import {
30
30
  PORTRAIT_MIME_TYPES,
31
31
  portraitMimeType,
32
32
  readCoverProvenance,
33
+ SegmentSchema,
34
+ type Segment,
33
35
  thumbnailImageCacheName,
34
36
  type CoverProvenance,
35
37
  type GenerateThumbnailImageOptions,
@@ -548,6 +550,46 @@ export async function startEditServer(
548
550
  });
549
551
  }
550
552
 
553
+ if (url.pathname === "/api/cleanup" && req.method === "GET") {
554
+ // The labeled removals: since cut review step 3 this serves the
555
+ // PROPOSAL (`cutlistProposed` — the automatic cutlist before the
556
+ // user's cleanup vetoes and user cuts), because that is what the
557
+ // editor's checkboxes and seams reason about: a DECLINED pause has
558
+ // already merged into a plain keep in the resolved `cutlist`, so
559
+ // serving that would make the veto invisible the moment it worked.
560
+ // The fallback to `cutlist` keeps pre-step-3 workdirs drawing their
561
+ // seams — back then the recorded cutlist WAS the proposal (plus
562
+ // applied user cuts, whose seams the applied-cut restore marker
563
+ // draws independently anyway). Same lenient-read posture as
564
+ // /api/usage above: a missing or corrupt production.json degrades
565
+ // to an empty cutlist, never a 500 — the timeline simply draws no
566
+ // removal seams.
567
+ if (!workdir) return send(409, { error: "no workdir open" });
568
+ let cutlist: Segment[] = [];
569
+ try {
570
+ const production = JSON.parse(
571
+ await readFile(join(workdir, "production.json"), "utf8"),
572
+ ) as { cutlist?: unknown; cutlistProposed?: unknown };
573
+ const source = Array.isArray(production.cutlistProposed)
574
+ ? production.cutlistProposed
575
+ : production.cutlist;
576
+ if (Array.isArray(source)) {
577
+ // Each span parses ALONE: a hand-edited production.json with
578
+ // one bad span (a string srcIn, a negative time) drops that
579
+ // span and keeps the rest, instead of either 500ing or letting
580
+ // a NaN through to position a seam off-screen. zod parse, not
581
+ // a cast — the house rule for anything a user can have edited.
582
+ cutlist = source.flatMap((s) => {
583
+ const parsed = SegmentSchema.safeParse(s);
584
+ return parsed.success ? [parsed.data] : [];
585
+ });
586
+ }
587
+ } catch {
588
+ // degrade — same as /api/usage's readJson
589
+ }
590
+ return send(200, { cutlist });
591
+ }
592
+
551
593
  if (url.pathname === "/api/workdir" && req.method === "POST") {
552
594
  // Open/switch the project (R17 §83). Refused mid-render: the
553
595
  // running child belongs to the CURRENT workdir, and its status
package/src/llm-detect.ts CHANGED
@@ -60,3 +60,14 @@ export function detectionLine(name: ProviderName): string {
60
60
  return "▸ using the mock provider (no LLM)";
61
61
  }
62
62
  }
63
+
64
+ /**
65
+ * The out-loud line for a §143 timeout fallback (2026-08-22): agy expired its
66
+ * own print timeout on the editorial call and another provider is answering
67
+ * it. Names all three facts — who failed, on which call, who took over —
68
+ * because a silent substitution would be worse than the hang: the user must
69
+ * know which model planned their video.
70
+ */
71
+ export function fallbackLine(from: string, to: string, schemaName: string): string {
72
+ return `⚠ ${from} timed out on ${schemaName} — falling back to ${to}`;
73
+ }