@mevdragon/vidfarm-devcli 0.20.6 → 0.20.9

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.
Files changed (157) hide show
  1. package/.agents/skills/editor-capabilities/SKILL.md +15 -1
  2. package/.agents/skills/vidfarm-director/SKILL.md +106 -0
  3. package/.agents/skills/vidfarm-director/recipes/find-and-fork-template.md +16 -0
  4. package/.agents/skills/vidfarm-director/recipes/local-edit-render-approve.md +13 -0
  5. package/.agents/skills/vidfarm-director/recipes/onboard-a-new-director.md +13 -0
  6. package/.agents/skills/vidfarm-director/recipes/retheme-template.md +17 -0
  7. package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +117 -0
  8. package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +245 -0
  9. package/.agents/skills/vidfarm-director/references/core-workflows.md +273 -0
  10. package/.agents/skills/vidfarm-director/references/editor-workflows.md +365 -0
  11. package/.agents/skills/vidfarm-director/references/onboarding.md +28 -0
  12. package/.agents/skills/vidfarm-director/references/primitives.md +308 -0
  13. package/SKILL.director.md +517 -250
  14. package/dist/src/cli.js +563 -99
  15. package/dist/src/devcli/clips.js +29 -12
  16. package/dist/src/devcli/doctor.js +2 -2
  17. package/dist/src/devcli/local-backend.js +46 -2
  18. package/dist/src/services/clip-curation/cost.js +5 -1
  19. package/dist/src/services/clip-curation/gemini.js +14 -2
  20. package/dist/src/services/clip-curation/hunt.js +56 -0
  21. package/dist/src/services/clip-curation/index.js +1 -1
  22. package/dist/src/services/clip-curation/scan.js +5 -3
  23. package/package.json +30 -10
  24. package/SKILL.platform.md +0 -432
  25. package/demo/README.md +0 -28
  26. package/demo/dist/app.css +0 -1
  27. package/demo/dist/app.js +0 -1850
  28. package/demo/dist/chunks/chunk-DXB73IDG.js +0 -1
  29. package/demo/dist/chunks/chunk-S7OWAJDS.js +0 -36
  30. package/demo/dist/chunks/chunk-VTIBZ6AN.js +0 -1
  31. package/demo/dist/chunks/dist-ADSJKBVE.js +0 -332
  32. package/demo/dist/chunks/domEditingLayers-VZMLL4AP-SGHWPND4.js +0 -1
  33. package/demo/dist/chunks/hyperframes-player-XB65TCD6.js +0 -425
  34. package/demo/dist/chunks/lib-XAQ37YOE.js +0 -1
  35. package/demo/dist/chunks/src-TJ2QYA4U.js +0 -207
  36. package/demo/dist/favicon.ico +0 -0
  37. package/demo/dist/icons/timeline/audio.svg +0 -7
  38. package/demo/dist/icons/timeline/captions.svg +0 -5
  39. package/demo/dist/icons/timeline/composition.svg +0 -12
  40. package/demo/dist/icons/timeline/image.svg +0 -18
  41. package/demo/dist/icons/timeline/music.svg +0 -10
  42. package/demo/dist/icons/timeline/text.svg +0 -3
  43. package/demo/dist/index.html +0 -15
  44. package/dist/src/account-pages-legacy.js +0 -9396
  45. package/dist/src/account-pages.js +0 -61
  46. package/dist/src/app.js +0 -21603
  47. package/dist/src/composition-runtime.js +0 -1053
  48. package/dist/src/config.js +0 -217
  49. package/dist/src/context.js +0 -447
  50. package/dist/src/dev-app-legacy.js +0 -739
  51. package/dist/src/dev-app.js +0 -6
  52. package/dist/src/devcli/migrate-local.js +0 -140
  53. package/dist/src/devcli/sync.js +0 -368
  54. package/dist/src/domain.js +0 -5
  55. package/dist/src/editor-chat-history.js +0 -82
  56. package/dist/src/editor-chat.js +0 -828
  57. package/dist/src/editor-dark-theme.js +0 -1128
  58. package/dist/src/frontend/debug.js +0 -71
  59. package/dist/src/frontend/discover-client.js +0 -130
  60. package/dist/src/frontend/discover-store.js +0 -23
  61. package/dist/src/frontend/file-directory.js +0 -1018
  62. package/dist/src/frontend/flockposter-cache-store.js +0 -124
  63. package/dist/src/frontend/homepage-client.js +0 -446
  64. package/dist/src/frontend/homepage-shared.js +0 -201
  65. package/dist/src/frontend/homepage-store.js +0 -66
  66. package/dist/src/frontend/homepage-view.js +0 -705
  67. package/dist/src/frontend/page-runtime-client.js +0 -132
  68. package/dist/src/frontend/page-runtime-store.js +0 -9
  69. package/dist/src/frontend/sentry.js +0 -42
  70. package/dist/src/frontend/template-editor-chat.js +0 -4181
  71. package/dist/src/help-page.js +0 -346
  72. package/dist/src/homepage.js +0 -1458
  73. package/dist/src/index.js +0 -16
  74. package/dist/src/instrument.js +0 -30
  75. package/dist/src/landing-page.js +0 -384
  76. package/dist/src/page-runtime.js +0 -2
  77. package/dist/src/page-shell.js +0 -1452
  78. package/dist/src/primitive-context.js +0 -416
  79. package/dist/src/primitive-registry.js +0 -3940
  80. package/dist/src/primitive-sdk.js +0 -4
  81. package/dist/src/primitives/hyperframes-media.js +0 -108
  82. package/dist/src/react-page-shell.js +0 -35
  83. package/dist/src/ready-post-schedule-component.js +0 -1540
  84. package/dist/src/registry.js +0 -296
  85. package/dist/src/reskin/agency-page.js +0 -299
  86. package/dist/src/reskin/calendar-page.js +0 -568
  87. package/dist/src/reskin/chat-page.js +0 -942
  88. package/dist/src/reskin/discover-page.js +0 -1788
  89. package/dist/src/reskin/document.js +0 -1587
  90. package/dist/src/reskin/help-page.js +0 -357
  91. package/dist/src/reskin/index-page.js +0 -62
  92. package/dist/src/reskin/inpaint-clipper-page.js +0 -890
  93. package/dist/src/reskin/inpaint-page.js +0 -2554
  94. package/dist/src/reskin/inpaint-video-page.js +0 -1339
  95. package/dist/src/reskin/job-runs-page.js +0 -477
  96. package/dist/src/reskin/library-page.js +0 -1634
  97. package/dist/src/reskin/login-page.js +0 -262
  98. package/dist/src/reskin/portfolio-page.js +0 -687
  99. package/dist/src/reskin/pricing-page.js +0 -390
  100. package/dist/src/reskin/settings-page.js +0 -732
  101. package/dist/src/reskin/theme.js +0 -711
  102. package/dist/src/runtime.js +0 -35
  103. package/dist/src/services/api-call-history.js +0 -249
  104. package/dist/src/services/auth.js +0 -152
  105. package/dist/src/services/billing-pricing.js +0 -39
  106. package/dist/src/services/billing.js +0 -241
  107. package/dist/src/services/cast.js +0 -127
  108. package/dist/src/services/chat-threads.js +0 -92
  109. package/dist/src/services/clip-records.js +0 -250
  110. package/dist/src/services/clip-search.js +0 -77
  111. package/dist/src/services/clip-vectors.js +0 -125
  112. package/dist/src/services/composition-sanitize.js +0 -124
  113. package/dist/src/services/composition-watch.js +0 -79
  114. package/dist/src/services/elevenlabs.js +0 -222
  115. package/dist/src/services/file-directory.js +0 -117
  116. package/dist/src/services/fork-access.js +0 -93
  117. package/dist/src/services/fork-manifest.js +0 -42
  118. package/dist/src/services/ghostcut.js +0 -179
  119. package/dist/src/services/hyperframes.js +0 -3654
  120. package/dist/src/services/job-capacity.js +0 -14
  121. package/dist/src/services/job-logs.js +0 -197
  122. package/dist/src/services/jobs.js +0 -136
  123. package/dist/src/services/local-dynamo.js +0 -0
  124. package/dist/src/services/media-processing.js +0 -766
  125. package/dist/src/services/primitive-media-lambda.js +0 -280
  126. package/dist/src/services/providers.js +0 -2748
  127. package/dist/src/services/rate-limits.js +0 -262
  128. package/dist/src/services/scene-annotations.js +0 -32
  129. package/dist/src/services/serverless-auth.js +0 -382
  130. package/dist/src/services/serverless-jobs.js +0 -1084
  131. package/dist/src/services/serverless-provider-keys.js +0 -409
  132. package/dist/src/services/serverless-records.js +0 -1515
  133. package/dist/src/services/serverless-template-configs.js +0 -75
  134. package/dist/src/services/storage.js +0 -461
  135. package/dist/src/services/swipe-customize.js +0 -437
  136. package/dist/src/services/template-certification.js +0 -413
  137. package/dist/src/services/template-loader.js +0 -99
  138. package/dist/src/services/template-runtime-bundles.js +0 -217
  139. package/dist/src/services/template-sources.js +0 -1017
  140. package/dist/src/services/upstream.js +0 -248
  141. package/dist/src/services/video-normalization.js +0 -2
  142. package/dist/src/services/webhooks.js +0 -62
  143. package/dist/src/template-editor-pages.js +0 -2576
  144. package/dist/src/template-editor-shell.js +0 -2893
  145. package/dist/src/template-sdk.js +0 -4
  146. package/dist/src/worker.js +0 -17
  147. package/public/assets/discover-client-app.js +0 -1
  148. package/public/assets/file-directory-app.js +0 -3
  149. package/public/assets/homepage-app.js +0 -54
  150. package/public/assets/homepage-client-app.js +0 -80
  151. package/public/assets/page-runtime-client-app.js +0 -94
  152. package/public/assets/placeholders/scene-placeholder.png +0 -0
  153. package/src/assets/SELLING_AWARENESS_STAGES.md +0 -579
  154. package/src/assets/SELLING_WITH_HOOKS.md +0 -377
  155. package/src/assets/SELLING_WITH_VSLS.md +0 -606
  156. package/src/assets/favicon.ico +0 -0
  157. package/src/assets/logo-vidfarm.png +0 -0
