@gobing-ai/knowledge-kit 0.0.35 → 0.0.36

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