miriad-viz 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cli/{chunk-HFGJKQTB.js → chunk-4CGFDD2G.js} +9 -1
- package/dist-cli/{chunk-R7QITZ76.js → chunk-CUDVVNEZ.js} +22 -0
- package/dist-cli/{chunk-GPVKAGZT.js → chunk-IMD2MNLI.js} +1 -1
- package/dist-cli/chunk-PHPII3CV.js +248 -0
- package/dist-cli/{curate-LBMQRKKG.js → curate-QUIYJ7VJ.js} +33 -10
- package/dist-cli/{extract-S5XKRYPG.js → extract-NDJN7REW.js} +285 -47
- package/dist-cli/index.js +133 -44
- package/dist-cli/{preview-F7ILLPMG.js → preview-PXC6HTMF.js} +52 -6
- package/dist-cli/{render-TC223YOE.js → render-JV57PXIE.js} +12 -1
- package/dist-cli/{transform-TEJWDQWZ.js → transform-POVVUALD.js} +13 -2
- package/dist-lib/{chunk-TCRXL725.js → chunk-A4KKFJGR.js} +15 -9
- package/dist-lib/chunk-A4KKFJGR.js.map +1 -0
- package/dist-lib/{chunk-LJG3H4FA.cjs → chunk-M54CHKPH.cjs} +15 -9
- package/dist-lib/chunk-M54CHKPH.cjs.map +1 -0
- package/dist-lib/index.cjs +9 -1
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.js +9 -1
- package/dist-lib/index.js.map +1 -1
- package/dist-lib/renderer/index.cjs +10 -10
- package/dist-lib/renderer/index.d.cts +7 -0
- package/dist-lib/renderer/index.d.ts +7 -0
- package/dist-lib/renderer/index.js +1 -1
- package/dist-lib/viewer/exports.cjs +657 -98
- package/dist-lib/viewer/exports.cjs.map +1 -1
- package/dist-lib/viewer/exports.d.cts +119 -60
- package/dist-lib/viewer/exports.d.ts +119 -60
- package/dist-lib/viewer/exports.js +633 -78
- package/dist-lib/viewer/exports.js.map +1 -1
- package/package.json +1 -1
- package/template/remotion/src/AudioLayer.tsx +4 -4
- package/template/remotion/src/MiriadViz.tsx +77 -74
- package/template/viewer/src/App.tsx +106 -8
- package/dist-lib/chunk-LJG3H4FA.cjs.map +0 -1
- package/dist-lib/chunk-TCRXL725.js.map +0 -1
|
@@ -148,7 +148,15 @@ function transformPRs(prs, prAgentMap) {
|
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
150
|
function inferArtifactType(slug) {
|
|
151
|
-
if (slug.
|
|
151
|
+
if (slug.startsWith("plan/task-")) return "task";
|
|
152
|
+
if (slug.startsWith("plan/spec-")) return "doc";
|
|
153
|
+
const ext = slug.split(".").pop()?.toLowerCase();
|
|
154
|
+
if (ext && ["ts", "tsx", "js", "jsx", "py", "rs", "go", "sh"].includes(ext)) return "code";
|
|
155
|
+
if (ext && ["png", "jpg", "jpeg", "svg", "gif", "webp", "ico"].includes(ext)) return "asset";
|
|
156
|
+
if (ext && ["md", "txt", "json", "yaml", "yml", "toml"].includes(ext)) return "doc";
|
|
157
|
+
if (slug.includes("/specs/") || slug.includes("/spec/")) return "doc";
|
|
158
|
+
if (slug.includes("/assets/") || slug.includes("/images/")) return "asset";
|
|
159
|
+
if (slug.includes(".app.")) return "code";
|
|
152
160
|
if (slug.includes("screenshot") || slug.includes("qa-")) return "asset";
|
|
153
161
|
if (slug.includes("decision")) return "decision";
|
|
154
162
|
if (slug.includes("task") || slug.includes("phase-")) return "task";
|
|
@@ -115,6 +115,26 @@ function buildChatActivity(messages, channelName, knownAgents) {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// src/cli/extract/time-range-filter.ts
|
|
118
|
+
var AUTO_TRIM_PADDING_HOURS = 12;
|
|
119
|
+
function computeMessageWindow(items, dateAccessor, paddingHours = AUTO_TRIM_PADDING_HOURS) {
|
|
120
|
+
if (items.length === 0) return {};
|
|
121
|
+
const getDate = typeof dateAccessor === "function" ? dateAccessor : (item) => item[dateAccessor];
|
|
122
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
123
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
124
|
+
for (const item of items) {
|
|
125
|
+
const dateStr = getDate(item);
|
|
126
|
+
if (!dateStr) continue;
|
|
127
|
+
const ms = new Date(dateStr).getTime();
|
|
128
|
+
if (ms < minMs) minMs = ms;
|
|
129
|
+
if (ms > maxMs) maxMs = ms;
|
|
130
|
+
}
|
|
131
|
+
if (minMs === Number.POSITIVE_INFINITY) return {};
|
|
132
|
+
const paddingMs = paddingHours * 60 * 60 * 1e3;
|
|
133
|
+
return {
|
|
134
|
+
from: new Date(minMs - paddingMs).toISOString(),
|
|
135
|
+
to: new Date(maxMs + paddingMs).toISOString()
|
|
136
|
+
};
|
|
137
|
+
}
|
|
118
138
|
function parseDate(dateStr, isEndBound) {
|
|
119
139
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
|
120
140
|
if (isEndBound) {
|
|
@@ -140,5 +160,7 @@ function filterByDateRange(items, dateAccessor, range) {
|
|
|
140
160
|
export {
|
|
141
161
|
extractMentions,
|
|
142
162
|
buildChatActivity,
|
|
163
|
+
AUTO_TRIM_PADDING_HOURS,
|
|
164
|
+
computeMessageWindow,
|
|
143
165
|
filterByDateRange
|
|
144
166
|
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// src/cli/board-sync.ts
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
3
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
function canSync() {
|
|
6
|
+
return !!(process.env.MIRIAD_SPACE_TOKEN && process.env.MIRIAD_API_URL && process.env.MIRIAD_CHANNEL_ID);
|
|
7
|
+
}
|
|
8
|
+
function getBoardSyncConfig(boardDir = "/viz-output") {
|
|
9
|
+
const apiUrl = process.env.MIRIAD_API_URL;
|
|
10
|
+
const channelId = process.env.MIRIAD_CHANNEL_ID;
|
|
11
|
+
const spaceToken = process.env.MIRIAD_SPACE_TOKEN;
|
|
12
|
+
if (!apiUrl || !channelId || !spaceToken) return null;
|
|
13
|
+
return { apiUrl, channelId, spaceToken, boardDir };
|
|
14
|
+
}
|
|
15
|
+
var TIMEOUT_MS = 1e4;
|
|
16
|
+
async function syncTextFile(config, localPath, boardPath) {
|
|
17
|
+
const content = readFileSync(localPath, "utf-8");
|
|
18
|
+
const fullBoardPath = `${config.boardDir}/${boardPath}`;
|
|
19
|
+
const url = `${config.apiUrl}/channels/${config.channelId}/files${fullBoardPath}`;
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
22
|
+
try {
|
|
23
|
+
const res = await fetch(url, {
|
|
24
|
+
method: "PUT",
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${config.spaceToken}`,
|
|
27
|
+
"Content-Type": "application/json"
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({ content }),
|
|
30
|
+
signal: controller.signal
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.text().catch(() => "");
|
|
34
|
+
console.warn(` \u26A0 Board sync failed for ${boardPath}: ${res.status} ${body.slice(0, 100)}`);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
console.warn(` \u26A0 Board sync failed for ${boardPath}: ${msg}`);
|
|
39
|
+
} finally {
|
|
40
|
+
clearTimeout(timeout);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function syncBinaryFile(config, localPath, boardPath, mimeType = "application/octet-stream") {
|
|
44
|
+
const fullBoardPath = `${config.boardDir}/${boardPath}`;
|
|
45
|
+
const uploadUrl = `${config.apiUrl}/channels/${config.channelId}/files/upload`;
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
48
|
+
try {
|
|
49
|
+
const res = await fetch(uploadUrl, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: `Bearer ${config.spaceToken}`,
|
|
53
|
+
"Content-Type": "application/json"
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ path: fullBoardPath, mimeType }),
|
|
56
|
+
signal: controller.signal
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
const body = await res.text().catch(() => "");
|
|
60
|
+
console.warn(
|
|
61
|
+
` \u26A0 Board upload request failed for ${boardPath}: ${res.status} ${body.slice(0, 100)}`
|
|
62
|
+
);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const { uploadUrl: presignedUrl } = await res.json();
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
const uploadController = new AbortController();
|
|
68
|
+
const uploadTimeout = setTimeout(() => uploadController.abort(), TIMEOUT_MS);
|
|
69
|
+
try {
|
|
70
|
+
const fileData = readFileSync(localPath);
|
|
71
|
+
const putRes = await fetch(presignedUrl, {
|
|
72
|
+
method: "PUT",
|
|
73
|
+
headers: { "Content-Type": mimeType },
|
|
74
|
+
body: fileData,
|
|
75
|
+
signal: uploadController.signal
|
|
76
|
+
});
|
|
77
|
+
if (!putRes.ok) {
|
|
78
|
+
console.warn(` \u26A0 Board binary upload failed for ${boardPath}: ${putRes.status}`);
|
|
79
|
+
}
|
|
80
|
+
} finally {
|
|
81
|
+
clearTimeout(uploadTimeout);
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
85
|
+
console.warn(` \u26A0 Board sync failed for ${boardPath}: ${msg}`);
|
|
86
|
+
} finally {
|
|
87
|
+
clearTimeout(timeout);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
var STEP_FILE_MAP = {
|
|
91
|
+
extract: [".miriad-viz.json"],
|
|
92
|
+
curate: ["retro-page-data.json", "retro-page-quotes.json", "timeline-events.json"],
|
|
93
|
+
script: ["script.json", "pacing.json"],
|
|
94
|
+
voices: [],
|
|
95
|
+
// handled specially — glob for audio/*.mp3
|
|
96
|
+
"viz-timing": ["timing.json"],
|
|
97
|
+
"sound-design": ["audio-manifest.json"],
|
|
98
|
+
transform: ["viz-data.json"],
|
|
99
|
+
render: []
|
|
100
|
+
// render output is the final video — too large for board
|
|
101
|
+
};
|
|
102
|
+
var ALWAYS_SYNC = [".miriad-viz.json"];
|
|
103
|
+
async function syncStepOutputs(config, step, dataDir) {
|
|
104
|
+
const files = STEP_FILE_MAP[step] ?? [];
|
|
105
|
+
const allFiles = [.../* @__PURE__ */ new Set([...files, ...ALWAYS_SYNC])];
|
|
106
|
+
let synced = 0;
|
|
107
|
+
for (const file of allFiles) {
|
|
108
|
+
const localPath = resolve(dataDir, file);
|
|
109
|
+
if (!existsSync(localPath)) continue;
|
|
110
|
+
await syncTextFile(config, localPath, file);
|
|
111
|
+
synced++;
|
|
112
|
+
}
|
|
113
|
+
if (step === "voices" || step === "sound-design") {
|
|
114
|
+
const audioDir = resolve(dataDir, "audio");
|
|
115
|
+
if (existsSync(audioDir)) {
|
|
116
|
+
const audioFiles = readdirSync(audioDir).filter((f) => f.endsWith(".mp3"));
|
|
117
|
+
for (const audioFile of audioFiles) {
|
|
118
|
+
const localPath = resolve(audioDir, audioFile);
|
|
119
|
+
await syncBinaryFile(config, localPath, `audio/${audioFile}`, "audio/mpeg");
|
|
120
|
+
synced++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (synced > 0) {
|
|
125
|
+
console.log(` \u2601 Synced ${synced} file${synced > 1 ? "s" : ""} to board`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function pullFromBoard(config, dataDir) {
|
|
129
|
+
const warnings = [];
|
|
130
|
+
let pulled = 0;
|
|
131
|
+
try {
|
|
132
|
+
const listUrl = `${config.apiUrl}/channels/${config.channelId}/files?glob=${encodeURIComponent(`${config.boardDir}/**`)}`;
|
|
133
|
+
const res = await fetch(listUrl, {
|
|
134
|
+
headers: { Authorization: `Bearer ${config.spaceToken}` }
|
|
135
|
+
});
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
warnings.push(`Board listing failed: ${res.status}`);
|
|
138
|
+
return { pulled, warnings };
|
|
139
|
+
}
|
|
140
|
+
const { results } = await res.json();
|
|
141
|
+
if (!results || results.length === 0) {
|
|
142
|
+
return { pulled, warnings };
|
|
143
|
+
}
|
|
144
|
+
mkdirSync(dataDir, { recursive: true });
|
|
145
|
+
for (const file of results) {
|
|
146
|
+
const relativePath = file.path.replace(`${config.boardDir}/`, "");
|
|
147
|
+
const localPath = resolve(dataDir, relativePath);
|
|
148
|
+
const parentDir = resolve(localPath, "..");
|
|
149
|
+
mkdirSync(parentDir, { recursive: true });
|
|
150
|
+
try {
|
|
151
|
+
if (file.isText) {
|
|
152
|
+
const fileUrl = `${config.apiUrl}/channels/${config.channelId}/files${file.path}`;
|
|
153
|
+
const fileRes = await fetch(fileUrl, {
|
|
154
|
+
headers: { Authorization: `Bearer ${config.spaceToken}` }
|
|
155
|
+
});
|
|
156
|
+
if (fileRes.ok) {
|
|
157
|
+
const data = await fileRes.json();
|
|
158
|
+
writeFileSync(localPath, data.content);
|
|
159
|
+
pulled++;
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
const downloadUrl = `${config.apiUrl}/channels/${config.channelId}/files${file.path}/download`;
|
|
163
|
+
const dlRes = await fetch(downloadUrl, {
|
|
164
|
+
headers: { Authorization: `Bearer ${config.spaceToken}` }
|
|
165
|
+
});
|
|
166
|
+
if (dlRes.ok) {
|
|
167
|
+
const { url } = await dlRes.json();
|
|
168
|
+
const binaryRes = await fetch(url);
|
|
169
|
+
if (binaryRes.ok) {
|
|
170
|
+
const buffer = Buffer.from(await binaryRes.arrayBuffer());
|
|
171
|
+
writeFileSync(localPath, buffer);
|
|
172
|
+
pulled++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} catch (err) {
|
|
177
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
178
|
+
warnings.push(`Failed to pull ${relativePath}: ${msg}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const progressPath = resolve(dataDir, ".miriad-viz.json");
|
|
182
|
+
if (existsSync(progressPath)) {
|
|
183
|
+
try {
|
|
184
|
+
const progress = JSON.parse(readFileSync(progressPath, "utf-8"));
|
|
185
|
+
const validationWarnings = validateProgressConsistency(progress, dataDir);
|
|
186
|
+
warnings.push(...validationWarnings);
|
|
187
|
+
} catch {
|
|
188
|
+
warnings.push("Failed to parse .miriad-viz.json for consistency check");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (err) {
|
|
192
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
193
|
+
warnings.push(`Board pull failed: ${msg}`);
|
|
194
|
+
}
|
|
195
|
+
return { pulled, warnings };
|
|
196
|
+
}
|
|
197
|
+
var STEP_REQUIRED_FILES = {
|
|
198
|
+
extract: ["git-commits.json"],
|
|
199
|
+
curate: ["retro-page-data.json", "timeline-events.json"],
|
|
200
|
+
script: ["script.json"],
|
|
201
|
+
voices: [],
|
|
202
|
+
// checked dynamically — at least one .mp3 in audio/
|
|
203
|
+
"viz-timing": ["timing.json"],
|
|
204
|
+
"sound-design": ["audio-manifest.json"],
|
|
205
|
+
transform: ["viz-data.json"]
|
|
206
|
+
};
|
|
207
|
+
function validateProgressConsistency(progress, dataDir) {
|
|
208
|
+
const warnings = [];
|
|
209
|
+
const steps = progress.steps;
|
|
210
|
+
if (!steps) return warnings;
|
|
211
|
+
for (const [step, state] of Object.entries(steps)) {
|
|
212
|
+
if (state.status !== "complete") continue;
|
|
213
|
+
const requiredFiles = STEP_REQUIRED_FILES[step];
|
|
214
|
+
if (!requiredFiles) continue;
|
|
215
|
+
if (step === "voices") {
|
|
216
|
+
const audioDir = resolve(dataDir, "audio");
|
|
217
|
+
const hasMp3 = existsSync(audioDir) && readdirSync(audioDir).some((f) => f.endsWith(".mp3"));
|
|
218
|
+
if (!hasMp3) {
|
|
219
|
+
warnings.push(
|
|
220
|
+
`Step '${step}' marked complete but no audio files found \u2014 resetting to pending`
|
|
221
|
+
);
|
|
222
|
+
state.status = "pending";
|
|
223
|
+
}
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
for (const file of requiredFiles) {
|
|
227
|
+
if (!existsSync(resolve(dataDir, file))) {
|
|
228
|
+
warnings.push(`Step '${step}' marked complete but ${file} missing \u2014 resetting to pending`);
|
|
229
|
+
state.status = "pending";
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (warnings.length > 0) {
|
|
235
|
+
const progressPath = resolve(dataDir, ".miriad-viz.json");
|
|
236
|
+
writeFileSync(progressPath, `${JSON.stringify(progress, null, 2)}
|
|
237
|
+
`);
|
|
238
|
+
}
|
|
239
|
+
return warnings;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export {
|
|
243
|
+
canSync,
|
|
244
|
+
getBoardSyncConfig,
|
|
245
|
+
syncTextFile,
|
|
246
|
+
syncStepOutputs,
|
|
247
|
+
pullFromBoard
|
|
248
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
extractMentions,
|
|
3
3
|
filterByDateRange
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CUDVVNEZ.js";
|
|
5
5
|
import {
|
|
6
6
|
inferRole
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4CGFDD2G.js";
|
|
8
8
|
import {
|
|
9
9
|
markComplete,
|
|
10
10
|
markInProgress,
|
|
11
11
|
writeProgress
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IMD2MNLI.js";
|
|
13
13
|
|
|
14
14
|
// src/cli/guided/steps/curate.ts
|
|
15
15
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -27,8 +27,9 @@ function getDateRange(dataDir, chatInputPath) {
|
|
|
27
27
|
} catch {
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
const messagesVizInDataDir = resolve(dataDir, "messages-viz.json");
|
|
30
31
|
const messagesInDataDir = resolve(dataDir, "messages.json");
|
|
31
|
-
const messagesPath = existsSync(messagesInDataDir) ? messagesInDataDir : chatInputPath && existsSync(chatInputPath) ? chatInputPath : null;
|
|
32
|
+
const messagesPath = existsSync(messagesVizInDataDir) ? messagesVizInDataDir : existsSync(messagesInDataDir) ? messagesInDataDir : chatInputPath && existsSync(chatInputPath) ? chatInputPath : null;
|
|
32
33
|
if (messagesPath) {
|
|
33
34
|
try {
|
|
34
35
|
const raw = JSON.parse(readFileSync(messagesPath, "utf-8"));
|
|
@@ -95,11 +96,12 @@ function getAgentList(dataDir, chatInputPath) {
|
|
|
95
96
|
} catch {
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
99
|
+
const messagesVizInDataDir2 = resolve(dataDir, "messages-viz.json");
|
|
100
|
+
const messagesInDataDir2 = resolve(dataDir, "messages.json");
|
|
101
|
+
const agentMessagesPath = existsSync(messagesVizInDataDir2) ? messagesVizInDataDir2 : existsSync(messagesInDataDir2) ? messagesInDataDir2 : chatInputPath && existsSync(chatInputPath) ? chatInputPath : null;
|
|
102
|
+
if (agentMessagesPath) {
|
|
101
103
|
try {
|
|
102
|
-
const raw = JSON.parse(readFileSync(
|
|
104
|
+
const raw = JSON.parse(readFileSync(agentMessagesPath, "utf-8"));
|
|
103
105
|
const messages = raw.messages || raw;
|
|
104
106
|
for (const m of messages) agents.add(m.sender);
|
|
105
107
|
} catch {
|
|
@@ -336,14 +338,35 @@ function generateTimelineEvents(dataDir, chatInputPath, dateRange) {
|
|
|
336
338
|
}
|
|
337
339
|
}
|
|
338
340
|
const chatActivityPath = resolve(dataDir, "chat-activity.json");
|
|
341
|
+
const messagesVizPath = resolve(dataDir, "messages-viz.json");
|
|
339
342
|
const messagesInDataDir = resolve(dataDir, "messages.json");
|
|
340
|
-
|
|
343
|
+
let messagesPath = null;
|
|
344
|
+
let usePreExtractedMentions = false;
|
|
345
|
+
if (existsSync(chatActivityPath)) {
|
|
346
|
+
try {
|
|
347
|
+
const raw = JSON.parse(readFileSync(chatActivityPath, "utf-8"));
|
|
348
|
+
if (Array.isArray(raw.messages) || Array.isArray(raw)) {
|
|
349
|
+
messagesPath = chatActivityPath;
|
|
350
|
+
}
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (!messagesPath && existsSync(messagesVizPath)) {
|
|
355
|
+
messagesPath = messagesVizPath;
|
|
356
|
+
usePreExtractedMentions = true;
|
|
357
|
+
}
|
|
358
|
+
if (!messagesPath && existsSync(messagesInDataDir)) {
|
|
359
|
+
messagesPath = messagesInDataDir;
|
|
360
|
+
}
|
|
361
|
+
if (!messagesPath && chatInputPath && existsSync(chatInputPath)) {
|
|
362
|
+
messagesPath = chatInputPath;
|
|
363
|
+
}
|
|
341
364
|
if (messagesPath) {
|
|
342
365
|
try {
|
|
343
366
|
const raw = JSON.parse(readFileSync(messagesPath, "utf-8"));
|
|
344
367
|
const messages = raw.messages || raw;
|
|
345
368
|
for (const msg of messages) {
|
|
346
|
-
const mentions = extractMentions(msg.content, msg.sender);
|
|
369
|
+
const mentions = usePreExtractedMentions && msg.mentions ? msg.mentions : msg.content ? extractMentions(msg.content, msg.sender) : [];
|
|
347
370
|
if (mentions.length > 0) {
|
|
348
371
|
events.push({
|
|
349
372
|
type: "message",
|