@@ -1,477 +0,0 @@
1
- // /reskin/job-runs — render & job history / health, MIGRATED to real production
2
- // data (part of the /reskin/* UX migration; reference: settings-page.ts).
3
- //
4
- // Like the live page (src/account-pages-legacy.ts → renderJobRunsPage), this
5
- // renders a SHELL then CLIENT-FETCHES the real history from `input.loadEndpoint`
6
- // (`/job-runs/history?limit=250`, same-origin, credentials). The endpoint
7
- // returns `{ entries, storage_driver, next_cursor }`; each entry is an
8
- // api-call-history row (`id, method, path, routePrefix, tracer, jobId, status,
9
- // durationMs, request, response, mediaUrls, outputMediaUrls, createdAt`) with an
10
- // optional resolved `linkedJob` ({ job_id, template_id, operation_name,
11
- // workflow_name, tracer, status, progress, started_at, completed_at,
12
- // billing.consumed_usd, ... }). We map each entry into a farmville run row —
13
- // status tile (✓/●/✕/◔), friendly type + job id, primitive/tracer sub-meta,
14
- // started + duration, REAL compute cost from `linkedJob.billing.consumed_usd`,
15
- // and an inline "View logs" details panel. Summary counts + compute total are
16
- // recomputed from the real data; the status filter runs over the real rows.
17
- //
18
- // The renderer takes the SAME input the live route builds
19
- // (`Parameters<typeof renderJobRunsPage>[0]`) and defaults it, so the existing
20
- // zero-arg `/reskin/job-runs` route keeps working (it fetches the live endpoint
21
- // client-side). NOTE: `linkedJob.billing` is present at RUNTIME on the real
22
- // endpoint but omitted from the declared input type — the client reads it off
23
- // the parsed JSON, so cost is real, not mocked.
24
- import { reskinDocument, rkEscape } from "./document.js";
25
- const DEFAULT_INPUT = {
26
- userId: "",
27
- currentAccountId: "",
28
- name: null,
29
- email: "",
30
- storageDriver: "s3",
31
- loadEndpoint: "/job-runs/history?limit=250",
32
- jobs: [],
33
- apiCallHistory: []
34
- };
35
- /** Safe JSON embedding inside a <script> tag (mirrors page-shell.escapeJsonForHtml). */
36
- function jsonForScript(value) {
37
- return JSON.stringify(value ?? null)
38
- .replace(/</g, "\\u003c")
39
- .replace(/>/g, "\\u003e")
40
- .replace(/&/g, "\\u0026")
41
- .replace(/\u2028/g, "\\u2028")
42
- .replace(/\u2029/g, "\\u2029");
43
- }
44
- /** Server-rendered filter chip (counts start at 0; the client fills them). */
45
- function statChip(filter, label, tone, active = false) {
46
- return `<button type="button" class="rk-jobs-chip${tone}${active ? " is-active" : ""}" data-rk-filter="${filter}">
47
- ${rkEscape(label)}<span class="rk-jobs-chip-n" data-rk-count="${filter}">0</span>
48
- </button>`;
49
- }
50
- export function renderReskinJobRuns(input = DEFAULT_INPUT) {
51
- const loadEndpoint = input.loadEndpoint || "/job-runs/history?limit=250";
52
- const accountId = input.currentAccountId || "";
53
- const storageDriver = input.storageDriver || "s3";
54
- const seed = Array.isArray(input.apiCallHistory) ? input.apiCallHistory : [];
55
- const boot = { loadEndpoint, accountId, storageDriver, entries: seed };
56
- const body = `
57
- <main class="rk-container rk-page">
58
- <div class="rk-page-head">
59
- <h1 class="rk-h1">Job runs</h1>
60
- <p class="rk-sub">Every render, clip scan, decompose and primitive job — with status, timing, and the compute it cost.</p>
61
- </div>
62
- ${jobRunsPanel(boot)}
63
- </main>`;
64
- return reskinDocument({
65
- title: "vidfarm reskin — Job runs",
66
- description: "Reskinned vidfarm job runs page — real render & job history, status, timing, and compute cost.",
67
- activeSlug: "job-runs",
68
- pageCss: JOBRUNS_PAGE_CSS,
69
- body,
70
- script: JOBRUNS_SCRIPT
71
- });
72
- }
73
- // The runs panel (summary + filterable list + boot JSON), WITHOUT the page
74
- // <main>/head — so it can be embedded standalone (renderReskinJobRuns) OR folded
75
- // into the Library "Logs" tab (library-page.ts). Hoisted; safe to call above.
76
- export function jobRunsPanel(boot) {
77
- return `
78
- <div class="rk-jobs-summary" data-rk-summary>Loading run history&hellip;</div>
79
-
80
- <div class="rk-card rk-jobs-panel">
81
- <div class="rk-spread rk-wrap rk-jobs-panel-head">
82
- <div class="rk-jobs-filters" role="group" aria-label="Filter runs by status">
83
- ${statChip("all", "All", "", true)}
84
- ${statChip("succeeded", "Succeeded", " is-green")}
85
- ${statChip("running", "Running", " is-gold")}
86
- ${statChip("failed", "Failed", " is-red")}
87
- ${statChip("queued", "Queued", " is-ink")}
88
- </div>
89
- <div class="rk-row">
90
- <span class="rk-pill rk-pill-gold rk-jobs-live"><span class="rk-jobs-live-dot"></span>Live</span>
91
- <button type="button" class="rk-btn rk-btn-ghost rk-btn-sm" data-rk-refresh>&#8635; Refresh</button>
92
- </div>
93
- </div>
94
-
95
- <div class="rk-jobs-head" aria-hidden="true">
96
- <span></span>
97
- <span>Run</span>
98
- <span class="rk-jobs-tail rk-jobs-head-tail">
99
- <span class="rk-jobs-when">Started</span>
100
- <span class="rk-jobs-cost">Cost</span>
101
- <span class="rk-jobs-logs-h"></span>
102
- </span>
103
- </div>
104
-
105
- <div class="rk-jobs-list" data-rk-list></div>
106
- <div class="rk-jobs-state" data-rk-state>Loading run history&hellip;</div>
107
- <div class="rk-jobs-empty" data-rk-empty hidden>No runs match this filter.</div>
108
-
109
- <div class="rk-row rk-jobs-foot">
110
- <button type="button" class="rk-btn rk-btn-ghost rk-btn-sm" data-rk-more hidden>Load older runs</button>
111
- <span class="rk-hint" data-rk-count-foot></span>
112
- </div>
113
- </div>
114
-
115
- <script type="application/json" data-rk-jobs-boot>${jsonForScript(boot)}</script>`;
116
- }
117
- export const JOBRUNS_PAGE_CSS = `
118
- .rk-jobs-summary{font-size:13.5px;color:var(--rk-text-muted);font-weight:500;margin-bottom:22px;line-height:1.7;min-height:24px}
119
- .rk-jobs-summary b{color:var(--rk-ink);font-weight:800;font-family:var(--rk-font-display);font-size:15px;letter-spacing:-.01em}
120
- .rk-jobs-summary-note{color:var(--rk-text-faint)}
121
- .rk-jobs-panel{padding:22px 22px 18px}
122
-
123
- /* status tiles not in the shared set */
124
- .rk-jobs-tile{font-size:15px;font-weight:800}
125
- .rk-jobs-tile-run{background:var(--rk-gold-tint2);color:var(--rk-gold-700);animation:rk-jobs-pulse 1.6s var(--rk-ease) infinite}
126
- .rk-jobs-tile-fail{background:var(--rk-red-tint);color:#b91c1c}
127
- @keyframes rk-jobs-pulse{0%,100%{box-shadow:0 0 0 0 rgba(246,199,68,.55)}50%{box-shadow:0 0 0 6px rgba(246,199,68,0)}}
128
-
129
- /* filter chips */
130
- .rk-jobs-panel-head{margin-bottom:18px}
131
- .rk-jobs-filters{display:flex;flex-wrap:wrap;gap:8px}
132
- .rk-jobs-chip{display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:var(--rk-r-full);
133
- font-family:var(--rk-font-body);font-size:13px;font-weight:600;color:var(--rk-n-600);cursor:pointer;
134
- background:#fff;border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-xs);
135
- transition:border-color var(--rk-dur) var(--rk-ease),background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease)}
136
- .rk-jobs-chip:hover{border-color:var(--rk-border-strong)}
137
- .rk-jobs-chip-n{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 6px;border-radius:var(--rk-r-full);
138
- background:var(--rk-n-100);color:var(--rk-n-600);font-size:11px;font-weight:700}
139
- .rk-jobs-chip.is-active{background:var(--rk-ink);color:#fff;border-color:var(--rk-ink)}
140
- .rk-jobs-chip.is-active .rk-jobs-chip-n{background:#ffffff26;color:#fff}
141
- .rk-jobs-chip.is-green.is-active{background:#15803d;border-color:#15803d}
142
- .rk-jobs-chip.is-gold.is-active{background:var(--rk-gold-500);border-color:var(--rk-gold-500);color:var(--rk-ink)}
143
- .rk-jobs-chip.is-gold.is-active .rk-jobs-chip-n{background:#00000012;color:var(--rk-ink)}
144
- .rk-jobs-chip.is-red.is-active{background:#b91c1c;border-color:#b91c1c}
145
- .rk-jobs-chip.is-ink.is-active{background:var(--rk-n-700);border-color:var(--rk-n-700)}
146
-
147
- .rk-jobs-live{gap:7px}
148
- .rk-jobs-live-dot{width:7px;height:7px;border-radius:50%;background:var(--rk-gold-700);animation:rk-jobs-pulse 1.6s var(--rk-ease) infinite}
149
-
150
- /* table-ish column header — 5 tracks that the display:contents tail flows into */
151
- .rk-jobs-head{display:grid;grid-template-columns:44px minmax(0,1fr) 156px 78px auto;gap:16px;align-items:center;
152
- padding:0 16px 10px;font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--rk-text-faint)}
153
- .rk-jobs-head .rk-jobs-when{justify-items:start;text-align:left}
154
- .rk-jobs-head .rk-jobs-cost{text-align:right}
155
-
156
- /* run rows */
157
- .rk-jobs-list{display:grid;gap:10px}
158
- .rk-jobs-item{min-width:0}
159
- .rk-jobs-item[hidden]{display:none}
160
- .rk-jobs-row{display:grid;grid-template-columns:44px minmax(0,1fr) 156px 78px auto;gap:16px;align-items:center;
161
- padding:14px 16px;background:#fff;border:1px solid var(--rk-border);border-radius:var(--rk-r-2xl);
162
- box-shadow:var(--rk-shadow-xs);transition:box-shadow var(--rk-dur) var(--rk-ease),transform var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease)}
163
- .rk-jobs-row:hover{box-shadow:var(--rk-shadow-md);border-color:var(--rk-border-strong)}
164
- .rk-jobs-item[data-rk-status="running"] .rk-jobs-row{border-color:var(--rk-gold-tint2);background:linear-gradient(180deg,var(--rk-gold-tint) 0%,#fff 42%)}
165
- .rk-jobs-main{min-width:0}
166
- .rk-jobs-row-title{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:4px}
167
- .rk-jobs-type{font-family:var(--rk-font-display);font-weight:700;font-size:15px;color:var(--rk-ink);letter-spacing:-.01em}
168
- .rk-jobs-id{font-size:12px;color:var(--rk-text-faint)}
169
- .rk-jobs-sub{font-size:13px;color:var(--rk-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
170
-
171
- .rk-jobs-tail{display:contents}
172
- .rk-jobs-when{width:156px;display:grid;gap:5px;justify-items:end;text-align:right}
173
- .rk-jobs-when-at{font-size:13px;font-weight:600;color:var(--rk-n-700)}
174
- .rk-jobs-when-dur{font-size:12px;color:var(--rk-text-muted)}
175
- .rk-jobs-when-dur.is-run{color:var(--rk-gold-700);font-weight:700}
176
- .rk-jobs-when-dur.is-wait{color:var(--rk-text-faint)}
177
- .rk-jobs-progress{width:100%;height:6px;border-radius:var(--rk-r-full);background:var(--rk-gold-tint2);overflow:hidden}
178
- .rk-jobs-progress-bar{display:block;height:100%;border-radius:var(--rk-r-full);
179
- background:linear-gradient(90deg,var(--rk-gold-500),var(--rk-gold-700))}
180
- .rk-jobs-cost{width:78px;text-align:right;font-family:var(--rk-font-display);font-weight:700;font-size:15px;color:var(--rk-n-700)}
181
- .rk-jobs-cost.is-zero{color:var(--rk-text-faint);font-weight:500}
182
- .rk-jobs-logs{flex:none}
183
-
184
- /* inline "View logs" details panel */
185
- .rk-jobs-details{margin-top:8px;padding:14px 16px;background:var(--rk-n-50);border:1px solid var(--rk-border);
186
- border-radius:var(--rk-r-2xl);display:grid;gap:8px;font-size:13px}
187
- .rk-jobs-details[hidden]{display:none}
188
- .rk-jobs-detail-row{display:flex;gap:12px;align-items:baseline}
189
- .rk-jobs-detail-k{flex:none;min-width:96px;color:var(--rk-text-faint);font-weight:800;font-size:10.5px;
190
- letter-spacing:.06em;text-transform:uppercase;padding-top:1px}
191
- .rk-jobs-detail-v{color:var(--rk-n-700);word-break:break-word;min-width:0;font-family:var(--rk-font-mono);font-size:12.5px}
192
- .rk-jobs-detail-media{display:flex;flex-wrap:wrap;gap:8px}
193
- .rk-jobs-detail-media a{font-family:var(--rk-font-body);font-size:12px;font-weight:600;color:#1d6fb8;
194
- padding:3px 10px;border-radius:var(--rk-r-full);background:var(--rk-sky-tint)}
195
-
196
- /* load / empty / error states */
197
- .rk-jobs-state{padding:44px 16px;text-align:center;color:var(--rk-text-muted);font-size:14px;
198
- background:#fff;border:1px solid var(--rk-border);border-radius:var(--rk-r-2xl);box-shadow:var(--rk-shadow-xs)}
199
- .rk-jobs-state[hidden]{display:none}
200
- .rk-jobs-state.is-error{color:#b91c1c;background:var(--rk-red-tint);border-color:#fecaca;font-weight:500}
201
- .rk-jobs-empty{padding:36px 16px;text-align:center;color:var(--rk-text-muted);font-size:14px}
202
- .rk-jobs-empty[hidden]{display:none}
203
- .rk-jobs-foot{margin-top:16px;justify-content:space-between}
204
- /* .rk-btn sets display:inline-flex, which beats the UA [hidden] rule — force it */
205
- [data-rk-more][hidden]{display:none}
206
-
207
- @media(max-width:780px){
208
- .rk-jobs-head{display:none}
209
- .rk-jobs-row{grid-template-columns:44px minmax(0,1fr);row-gap:12px}
210
- .rk-jobs-tail{display:flex;grid-column:1 / -1;flex-wrap:wrap;align-items:center;gap:14px;padding-left:60px}
211
- .rk-jobs-when{width:auto;justify-items:start;text-align:left}
212
- .rk-jobs-progress{width:120px}
213
- .rk-jobs-cost{width:auto;text-align:left}
214
- .rk-jobs-logs{margin-left:auto}
215
- }
216
- @media(max-width:520px){
217
- .rk-jobs-foot{flex-direction:column;align-items:flex-start;gap:10px}
218
- }
219
- `;
220
- export const JOBRUNS_SCRIPT = `
221
- (function(){
222
- var root=document;
223
- var bootEl=root.querySelector('[data-rk-jobs-boot]');
224
- var boot={};
225
- try{ boot=JSON.parse(bootEl&&bootEl.textContent?bootEl.textContent:'{}'); }catch(e){ boot={}; }
226
- var loadEndpoint=boot.loadEndpoint||'/job-runs/history?limit=250';
227
- var accountId=boot.accountId||'';
228
-
229
- var listEl=root.querySelector('[data-rk-list]');
230
- var stateEl=root.querySelector('[data-rk-state]');
231
- var emptyEl=root.querySelector('[data-rk-empty]');
232
- var summaryEl=root.querySelector('[data-rk-summary]');
233
- var footEl=root.querySelector('[data-rk-count-foot]');
234
- var moreBtn=root.querySelector('[data-rk-more]');
235
- var refreshBtn=root.querySelector('[data-rk-refresh]');
236
-
237
- var state={ entries:[], filter:'all', nextCursor:null, loading:false, error:null };
238
-
239
- function esc(v){ return String(v==null?'':v).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;'); }
240
- function money(n){ n=Number(n)||0; if(!n) return '\\u2014'; return '$'+n.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2}); }
241
- function humanMs(ms){ ms=Number(ms)||0; if(ms<1000) return ms+'ms'; var s=Math.round(ms/1000); if(s<60) return s+'s'; var m=Math.floor(s/60); var r=s%60; return m+'m '+(r<10?'0':'')+r+'s'; }
242
- function whenText(iso){ var t=Date.parse(iso); if(isNaN(t)) return ''; var d=new Date(t); return d.toLocaleDateString('en-US',{month:'short',day:'numeric'})+', '+d.toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'}); }
243
- function shortId(id){ id=String(id||''); return id.length>18? id.slice(0,16)+'\\u2026' : id; }
244
-
245
- var TYPE_MAP={timeline_render:'Timeline render',hyperframes_render:'HyperFrames render',still_render:'Still render',render_still:'Still render',clip_scan_lambda:'Clip scan',clip_scan:'Clip scan',decompose:'Decompose',scene_annotation:'Scene annotation',cast_identification:'Cast identification',product_placement:'Product placement',swipe_customize:'Swipe customize',tts:'Text-to-speech',stt:'Speech-to-text',image_generate:'Image generate',image_edit:'Image edit',video_download:'Video download',video_generate:'Video generate',render_slides:'Slide render',captions:'Animated captions',transcribe:'Transcribe',speech:'Narration',regenerate_speech:'Revoice narration',remove_captions:'Caption removal',dedupe:'Media dedupe'};
246
- function prettify(raw){
247
- raw=String(raw||'').replace(/^primitive:/,'').trim();
248
- if(!raw) return 'Job';
249
- var key=raw.split('/').filter(Boolean).pop()||raw;
250
- key=key.replace(/:/g,'_');
251
- if(TYPE_MAP[key]) return TYPE_MAP[key];
252
- var words=key.split(/[_\\-\\s]+/).filter(Boolean);
253
- if(!words.length) return 'Job';
254
- return words.map(function(w,i){ return i===0? (w.charAt(0).toUpperCase()+w.slice(1)) : w.toLowerCase(); }).join(' ');
255
- }
256
- function typeLabel(entry){
257
- var j=entry.linkedJob;
258
- var raw=(j&&(j.operation_name||j.workflow_name||j.template_id))||'';
259
- if(!raw) raw=entry.routePrefix||entry.path||'';
260
- return prettify(raw);
261
- }
262
- function operationStr(entry){
263
- var j=entry.linkedJob;
264
- return String((j&&(j.template_id||j.operation_name))||entry.routePrefix||entry.path||'\\u2014');
265
- }
266
- function runStatus(entry){
267
- var j=entry.linkedJob;
268
- if(j&&j.status){
269
- var s=String(j.status).toLowerCase();
270
- if(s==='failed'||s==='cancelled'||s==='canceled'||s==='error') return 'failed';
271
- if(s==='queued'||s==='pending') return 'queued';
272
- if(s==='running'||s.indexOf('waiting')===0) return 'running';
273
- if(s==='succeeded'||s==='success'||s==='completed'||s==='done') return 'succeeded';
274
- return 'running';
275
- }
276
- var http=Number(entry.status)||0;
277
- if(http>=400) return 'failed';
278
- if(http===202) return 'queued';
279
- if(http>=200&&http<300) return 'succeeded';
280
- return 'failed';
281
- }
282
- function costOf(entry){ var j=entry.linkedJob; return (j&&j.billing&&Number(j.billing.consumed_usd))||0; }
283
- function durationText(entry){
284
- var j=entry.linkedJob;
285
- if(j&&j.started_at&&j.completed_at){ var ms=Date.parse(j.completed_at)-Date.parse(j.started_at); if(ms>=0) return humanMs(ms); }
286
- if(entry.durationMs&&entry.durationMs>0) return humanMs(entry.durationMs);
287
- return '';
288
- }
289
-
290
- var STATUS_META={
291
- succeeded:{label:'Succeeded',tile:'rk-tile-green',pill:'rk-pill-green',glyph:'\\u2713'},
292
- running:{label:'Running',tile:'rk-jobs-tile-run',pill:'rk-pill-gold',glyph:'\\u25CF'},
293
- failed:{label:'Failed',tile:'rk-jobs-tile-fail',pill:'rk-pill-red',glyph:'\\u2715'},
294
- queued:{label:'Queued',tile:'rk-tile-ink',pill:'rk-pill',glyph:'\\u25D4'}
295
- };
296
-
297
- function normalize(entry){
298
- var j=entry.linkedJob||null;
299
- var status=runStatus(entry);
300
- var media=(Array.isArray(entry.outputMediaUrls)&&entry.outputMediaUrls.length)?entry.outputMediaUrls:(Array.isArray(entry.mediaUrls)?entry.mediaUrls:[]);
301
- return {
302
- status:status,
303
- type:typeLabel(entry),
304
- jobId:String(entry.jobId||(j&&j.job_id)||entry.id||''),
305
- operation:operationStr(entry),
306
- tracer:String(entry.tracer||(j&&j.tracer)||''),
307
- when:whenText(entry.createdAt||(j&&j.created_at)),
308
- duration:durationText(entry),
309
- progress:(j&&typeof j.progress==='number')?j.progress:0,
310
- cost:costOf(entry),
311
- method:String(entry.method||''),
312
- path:String(entry.path||''),
313
- httpStatus:Number(entry.status)||0,
314
- workflow:(j&&j.workflow_name)||'',
315
- jobStatus:(j&&j.status)||'',
316
- eventCount:(j&&j.billing&&Number(j.billing.event_count))||0,
317
- media:media
318
- };
319
- }
320
-
321
- function detailRow(k,v){ return '<div class="rk-jobs-detail-row"><span class="rk-jobs-detail-k">'+k+'</span><span class="rk-jobs-detail-v">'+v+'</span></div>'; }
322
-
323
- function rowHtml(n){
324
- var meta=STATUS_META[n.status]||STATUS_META.queued;
325
- var pct=Math.max(0,Math.min(100,Math.round((n.progress||0)*100)));
326
- var when = n.status==='running'
327
- ? '<div class="rk-jobs-progress" role="progressbar" aria-valuenow="'+pct+'" aria-valuemin="0" aria-valuemax="100"><span class="rk-jobs-progress-bar" style="width:'+pct+'%"></span></div><div class="rk-jobs-when-dur is-run">'+pct+'% done</div>'
328
- : n.status==='queued'
329
- ? '<div class="rk-jobs-when-dur is-wait">In queue</div>'
330
- : '<div class="rk-jobs-when-dur">'+esc(n.duration||'\\u2014')+'</div>';
331
- var sub = '<span class="rk-mono">'+esc(n.operation)+'</span>'+(n.tracer?' \\u00b7 tracer <span class="rk-mono">'+esc(n.tracer)+'</span>':'');
332
-
333
- var det = detailRow('HTTP', esc(n.method)+' '+esc(n.path)+' \\u2192 '+esc(n.httpStatus||'\\u2014'))
334
- + detailRow('Job', esc(n.jobId||'\\u2014'))
335
- + detailRow('Operation', esc(n.operation))
336
- + (n.workflow?detailRow('Workflow', esc(n.workflow)):'')
337
- + (n.tracer?detailRow('Tracer', esc(n.tracer)):'')
338
- + detailRow('Job status', esc(n.jobStatus||n.status))
339
- + detailRow('Started', esc(n.when||'\\u2014'))
340
- + (n.duration?detailRow('Duration', esc(n.duration)):'')
341
- + detailRow('Compute', esc(money(n.cost))+(n.eventCount?(' \\u00b7 '+n.eventCount+' event'+(n.eventCount===1?'':'s')):''))
342
- + (n.media.length?detailRow('Output', '<span class="rk-jobs-detail-media">'+n.media.map(function(u){return '<a href="'+esc(u)+'" target="_blank" rel="noreferrer">Open \\u2197</a>';}).join('')+'</span>'):'');
343
-
344
- return '<div class="rk-jobs-item" data-rk-status="'+n.status+'">'
345
- + '<div class="rk-jobs-row">'
346
- + '<span class="rk-tile '+meta.tile+' rk-jobs-tile" aria-hidden="true">'+meta.glyph+'</span>'
347
- + '<div class="rk-jobs-main">'
348
- + '<div class="rk-jobs-row-title"><span class="rk-jobs-type">'+esc(n.type)+'</span><span class="rk-mono rk-jobs-id" title="'+esc(n.jobId)+'">'+esc(shortId(n.jobId))+'</span><span class="rk-pill '+meta.pill+'">'+meta.label+'</span></div>'
349
- + '<div class="rk-jobs-sub">'+sub+'</div>'
350
- + '</div>'
351
- + '<div class="rk-jobs-tail">'
352
- + '<div class="rk-jobs-when"><div class="rk-jobs-when-at">'+esc(n.when||'\\u2014')+'</div>'+when+'</div>'
353
- + '<div class="rk-jobs-cost'+(n.cost?'':' is-zero')+'">'+esc(money(n.cost))+'</div>'
354
- + '<button type="button" class="rk-btn rk-btn-ghost rk-btn-sm rk-jobs-logs" data-rk-logs>View logs</button>'
355
- + '</div>'
356
- + '</div>'
357
- + '<div class="rk-jobs-details" data-rk-details hidden>'+det+'</div>'
358
- + '</div>';
359
- }
360
-
361
- function computeCounts(){
362
- var c={all:state.entries.length,succeeded:0,running:0,failed:0,queued:0};
363
- state.entries.forEach(function(e){ var s=runStatus(e); if(c[s]!=null) c[s]++; });
364
- return c;
365
- }
366
-
367
- function updateSummary(){
368
- var c=computeCounts();
369
- root.querySelectorAll('[data-rk-count]').forEach(function(el){ var k=el.getAttribute('data-rk-count'); el.textContent = (c[k]!=null?c[k]:0); });
370
- if(!summaryEl) return;
371
- if(state.loading&&state.entries.length===0){ summaryEl.innerHTML='Loading run history\\u2026'; return; }
372
- if(state.error&&state.entries.length===0){ summaryEl.innerHTML=esc(state.error); return; }
373
- var compute=0; state.entries.forEach(function(e){ compute+=costOf(e); });
374
- var completed=c.succeeded+c.failed;
375
- var rate=completed?Math.round(c.succeeded/completed*100)+'%':'\\u2014';
376
- summaryEl.innerHTML='<b>'+c.all+'</b> runs&nbsp;\\u00b7&nbsp;<b>'+rate+'</b> success&nbsp;\\u00b7&nbsp;<b>'+c.failed+'</b> failed&nbsp;\\u00b7&nbsp;<b>'+esc(money(compute))+'</b> compute&nbsp;\\u00b7&nbsp;<span class="rk-jobs-summary-note">most recent '+c.all+' \\u00b7 BYO AI keys never billed</span>';
377
- }
378
-
379
- function applyFilter(){
380
- var shown=0;
381
- listEl.querySelectorAll('.rk-jobs-item').forEach(function(w){
382
- var m=state.filter==='all'||w.getAttribute('data-rk-status')===state.filter;
383
- w.hidden=!m; if(m) shown++;
384
- });
385
- if(emptyEl) emptyEl.hidden = shown!==0 || state.entries.length===0;
386
- }
387
-
388
- function wireRows(){
389
- listEl.querySelectorAll('[data-rk-logs]').forEach(function(btn){
390
- btn.addEventListener('click',function(){
391
- var item=btn.closest('.rk-jobs-item'); if(!item) return;
392
- var det=item.querySelector('[data-rk-details]'); if(!det) return;
393
- var willShow=det.hidden; det.hidden=!willShow;
394
- btn.textContent=willShow?'Hide logs':'View logs';
395
- });
396
- });
397
- }
398
-
399
- function setStateMsg(msg,isError){
400
- if(!stateEl) return;
401
- stateEl.textContent=msg;
402
- stateEl.hidden=false;
403
- stateEl.classList.toggle('is-error',!!isError);
404
- if(listEl) listEl.innerHTML='';
405
- if(emptyEl) emptyEl.hidden=true;
406
- }
407
- function hideStateMsg(){ if(stateEl) stateEl.hidden=true; }
408
-
409
- function render(){
410
- updateSummary();
411
- if(footEl) footEl.textContent = state.entries.length? ('Showing '+state.entries.length+' most recent'+(state.nextCursor?' \\u00b7 more available':'')) : '';
412
- if(moreBtn) moreBtn.hidden = !state.nextCursor;
413
-
414
- if(state.loading&&state.entries.length===0){ setStateMsg('Loading run history\\u2026',false); return; }
415
- if(state.error&&state.entries.length===0){ setStateMsg(state.error,true); return; }
416
- if(state.entries.length===0){ setStateMsg('No runs yet \\u2014 fire a render, clip scan, or decompose and it will show up here.',false); return; }
417
-
418
- hideStateMsg();
419
- listEl.innerHTML = state.entries.map(function(e){ return rowHtml(normalize(e)); }).join('');
420
- wireRows();
421
- applyFilter();
422
- }
423
-
424
- function load(cursor){
425
- state.loading=true; state.error=null;
426
- if(!cursor) render();
427
- if(refreshBtn){ refreshBtn.disabled=true; }
428
- var href=loadEndpoint;
429
- try{
430
- var url=new URL(loadEndpoint, window.location.href);
431
- if(accountId) url.searchParams.set('account', accountId);
432
- if(cursor) url.searchParams.set('cursor', cursor);
433
- href=url.toString();
434
- }catch(e){ href=loadEndpoint; }
435
- fetch(href,{credentials:'same-origin',headers:{'accept':'application/json'}})
436
- .then(function(r){
437
- if(!r.ok){ throw new Error(r.status===401?'Sign in to view your run history.':('Couldn\\'t load run history ('+r.status+').')); }
438
- return r.json();
439
- })
440
- .then(function(j){
441
- var entries=(j&&Array.isArray(j.entries))?j.entries:[];
442
- state.entries = cursor? state.entries.concat(entries) : entries;
443
- state.nextCursor = (j&&j.next_cursor)?j.next_cursor:null;
444
- state.loading=false; state.error=null;
445
- if(refreshBtn){ refreshBtn.disabled=false; }
446
- render();
447
- })
448
- .catch(function(err){
449
- state.loading=false;
450
- var msg=(err&&err.message)?String(err.message):'';
451
- // Raw network TypeErrors ("Failed to fetch") aren't user-friendly.
452
- state.error=(!msg||/failed to fetch|networkerror|load failed/i.test(msg))
453
- ? "Couldn't reach the server \\u2014 check your connection, or sign in to view your run history."
454
- : msg;
455
- if(refreshBtn){ refreshBtn.disabled=false; }
456
- render();
457
- });
458
- }
459
-
460
- // filter chips (work over the real, client-rendered rows)
461
- root.querySelectorAll('[data-rk-filter]').forEach(function(btn){
462
- btn.addEventListener('click',function(){
463
- state.filter=btn.getAttribute('data-rk-filter');
464
- root.querySelectorAll('[data-rk-filter]').forEach(function(b){ b.classList.toggle('is-active',b===btn); });
465
- applyFilter();
466
- });
467
- });
468
- if(refreshBtn) refreshBtn.addEventListener('click',function(){ load(); });
469
- if(moreBtn) moreBtn.addEventListener('click',function(){ if(state.nextCursor) load(state.nextCursor); });
470
-
471
- // boot: render a server seed immediately if present (mirrors the live page),
472
- // otherwise fetch the real endpoint. Refresh always re-fetches.
473
- state.entries = Array.isArray(boot.entries)? boot.entries : [];
474
- if(state.entries.length){ render(); }
475
- else { state.loading=true; render(); load(); }
476
- })();`;
477
- //# sourceMappingURL=job-runs-page.js.map