@gobing-ai/knowledge-kit 0.0.35 → 0.0.37

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 (124) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +1 -1
  3. package/dist/board/collect/index.css +42 -0
  4. package/dist/board/collect/index.js +787 -0
  5. package/dist/board/daily-voice/index.css +13 -0
  6. package/dist/board/daily-voice/index.js +902 -0
  7. package/dist/board/itc/index.css +14 -0
  8. package/dist/board/itc/index.js +1026 -0
  9. package/dist/index.js +12996 -10476
  10. package/package.json +10 -9
  11. package/plugins/generations/content-gen/dist/index.js +1015 -10814
  12. package/plugins/generations/content-gen/package.json +1 -1
  13. package/plugins/generations/core-facts-gen/dist/index.js +1002 -10801
  14. package/plugins/generations/core-facts-gen/package.json +1 -1
  15. package/plugins/generations/daily-article-gen/dist/index.js +1004 -10803
  16. package/plugins/generations/daily-article-gen/package.json +1 -1
  17. package/plugins/generations/dailynews-gen/dist/index.js +1111 -10888
  18. package/plugins/generations/dailynews-gen/package.json +1 -1
  19. package/plugins/generations/dailynews-gen/src/script-plan.ts +32 -0
  20. package/plugins/generations/episode-plan-gen/dist/index.js +1124 -10923
  21. package/plugins/generations/episode-plan-gen/package.json +1 -1
  22. package/plugins/generations/gemini-tts/dist/index.js +1104 -10903
  23. package/plugins/generations/gemini-tts/package.json +1 -1
  24. package/plugins/generations/image-gen/dist/index.js +1239 -11035
  25. package/plugins/generations/image-gen/package.json +1 -1
  26. package/plugins/generations/news-report-gen/dist/index.js +1048 -10847
  27. package/plugins/generations/news-report-gen/package.json +1 -1
  28. package/plugins/generations/voice-gen/dist/index.js +1062 -10861
  29. package/plugins/generations/voice-gen/package.json +1 -1
  30. package/plugins/generations/voxcpm-tts/README.md +72 -0
  31. package/plugins/generations/voxcpm-tts/dist/index.js +14006 -0
  32. package/plugins/generations/voxcpm-tts/package.json +16 -0
  33. package/plugins/generations/voxcpm-tts/plugin.json +6 -0
  34. package/plugins/generations/voxcpm-tts/profiles.json +10 -0
  35. package/plugins/generations/voxcpm-tts/pyproject.toml +9 -0
  36. package/plugins/generations/voxcpm-tts/python/worker.py +353 -0
  37. package/plugins/generations/voxcpm-tts/src/index.ts +42 -0
  38. package/plugins/generations/voxcpm-tts/src/voxcpm-client.ts +765 -0
  39. package/plugins/generations/voxcpm-tts/tsconfig.json +8 -0
  40. package/plugins/generations/voxcpm-tts/uv.lock +2571 -0
  41. package/plugins/ingestions/aihot-ingest/dist/index.js +1081 -10628
  42. package/plugins/ingestions/aihot-ingest/package.json +1 -1
  43. package/plugins/ingestions/horizon-ingest/dist/index.js +1013 -10812
  44. package/plugins/ingestions/horizon-ingest/package.json +1 -1
  45. package/plugins/ingestions/karakeep-local/dist/index.js +689 -10774
  46. package/plugins/ingestions/karakeep-local/package.json +1 -1
  47. package/plugins/ingestions/last30days-ingest/dist/index.js +1011 -10810
  48. package/plugins/ingestions/last30days-ingest/package.json +1 -1
  49. package/plugins/ingestions/web-search/dist/index.js +1250 -11033
  50. package/plugins/ingestions/web-search/package.json +1 -1
  51. package/plugins/kk/README.md +29 -2
  52. package/plugins/kk/plugin.json +1 -1
  53. package/plugins/kk/schedules/cron.tmpl +9 -1
  54. package/plugins/kk/schedules/kk-serve.launchd.plist.tmpl +79 -0
  55. package/plugins/kk/schedules/launchd.plist.tmpl +11 -1
  56. package/plugins/kk/scripts/daily-stages.ts +428 -46
  57. package/plugins/kk/scripts/daily-voice-style.zh.md +1 -1
  58. package/plugins/kk/scripts/kk-workflow-stages.ts +76 -146
  59. package/plugins/kk/skills/publish/SKILL.md +8 -4
  60. package/plugins/kk/workflows/feature-verification.yaml +93 -0
  61. package/plugins/kk/workflows/judge-gated-publish-example.yaml +1 -0
  62. package/plugins/kk/workflows/kk-collect.yaml +43 -11
  63. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +4 -2
  64. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +87 -16
  65. package/plugins/kk/workflows/kk-daily-safety.yaml +15 -2
  66. package/plugins/kk/workflows/kk-itc.yaml +8 -1
  67. package/plugins/kk/workflows/kk-solo-podcast.yaml +2 -0
  68. package/plugins/publishings/emdash-pub/dist/index.js +987 -10814
  69. package/plugins/publishings/emdash-pub/package.json +1 -1
  70. package/plugins/publishings/infoq-pub/dist/index.js +1928 -11444
  71. package/plugins/publishings/infoq-pub/dist/profile-check.js +1677 -11199
  72. package/plugins/publishings/infoq-pub/package.json +1 -1
  73. package/plugins/publishings/infoq-pub/plugin.json +5 -1
  74. package/plugins/publishings/juejin-pub/dist/index.js +1940 -11456
  75. package/plugins/publishings/juejin-pub/dist/profile-check.js +1677 -11199
  76. package/plugins/publishings/juejin-pub/package.json +1 -1
  77. package/plugins/publishings/juejin-pub/plugin.json +5 -1
  78. package/plugins/publishings/medium-pub/dist/index.js +978 -10805
  79. package/plugins/publishings/medium-pub/package.json +1 -1
  80. package/plugins/publishings/podcast-pub/dist/index.js +1016 -10843
  81. package/plugins/publishings/podcast-pub/package.json +1 -1
  82. package/plugins/publishings/qiita-pub/dist/index.js +976 -10803
  83. package/plugins/publishings/qiita-pub/package.json +1 -1
  84. package/plugins/publishings/substack-pub/dist/index.js +1932 -11448
  85. package/plugins/publishings/substack-pub/dist/profile-check.js +1698 -11200
  86. package/plugins/publishings/substack-pub/package.json +1 -1
  87. package/plugins/publishings/substack-pub/plugin.json +4 -1
  88. package/plugins/publishings/substack-pub/src/profile-check.ts +36 -3
  89. package/plugins/publishings/surfdash-pub/dist/index.js +1151 -10834
  90. package/plugins/publishings/surfdash-pub/package.json +1 -1
  91. package/plugins/publishings/surfdash-pub/src/index.ts +137 -15
  92. package/plugins/publishings/surfdash-pub/src/patch.ts +144 -0
  93. package/plugins/publishings/threads-pub/dist/index.js +12394 -0
  94. package/plugins/publishings/threads-pub/package.json +17 -0
  95. package/plugins/publishings/threads-pub/plugin.json +7 -0
  96. package/plugins/publishings/threads-pub/src/index.ts +340 -0
  97. package/plugins/publishings/threads-pub/tsconfig.json +4 -0
  98. package/plugins/publishings/wechatmp-pub/dist/index.js +2508 -11695
  99. package/plugins/publishings/wechatmp-pub/dist/profile-check.js +1656 -11188
  100. package/plugins/publishings/wechatmp-pub/package.json +1 -1
  101. package/plugins/publishings/wechatmp-pub/plugin.json +5 -1
  102. package/plugins/publishings/wechatmp-pub/src/enrich.ts +244 -71
  103. package/plugins/publishings/wechatmp-pub/src/flow.ts +412 -96
  104. package/plugins/publishings/wechatmp-pub/src/index.ts +24 -3
  105. package/plugins/publishings/wechatmp-pub/src/page.ts +16 -0
  106. package/plugins/publishings/wechatmp-pub/src/profile-check.ts +40 -4
  107. package/plugins/publishings/weibo-pub/dist/index.js +21345 -0
  108. package/plugins/publishings/weibo-pub/dist/profile-check.js +20817 -0
  109. package/plugins/publishings/weibo-pub/package.json +19 -0
  110. package/plugins/publishings/weibo-pub/plugin.json +12 -0
  111. package/plugins/publishings/weibo-pub/src/index.ts +868 -0
  112. package/plugins/publishings/weibo-pub/src/profile-check.ts +20 -0
  113. package/plugins/publishings/weibo-pub/tsconfig.json +4 -0
  114. package/plugins/publishings/x-pub/dist/index.js +1948 -11440
  115. package/plugins/publishings/x-pub/dist/profile-check.js +1677 -11199
  116. package/plugins/publishings/x-pub/package.json +1 -1
  117. package/plugins/publishings/x-pub/plugin.json +5 -1
  118. package/plugins/publishings/xhs-pub/dist/index.js +1993 -11509
  119. package/plugins/publishings/xhs-pub/dist/profile-check.js +1697 -11212
  120. package/plugins/publishings/xhs-pub/package.json +1 -1
  121. package/plugins/publishings/xhs-pub/plugin.json +5 -1
  122. package/plugins/publishings/xhs-pub/src/profile-check.ts +72 -2
  123. package/plugins/publishings/zenn-pub/dist/index.js +988 -10815
  124. package/plugins/publishings/zenn-pub/package.json +1 -1
@@ -0,0 +1,902 @@
1
+ // ../board/src/daily-voice/index.tsx
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+
4
+ // ../board/src/shared/api.ts
5
+ var DEFAULT_READER_ORIGIN = "http://127.0.0.1:4340";
6
+ function readerOriginFrom(search) {
7
+ const override = new URLSearchParams(search).get("kkApi");
8
+ if (override === null)
9
+ return { origin: DEFAULT_READER_ORIGIN, diagnostic: null };
10
+ if (isLoopbackHttpOrigin(override))
11
+ return { origin: override, diagnostic: null };
12
+ return {
13
+ origin: DEFAULT_READER_ORIGIN,
14
+ diagnostic: {
15
+ code: "board.reader.origin-invalid",
16
+ message: "Ignored a non-loopback kkApi origin; using the default reader."
17
+ }
18
+ };
19
+ }
20
+ function isLoopbackHttpOrigin(origin) {
21
+ let url;
22
+ try {
23
+ url = new URL(origin);
24
+ } catch {
25
+ return false;
26
+ }
27
+ if (url.protocol !== "http:")
28
+ return false;
29
+ if (url.username !== "" || url.password !== "")
30
+ return false;
31
+ if (url.pathname !== "/" || url.search !== "" || url.hash !== "")
32
+ return false;
33
+ return url.hostname === "127.0.0.1" || url.hostname === "localhost" || url.hostname === "[::1]";
34
+ }
35
+ function origin(base) {
36
+ return base.replace(/\/+$/, "");
37
+ }
38
+ function createBoardClient(options) {
39
+ if (!isLoopbackHttpOrigin(options.readerOrigin)) {
40
+ throw new Error(`reader origin must be loopback http, got '${options.readerOrigin}'`);
41
+ }
42
+ if (!isLoopbackHttpOrigin(options.boardOrigin)) {
43
+ throw new Error(`board origin must be loopback http, got '${options.boardOrigin}'`);
44
+ }
45
+ const reader = origin(options.readerOrigin);
46
+ const board = origin(options.boardOrigin);
47
+ const doFetch = options.fetchImpl ?? fetch;
48
+ async function getJson(url) {
49
+ const response = await doFetch(url, { headers: { accept: "application/json" } });
50
+ if (!response.ok) {
51
+ throw new Error(`request failed (${response.status}): ${url}`);
52
+ }
53
+ return await response.json();
54
+ }
55
+ return {
56
+ health: () => getJson(`${reader}/api/health`),
57
+ results: (workflow, runId) => getJson(`${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/results`),
58
+ config: (workflow, runId) => getJson(`${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/config`),
59
+ artifactUrl: (workflow, runId, artifactId) => `${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}`,
60
+ runs: (workflow, cursor) => {
61
+ const params = new URLSearchParams({ workflow, limit: "25" });
62
+ if (cursor !== undefined)
63
+ params.set("cursor", cursor);
64
+ return getJson(`${board}/api/runs?${params.toString()}`);
65
+ },
66
+ runDetail: (runId) => getJson(`${board}/api/runs/${encodeURIComponent(runId)}`),
67
+ progress: (runId) => getJson(`${board}/api/runs/${encodeURIComponent(runId)}/progress`)
68
+ };
69
+ }
70
+
71
+ // ../board/src/shared/format.ts
72
+ function availabilityLabel(availability) {
73
+ switch (availability) {
74
+ case "available":
75
+ return "Available";
76
+ case "pending":
77
+ return "Not yet written";
78
+ case "missing":
79
+ return "Missing";
80
+ case "invalid":
81
+ return "Malformed";
82
+ case "oversized":
83
+ return "Too large to preview";
84
+ case "superseded":
85
+ return "Superseded by a later run";
86
+ case "unverified":
87
+ return "Unverified";
88
+ }
89
+ }
90
+ function diagnosticLine(diagnostic) {
91
+ return `${diagnostic.code}: ${diagnostic.message}`;
92
+ }
93
+ function formatElapsed(startedAt, now) {
94
+ if (startedAt === null || startedAt === undefined)
95
+ return "elapsed unknown";
96
+ const start = Date.parse(startedAt);
97
+ if (Number.isNaN(start))
98
+ return "elapsed unknown";
99
+ const seconds = Math.max(0, Math.round((now - start) / 1000));
100
+ if (seconds < 60)
101
+ return `${seconds}s`;
102
+ const minutes = Math.floor(seconds / 60);
103
+ if (minutes < 60)
104
+ return `${minutes}m ${seconds % 60}s`;
105
+ return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
106
+ }
107
+ function dedupeDiagnostics(diagnostics) {
108
+ const seen = new Set;
109
+ return diagnostics.filter((diagnostic) => {
110
+ if (seen.has(diagnostic.code))
111
+ return false;
112
+ seen.add(diagnostic.code);
113
+ return true;
114
+ });
115
+ }
116
+ function formatTimestamp(iso) {
117
+ if (iso === null || iso === undefined)
118
+ return "time unknown";
119
+ const epoch = Date.parse(iso);
120
+ if (Number.isNaN(epoch))
121
+ return "time unknown";
122
+ return `${new Date(epoch).toLocaleString()} (${new Date(epoch).toISOString()})`;
123
+ }
124
+
125
+ // ../board/src/shared/collect.ts
126
+ function artifactViews(results, readerOrigin) {
127
+ return results.artifacts.map((artifact) => ({
128
+ id: artifact.id,
129
+ label: artifact.label,
130
+ kind: artifact.kind,
131
+ availability: artifact.availability,
132
+ state: availabilityLabel(artifact.availability),
133
+ href: artifact.availability === "available" ? `${readerOrigin}/api/workflows/${results.workflow}/runs/${results.runId}/artifacts/${artifact.id}` : null
134
+ }));
135
+ }
136
+
137
+ // ../board/src/shared/refresh.ts
138
+ var ACTIVE_POLL_MS = 5000;
139
+ var HISTORY_POLL_MS = 30000;
140
+ var MAX_BACKOFF_MS = 30000;
141
+ function initialRefresh(intervalMs) {
142
+ return { pending: false, failures: 0, backoffMs: intervalMs, lastSuccessAt: null, failingSince: null };
143
+ }
144
+ function tick(state) {
145
+ return state.pending ? state : { ...state, pending: true };
146
+ }
147
+ function succeeded(now, intervalMs) {
148
+ return { pending: false, failures: 0, backoffMs: intervalMs, lastSuccessAt: now, failingSince: null };
149
+ }
150
+ function failed(state, now) {
151
+ const failures = state.failures + 1;
152
+ return {
153
+ pending: false,
154
+ failures,
155
+ backoffMs: Math.min(state.backoffMs * 2, MAX_BACKOFF_MS),
156
+ lastSuccessAt: state.lastSuccessAt,
157
+ failingSince: state.failingSince ?? now
158
+ };
159
+ }
160
+ function delayMs(state, intervalMs) {
161
+ return state.failures > 0 ? state.backoffMs : intervalMs;
162
+ }
163
+ function isStale(state) {
164
+ return state.failures > 0;
165
+ }
166
+ function freshnessLabel(state) {
167
+ if (state.lastSuccessAt === null)
168
+ return "Not yet loaded";
169
+ const updated = new Date(state.lastSuccessAt).toISOString();
170
+ return isStale(state) ? `Stale — last success ${updated}` : `Updated ${updated}`;
171
+ }
172
+
173
+ // ../board/src/shared/run-selection.ts
174
+ var BOARD_TABS = ["summary", "results", "progress", "config"];
175
+ function isBoardTab(value) {
176
+ return value !== null && value !== undefined && BOARD_TABS.includes(value);
177
+ }
178
+ function parseDeepLink(search) {
179
+ const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
180
+ const diagnostics = [];
181
+ const rawTab = params.get("tab");
182
+ const rawRun = params.get("run");
183
+ let tab;
184
+ if (rawTab !== null) {
185
+ if (isBoardTab(rawTab)) {
186
+ tab = rawTab;
187
+ } else {
188
+ diagnostics.push({
189
+ code: "board.deeplink.unknown-tab",
190
+ message: `Unknown tab '${rawTab}'; showing Summary.`
191
+ });
192
+ }
193
+ }
194
+ let runId;
195
+ if (rawRun !== null) {
196
+ if (rawRun === "") {
197
+ diagnostics.push({ code: "board.deeplink.empty-run", message: "Empty run id ignored." });
198
+ } else {
199
+ runId = rawRun;
200
+ }
201
+ }
202
+ return { ...runId === undefined ? {} : { runId }, ...tab === undefined ? {} : { tab }, diagnostics };
203
+ }
204
+ function resolveSelection(rows, link) {
205
+ const tab = link.tab ?? "summary";
206
+ const diagnostics = [...link.diagnostics];
207
+ if (link.runId !== undefined) {
208
+ if (rows.some((row) => row.id === link.runId)) {
209
+ return { runId: link.runId, tab, diagnostics };
210
+ }
211
+ diagnostics.push({
212
+ code: "board.selection.unknown-run",
213
+ message: `Run '${link.runId}' is not in the loaded history; select a run.`
214
+ });
215
+ return { runId: null, tab, diagnostics };
216
+ }
217
+ return { runId: rows[0]?.id ?? null, tab, diagnostics };
218
+ }
219
+ function selectionQuery(selection, search = "") {
220
+ const params = new URLSearchParams;
221
+ if (selection.runId !== null)
222
+ params.set("run", selection.runId);
223
+ params.set("tab", selection.tab);
224
+ for (const [key, value] of new URLSearchParams(search)) {
225
+ if (key === "run" || key === "tab")
226
+ continue;
227
+ params.set(key, value);
228
+ }
229
+ return `?${params.toString()}`;
230
+ }
231
+ var COLLECT_MODULE_PATH = "/board/modules/kk-collect";
232
+ function selectionPath(selection, search = "", modulePath = COLLECT_MODULE_PATH) {
233
+ return `${modulePath}${selectionQuery(selection, search)}`;
234
+ }
235
+ function syncSelectionUrl(selection, target, modulePath = COLLECT_MODULE_PATH) {
236
+ if (target.location.pathname !== modulePath)
237
+ return;
238
+ const url = selectionPath(selection, target.location.search, modulePath);
239
+ if (`${target.location.pathname}${target.location.search}` === url)
240
+ return;
241
+ target.history.replaceState(target.history.state, "", url);
242
+ }
243
+ function mergeRunPages(existing, page) {
244
+ const seen = new Set(existing.map((row) => row.id));
245
+ const merged = [...existing, ...page.runs.filter((row) => !seen.has(row.id))];
246
+ return { runs: merged, count: merged.length, nextCursor: page.nextCursor, hasMore: page.hasMore };
247
+ }
248
+
249
+ // ../board/src/daily-voice/view.ts
250
+ var CHANNEL_OUTCOME_LABELS = {
251
+ live: "Live",
252
+ draft: "Draft",
253
+ skipped: "Skipped",
254
+ error: "Failed",
255
+ pending: "Not yet recorded",
256
+ unavailable: "Unavailable"
257
+ };
258
+ function asRecord(value) {
259
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
260
+ }
261
+ function asString(value) {
262
+ return typeof value === "string" && value !== "" ? value : null;
263
+ }
264
+ function asNumber(value) {
265
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
266
+ }
267
+ function asBool(value) {
268
+ return typeof value === "boolean" ? value : null;
269
+ }
270
+ function isChannelOutcome(value) {
271
+ return value === "live" || value === "draft" || value === "skipped" || value === "error" || value === "pending" || value === "unavailable";
272
+ }
273
+ function isConfidenceLevel(value) {
274
+ return value === "HIGH" || value === "MEDIUM" || value === "LOW";
275
+ }
276
+ function channelView(value) {
277
+ const record = asRecord(value);
278
+ if (record === null || typeof record.channel !== "string" || !isChannelOutcome(record.outcome))
279
+ return null;
280
+ return {
281
+ channel: record.channel,
282
+ label: asString(record.label) ?? record.channel,
283
+ outcome: record.outcome,
284
+ state: CHANNEL_OUTCOME_LABELS[record.outcome],
285
+ url: asString(record.url),
286
+ detail: asString(record.detail)
287
+ };
288
+ }
289
+ function nodeView(value) {
290
+ const record = asRecord(value);
291
+ if (record === null || typeof record.id !== "string")
292
+ return null;
293
+ return {
294
+ id: record.id,
295
+ status: asString(record.status) ?? "unknown",
296
+ attempts: asNumber(record.attempts) ?? 0,
297
+ timing: asString(record.timing) ?? "timing unknown"
298
+ };
299
+ }
300
+ function progressView(value) {
301
+ const record = asRecord(value);
302
+ if (record === null)
303
+ return null;
304
+ const edges = Array.isArray(record.edges) ? record.edges.map((edge) => asRecord(edge)).filter((edge) => edge !== null).map((edge) => ({ from: String(edge.from ?? ""), to: String(edge.to ?? "") })) : null;
305
+ return {
306
+ nodes: Array.isArray(record.nodes) ? record.nodes.map(nodeView).filter((node) => node !== null) : [],
307
+ edges,
308
+ edgesKnown: record.edgesKnown === true,
309
+ childRunId: asString(record.childRunId)
310
+ };
311
+ }
312
+ function dailySummary(results) {
313
+ const raw = results.summary ?? {};
314
+ const counts = asRecord(raw.counts);
315
+ const quality = asRecord(raw.quality);
316
+ const safety = asRecord(raw.safety);
317
+ return {
318
+ status: asString(raw.status),
319
+ startedAt: asString(raw.startedAt),
320
+ completedAt: asString(raw.completedAt),
321
+ outcome: asString(raw.outcome),
322
+ articleTitle: asString(raw.articleTitle),
323
+ channels: Array.isArray(raw.channels) ? raw.channels.map(channelView).filter((channel) => channel !== null) : [],
324
+ quality: quality === null ? null : {
325
+ overallScore: asNumber(quality.overallScore),
326
+ passed: asBool(quality.passed),
327
+ criticalIssues: Array.isArray(quality.criticalIssues) ? quality.criticalIssues.filter((issue) => typeof issue === "string") : []
328
+ },
329
+ safety: safety === null ? null : {
330
+ verdict: asString(safety.verdict),
331
+ confidence: isConfidenceLevel(safety.confidence) ? safety.confidence : null
332
+ },
333
+ progress: progressView(raw.progress),
334
+ counts: {
335
+ live: asNumber(counts?.live) ?? 0,
336
+ draft: asNumber(counts?.draft) ?? 0,
337
+ failed: asNumber(counts?.failed) ?? 0,
338
+ skipped: asNumber(counts?.skipped) ?? 0
339
+ },
340
+ countsRecorded: counts !== null
341
+ };
342
+ }
343
+ function count(value) {
344
+ return value === null ? "unavailable" : String(value);
345
+ }
346
+ function dailySummaryFacts(results, now) {
347
+ const summary = dailySummary(results);
348
+ const available = results.artifacts.filter((artifact) => artifact.availability === "available").length;
349
+ const facts = [
350
+ {
351
+ label: "Execution status",
352
+ value: summary.status ?? "unavailable",
353
+ availability: summary.status === null ? "unverified" : "available"
354
+ },
355
+ {
356
+ label: "Result outcome",
357
+ value: summary.outcome ?? "unavailable",
358
+ availability: summary.outcome === null ? "unverified" : "available"
359
+ },
360
+ {
361
+ label: "Result availability",
362
+ value: `${available}/${results.artifacts.length} artifacts available`,
363
+ availability: results.availability
364
+ },
365
+ {
366
+ label: "Started",
367
+ value: formatTimestamp(summary.startedAt),
368
+ availability: summary.startedAt === null ? "unverified" : "available"
369
+ },
370
+ {
371
+ label: "Elapsed",
372
+ value: formatElapsed(summary.startedAt, now),
373
+ availability: summary.startedAt === null ? "unverified" : "available"
374
+ },
375
+ {
376
+ label: "Channels live / draft",
377
+ value: summary.countsRecorded ? `${summary.counts.live} live, ${summary.counts.draft} draft` : "not recorded",
378
+ availability: summary.countsRecorded ? "available" : "unverified"
379
+ },
380
+ {
381
+ label: "Channels failed / skipped",
382
+ value: summary.countsRecorded ? `${summary.counts.failed} failed, ${summary.counts.skipped} skipped` : "not recorded",
383
+ availability: !summary.countsRecorded ? "unverified" : summary.counts.failed > 0 ? "missing" : "available"
384
+ },
385
+ {
386
+ label: "Article",
387
+ value: summary.articleTitle ?? "unavailable",
388
+ availability: summary.articleTitle === null ? "unverified" : "available"
389
+ },
390
+ {
391
+ label: "Audio QC score",
392
+ value: count(summary.quality?.overallScore ?? null),
393
+ availability: summary.quality === null ? "unverified" : "available"
394
+ },
395
+ {
396
+ label: "Content safety verdict",
397
+ value: summary.safety?.verdict ?? "not recorded",
398
+ availability: summary.safety === null ? "unverified" : "available"
399
+ },
400
+ {
401
+ label: "Safety confidence",
402
+ value: summary.safety?.confidence ?? "not recorded",
403
+ availability: summary.safety?.confidence == null ? "unverified" : "available"
404
+ }
405
+ ];
406
+ return facts;
407
+ }
408
+
409
+ // ../board/src/daily-voice/index.tsx
410
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
411
+ var WORKFLOW = "kk-daily-ai-voice2";
412
+ var MODULE_PATH = "/board/modules/kk-daily-ai-voice2";
413
+ var TAB_LABELS = {
414
+ summary: "Summary",
415
+ results: "Results",
416
+ progress: "Execution progress",
417
+ config: "Workflow Config Summary"
418
+ };
419
+ function messageOf(error) {
420
+ return error instanceof Error ? error.message : String(error);
421
+ }
422
+ function usePolling(loader, intervalMs, refresh) {
423
+ const loaderRef = useRef(loader);
424
+ loaderRef.current = loader;
425
+ const refreshRef = useRef(refresh);
426
+ refreshRef.current = refresh;
427
+ useEffect(() => {
428
+ let cancelled = false;
429
+ let timer;
430
+ const loop = async () => {
431
+ if (!document.hidden)
432
+ await loaderRef.current();
433
+ if (!cancelled)
434
+ timer = setTimeout(() => void loop(), delayMs(refreshRef.current, intervalMs));
435
+ };
436
+ loop();
437
+ return () => {
438
+ cancelled = true;
439
+ clearTimeout(timer);
440
+ };
441
+ }, [intervalMs]);
442
+ }
443
+ function DailyVoiceModule() {
444
+ const [link] = useState(() => parseDeepLink(window.location.search));
445
+ const [reader] = useState(() => readerOriginFrom(window.location.search));
446
+ const readerOrigin = reader.origin;
447
+ const client = useMemo(() => createBoardClient({ readerOrigin, boardOrigin: window.location.origin }), [readerOrigin]);
448
+ const [rows, setRows] = useState([]);
449
+ const [cursor, setCursor] = useState(null);
450
+ const [selection, setSelection] = useState({ runId: link.runId ?? null, tab: link.tab ?? "summary" });
451
+ const [diagnostics, setDiagnostics] = useState(() => [
452
+ ...link.diagnostics,
453
+ ...reader.diagnostic === null ? [] : [reader.diagnostic]
454
+ ]);
455
+ const [historyRefresh, setHistoryRefresh] = useState(() => initialRefresh(HISTORY_POLL_MS));
456
+ const [readerRefresh, setReaderRefresh] = useState(() => initialRefresh(ACTIVE_POLL_MS));
457
+ const [results, setResults] = useState(null);
458
+ const [config, setConfig] = useState(null);
459
+ const historyBusy = useRef(false);
460
+ const readerBusy = useRef(false);
461
+ const selectionRef = useRef(selection);
462
+ selectionRef.current = selection;
463
+ const loadHistory = useCallback(async () => {
464
+ if (historyBusy.current)
465
+ return;
466
+ historyBusy.current = true;
467
+ setHistoryRefresh((state) => tick(state));
468
+ try {
469
+ const page = await client.runs(WORKFLOW);
470
+ setRows((existing) => mergeRunPages(existing, page).runs);
471
+ setCursor(page.nextCursor);
472
+ setHistoryRefresh(() => succeeded(Date.now(), HISTORY_POLL_MS));
473
+ } catch (error) {
474
+ setDiagnostics((existing) => [
475
+ ...existing,
476
+ { code: "board.history.unavailable", message: messageOf(error) }
477
+ ]);
478
+ setHistoryRefresh((state) => failed(state, Date.now()));
479
+ } finally {
480
+ historyBusy.current = false;
481
+ }
482
+ }, [client]);
483
+ const loadReader = useCallback(async () => {
484
+ if (readerBusy.current)
485
+ return;
486
+ const runId = selectionRef.current.runId;
487
+ if (runId === null)
488
+ return;
489
+ readerBusy.current = true;
490
+ setReaderRefresh((state) => tick(state));
491
+ try {
492
+ const [nextResults, nextConfig] = await Promise.all([
493
+ client.results(WORKFLOW, runId),
494
+ client.config(WORKFLOW, runId)
495
+ ]);
496
+ setResults(nextResults);
497
+ setConfig(nextConfig);
498
+ setReaderRefresh(() => succeeded(Date.now(), ACTIVE_POLL_MS));
499
+ } catch (error) {
500
+ setDiagnostics((existing) => [
501
+ ...existing,
502
+ { code: "board.reader.unavailable", message: messageOf(error) }
503
+ ]);
504
+ setReaderRefresh((state) => failed(state, Date.now()));
505
+ } finally {
506
+ readerBusy.current = false;
507
+ }
508
+ }, [client]);
509
+ usePolling(loadHistory, HISTORY_POLL_MS, historyRefresh);
510
+ usePolling(loadReader, ACTIVE_POLL_MS, readerRefresh);
511
+ useEffect(() => {
512
+ if (selection.runId === null && rows.length > 0) {
513
+ setSelection((state) => state.runId === null ? resolveSelection(rows, link) : state);
514
+ }
515
+ }, [rows, selection.runId, link]);
516
+ useEffect(() => {
517
+ syncSelectionUrl(selection, { location: window.location, history: window.history }, MODULE_PATH);
518
+ }, [selection]);
519
+ const tab = selection.tab;
520
+ const now = Date.now();
521
+ const summary = results === null ? null : dailySummary(results);
522
+ const facts = results === null ? [] : dailySummaryFacts(results, now);
523
+ const artifacts = results === null ? [] : artifactViews(results, readerOrigin);
524
+ const selectedRow = rows.find((row) => row.id === selection.runId);
525
+ return /* @__PURE__ */ jsxs("div", {
526
+ className: "kk-board kk-board-daily-voice",
527
+ children: [
528
+ /* @__PURE__ */ jsxs("header", {
529
+ className: "kk-board-header",
530
+ children: [
531
+ /* @__PURE__ */ jsx("h1", {
532
+ children: "Daily AI Voice"
533
+ }),
534
+ /* @__PURE__ */ jsxs("p", {
535
+ children: [
536
+ "Run ",
537
+ /* @__PURE__ */ jsx("code", {
538
+ children: selection.runId ?? "none selected"
539
+ }),
540
+ " · ",
541
+ selectedRow?.status ?? "status unknown",
542
+ " ·",
543
+ " ",
544
+ freshnessLabel(readerRefresh)
545
+ ]
546
+ }),
547
+ summary === null ? null : /* @__PURE__ */ jsxs("p", {
548
+ children: [
549
+ "Outcome ",
550
+ summary.outcome ?? "unknown",
551
+ " · ",
552
+ results?.availability ?? "unverified"
553
+ ]
554
+ }),
555
+ /* @__PURE__ */ jsx("button", {
556
+ type: "button",
557
+ onClick: () => void loadReader(),
558
+ children: "Refresh"
559
+ }),
560
+ selection.runId === null ? null : /* @__PURE__ */ jsx("a", {
561
+ href: selectionPath(selection, window.location.search, MODULE_PATH),
562
+ children: "Permanent link to this view"
563
+ })
564
+ ]
565
+ }),
566
+ /* @__PURE__ */ jsx("nav", {
567
+ className: "kk-board-tabs",
568
+ "aria-label": "Daily AI Voice tabs",
569
+ children: BOARD_TABS.map((candidate) => /* @__PURE__ */ jsx("button", {
570
+ type: "button",
571
+ "aria-current": candidate === tab ? "page" : undefined,
572
+ onClick: () => setSelection((state) => ({ ...state, tab: candidate })),
573
+ children: TAB_LABELS[candidate]
574
+ }, candidate))
575
+ }),
576
+ /* @__PURE__ */ jsxs("label", {
577
+ className: "kk-board-run-selector",
578
+ children: [
579
+ "Run",
580
+ /* @__PURE__ */ jsxs("select", {
581
+ value: selection.runId ?? "",
582
+ onChange: (event) => setSelection((state) => ({ ...state, runId: event.target.value || null })),
583
+ children: [
584
+ /* @__PURE__ */ jsx("option", {
585
+ value: "",
586
+ children: rows.length === 0 ? "No runs recorded" : "Select a run"
587
+ }),
588
+ rows.map((row) => /* @__PURE__ */ jsxs("option", {
589
+ value: row.id,
590
+ children: [
591
+ row.id,
592
+ " — ",
593
+ row.status
594
+ ]
595
+ }, row.id))
596
+ ]
597
+ })
598
+ ]
599
+ }),
600
+ rows.length === 0 ? /* @__PURE__ */ jsxs("p", {
601
+ className: "kk-board-empty",
602
+ children: [
603
+ "No runs recorded for kk-daily-ai-voice2. Configure the workflow in",
604
+ " ",
605
+ /* @__PURE__ */ jsx("a", {
606
+ href: "/board/settings/workflows",
607
+ children: "Settings → Workflows"
608
+ }),
609
+ "."
610
+ ]
611
+ }) : null,
612
+ tab === "summary" ? /* @__PURE__ */ jsx(SummaryPanel, {
613
+ facts,
614
+ results
615
+ }) : null,
616
+ tab === "results" ? /* @__PURE__ */ jsx(ResultsPanel, {
617
+ artifacts,
618
+ channels: summary?.channels ?? []
619
+ }) : null,
620
+ tab === "progress" ? /* @__PURE__ */ jsx(ProgressPanel, {
621
+ progress: summary?.progress ?? null
622
+ }) : null,
623
+ tab === "config" ? /* @__PURE__ */ jsx(ConfigPanel, {
624
+ config
625
+ }) : null,
626
+ dedupeDiagnostics([...diagnostics, ...results?.diagnostics ?? []]).map((diagnostic) => /* @__PURE__ */ jsx("p", {
627
+ role: "status",
628
+ className: "kk-board-diagnostic",
629
+ children: diagnosticLine(diagnostic)
630
+ }, diagnostic.code)),
631
+ cursor === null ? null : /* @__PURE__ */ jsx("button", {
632
+ type: "button",
633
+ onClick: () => void loadHistory(),
634
+ children: "Load more runs"
635
+ }),
636
+ /* @__PURE__ */ jsxs("p", {
637
+ className: "kk-board-footnote",
638
+ children: [
639
+ "Run history every ",
640
+ HISTORY_POLL_MS / 1000,
641
+ "s; selected run every ",
642
+ ACTIVE_POLL_MS / 1000,
643
+ "s."
644
+ ]
645
+ })
646
+ ]
647
+ });
648
+ }
649
+ function SummaryPanel({ facts, results }) {
650
+ if (results === null)
651
+ return /* @__PURE__ */ jsx("p", {
652
+ children: "No captured results for the selected run."
653
+ });
654
+ return /* @__PURE__ */ jsx("dl", {
655
+ className: "kk-board-facts",
656
+ children: facts.map((fact) => /* @__PURE__ */ jsxs("div", {
657
+ children: [
658
+ /* @__PURE__ */ jsx("dt", {
659
+ children: fact.label
660
+ }),
661
+ /* @__PURE__ */ jsxs("dd", {
662
+ children: [
663
+ fact.value,
664
+ " ",
665
+ /* @__PURE__ */ jsx("span", {
666
+ className: "kk-board-state",
667
+ children: fact.availability
668
+ })
669
+ ]
670
+ })
671
+ ]
672
+ }, fact.label))
673
+ });
674
+ }
675
+ function ChannelList({ channels }) {
676
+ if (channels.length === 0)
677
+ return /* @__PURE__ */ jsx("p", {
678
+ children: "No channel outcomes recorded for the selected run."
679
+ });
680
+ return /* @__PURE__ */ jsx("ul", {
681
+ className: "kk-board-channels",
682
+ children: channels.map((channel) => /* @__PURE__ */ jsxs("li", {
683
+ children: [
684
+ /* @__PURE__ */ jsx("strong", {
685
+ children: channel.label
686
+ }),
687
+ " — ",
688
+ channel.state,
689
+ channel.detail === null ? null : /* @__PURE__ */ jsxs("span", {
690
+ className: "kk-board-state",
691
+ children: [
692
+ " (",
693
+ channel.detail,
694
+ ")"
695
+ ]
696
+ }),
697
+ channel.url === null ? null : /* @__PURE__ */ jsxs(Fragment, {
698
+ children: [
699
+ " ",
700
+ /* @__PURE__ */ jsx("a", {
701
+ href: channel.url,
702
+ rel: "noreferrer",
703
+ children: "open"
704
+ })
705
+ ]
706
+ })
707
+ ]
708
+ }, channel.channel))
709
+ });
710
+ }
711
+ function ResultsPanel({
712
+ artifacts,
713
+ channels
714
+ }) {
715
+ if (artifacts.length === 0)
716
+ return /* @__PURE__ */ jsx("p", {
717
+ children: "No artifact evidence for the selected run."
718
+ });
719
+ const media = artifacts.filter((artifact) => artifact.kind === "image" || artifact.kind === "audio");
720
+ const files = artifacts.filter((artifact) => artifact.kind !== "image" && artifact.kind !== "audio");
721
+ return /* @__PURE__ */ jsxs("div", {
722
+ className: "kk-board-results",
723
+ children: [
724
+ media.map((artifact) => artifact.href === null ? /* @__PURE__ */ jsxs("p", {
725
+ children: [
726
+ artifact.label,
727
+ " — ",
728
+ artifact.state
729
+ ]
730
+ }, artifact.id) : artifact.kind === "audio" ? /* @__PURE__ */ jsxs("p", {
731
+ children: [
732
+ /* @__PURE__ */ jsx("audio", {
733
+ controls: true,
734
+ src: artifact.href,
735
+ children: /* @__PURE__ */ jsx("track", {
736
+ kind: "captions"
737
+ })
738
+ }),
739
+ /* @__PURE__ */ jsxs("a", {
740
+ href: artifact.href,
741
+ download: true,
742
+ children: [
743
+ "download ",
744
+ artifact.label
745
+ ]
746
+ }),
747
+ " ",
748
+ "— ",
749
+ artifact.state
750
+ ]
751
+ }, artifact.id) : /* @__PURE__ */ jsxs("p", {
752
+ children: [
753
+ /* @__PURE__ */ jsx("img", {
754
+ src: artifact.href,
755
+ alt: artifact.label
756
+ }),
757
+ " ",
758
+ artifact.label,
759
+ " — ",
760
+ artifact.state
761
+ ]
762
+ }, artifact.id)),
763
+ /* @__PURE__ */ jsx("ul", {
764
+ className: "kk-board-artifacts",
765
+ children: files.map((artifact) => /* @__PURE__ */ jsx("li", {
766
+ children: artifact.href === null ? /* @__PURE__ */ jsxs("span", {
767
+ children: [
768
+ artifact.label,
769
+ " — ",
770
+ artifact.state
771
+ ]
772
+ }) : /* @__PURE__ */ jsxs("a", {
773
+ href: artifact.href,
774
+ children: [
775
+ artifact.label,
776
+ " — ",
777
+ artifact.state
778
+ ]
779
+ })
780
+ }, artifact.id))
781
+ }),
782
+ /* @__PURE__ */ jsx(ChannelList, {
783
+ channels
784
+ })
785
+ ]
786
+ });
787
+ }
788
+ function ProgressPanel({ progress }) {
789
+ if (progress === null || progress.nodes.length === 0) {
790
+ return /* @__PURE__ */ jsx("p", {
791
+ children: "Recorded progress is unavailable for the selected run."
792
+ });
793
+ }
794
+ return /* @__PURE__ */ jsxs("div", {
795
+ className: "kk-board-progress",
796
+ children: [
797
+ /* @__PURE__ */ jsx("ul", {
798
+ children: progress.nodes.map((node) => /* @__PURE__ */ jsxs("li", {
799
+ children: [
800
+ /* @__PURE__ */ jsx("strong", {
801
+ children: node.id
802
+ }),
803
+ " — ",
804
+ node.status,
805
+ " · ",
806
+ node.timing,
807
+ node.attempts > 1 ? /* @__PURE__ */ jsxs("span", {
808
+ className: "kk-board-state",
809
+ children: [
810
+ " ",
811
+ node.attempts,
812
+ " attempts"
813
+ ]
814
+ }) : null
815
+ ]
816
+ }, node.id))
817
+ }),
818
+ progress.edgesKnown && progress.edges !== null ? /* @__PURE__ */ jsx("ul", {
819
+ className: "kk-board-edges",
820
+ children: progress.edges.map((edge) => /* @__PURE__ */ jsxs("li", {
821
+ children: [
822
+ edge.from,
823
+ " → ",
824
+ edge.to
825
+ ]
826
+ }, `${edge.from}->${edge.to}`))
827
+ }) : /* @__PURE__ */ jsxs("p", {
828
+ children: [
829
+ "Dependency edges are unknown — no digest-verified topology was captured. See",
830
+ " ",
831
+ /* @__PURE__ */ jsx("a", {
832
+ href: "/board/settings/workflows",
833
+ children: "Settings → Workflows"
834
+ }),
835
+ " for the current graph."
836
+ ]
837
+ }),
838
+ progress.childRunId === null ? null : /* @__PURE__ */ jsxs("p", {
839
+ children: [
840
+ "Nested safety run: ",
841
+ /* @__PURE__ */ jsx("code", {
842
+ children: progress.childRunId
843
+ })
844
+ ]
845
+ })
846
+ ]
847
+ });
848
+ }
849
+ function ConfigPanel({ config }) {
850
+ if (config === null)
851
+ return /* @__PURE__ */ jsx("p", {
852
+ children: "No captured configuration for the selected run."
853
+ });
854
+ const entries = Object.entries(config.settings);
855
+ return /* @__PURE__ */ jsxs("div", {
856
+ className: "kk-board-config",
857
+ children: [
858
+ /* @__PURE__ */ jsxs("p", {
859
+ children: [
860
+ "Captured ",
861
+ formatTimestamp(config.capturedAt)
862
+ ]
863
+ }),
864
+ entries.length === 0 ? /* @__PURE__ */ jsx("p", {
865
+ children: "Recorded configuration unavailable for this run."
866
+ }) : null,
867
+ /* @__PURE__ */ jsx("dl", {
868
+ children: entries.map(([key, value]) => /* @__PURE__ */ jsxs("div", {
869
+ children: [
870
+ /* @__PURE__ */ jsx("dt", {
871
+ children: key
872
+ }),
873
+ /* @__PURE__ */ jsx("dd", {
874
+ children: value
875
+ })
876
+ ]
877
+ }, key))
878
+ }),
879
+ config.unavailableKeys.length === 0 ? null : /* @__PURE__ */ jsxs("p", {
880
+ children: [
881
+ "Uncaptured keys: ",
882
+ config.unavailableKeys.join(", ")
883
+ ]
884
+ }),
885
+ /* @__PURE__ */ jsxs("p", {
886
+ children: [
887
+ "Current definitions and defaults live in ",
888
+ /* @__PURE__ */ jsx("a", {
889
+ href: "/board/settings/workflows",
890
+ children: "Settings → Workflows"
891
+ }),
892
+ "."
893
+ ]
894
+ })
895
+ ]
896
+ });
897
+ }
898
+ var webModule = { apiVersion: 1, component: DailyVoiceModule };
899
+ export {
900
+ DailyVoiceModule,
901
+ webModule
902
+ };