@triedotdev/mcp 1.0.165 → 1.0.167
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/README.md +337 -801
- package/dist/chunk-2HF65EHQ.js +311 -0
- package/dist/chunk-2HF65EHQ.js.map +1 -0
- package/dist/{chunk-M7HMBZ3R.js → chunk-4MXH2ZPT.js} +12 -12
- package/dist/chunk-4MXH2ZPT.js.map +1 -0
- package/dist/{chunk-LR5M4RTN.js → chunk-575YT2SD.js} +1 -1
- package/dist/chunk-575YT2SD.js.map +1 -0
- package/dist/{chunk-HC5P6FZD.js → chunk-5BRRRTN6.js} +4 -4
- package/dist/{chunk-IPNPHPNN.js → chunk-7WITSO22.js} +3 -3
- package/dist/{chunk-ACU2RJUJ.js → chunk-F6WFNUAY.js} +2 -2
- package/dist/{chunk-VR4VWXXU.js → chunk-G2TGF6TR.js} +9 -2
- package/dist/chunk-G2TGF6TR.js.map +1 -0
- package/dist/{chunk-ZBXW244P.js → chunk-HVCDY3AK.js} +3 -3
- package/dist/chunk-HVCDY3AK.js.map +1 -0
- package/dist/{chunk-CDG2GVBP.js → chunk-LQIMKE3P.js} +700 -151
- package/dist/chunk-LQIMKE3P.js.map +1 -0
- package/dist/{chunk-RQ6QZBIN.js → chunk-MRHKX5M5.js} +3 -3
- package/dist/{chunk-OLNZJ3XV.js → chunk-Q63FFI6D.js} +2 -2
- package/dist/{chunk-SS2O3MTC.js → chunk-XE6KQRKZ.js} +9 -8
- package/dist/chunk-XE6KQRKZ.js.map +1 -0
- package/dist/{chunk-GDWA3CH3.js → chunk-XPZZFPBZ.js} +30 -6
- package/dist/chunk-XPZZFPBZ.js.map +1 -0
- package/dist/{chunk-WRYQHVPD.js → chunk-XTFWT2XM.js} +2 -2
- package/dist/{chunk-IS5UBN2R.js → chunk-YDHUCDHM.js} +18 -112
- package/dist/chunk-YDHUCDHM.js.map +1 -0
- package/dist/{chunk-5LRDF2WB.js → chunk-YZ6Y2H3P.js} +21 -196
- package/dist/chunk-YZ6Y2H3P.js.map +1 -0
- package/dist/{chunk-YAL3SUBG.js → chunk-ZJF5FTBX.js} +126 -355
- package/dist/chunk-ZJF5FTBX.js.map +1 -0
- package/dist/cli/create-agent.js +1 -1
- package/dist/cli/create-agent.js.map +1 -1
- package/dist/cli/main.js +194 -849
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +15 -14
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/{fast-analyzer-54AHLVO5.js → fast-analyzer-XXYMOXRK.js} +3 -3
- package/dist/git-EO5SRFMN.js +28 -0
- package/dist/{github-ingester-TFBDUDIY.js → github-ingester-ZOKK6GRS.js} +3 -3
- package/dist/{goal-manager-563BNILQ.js → goal-manager-YOB7VWK7.js} +5 -4
- package/dist/{goal-validator-FJEDIYU7.js → goal-validator-ULKIBDPX.js} +5 -4
- package/dist/{hypothesis-4KC7XRBZ.js → hypothesis-7BFFT5JY.js} +5 -4
- package/dist/index.js +19 -18
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-FOS4T736.js → issue-store-ZIRP23EP.js} +4 -3
- package/dist/{ledger-EDLPF6SB.js → ledger-TWZTGDFA.js} +3 -2
- package/dist/{linear-ingester-PLES2BRS.js → linear-ingester-XXPAZZRW.js} +3 -3
- package/dist/{output-manager-JNMEAXFO.js → output-manager-RVJ37XKA.js} +2 -2
- package/dist/server/mcp-server.js +19 -18
- package/dist/{tiered-storage-OP74NPJY.js → tiered-storage-Z3YCR465.js} +2 -2
- package/dist/{trie-agent-TM6ATSNR.js → trie-agent-3YDPEGHJ.js} +9 -8
- package/dist/trie-agent-3YDPEGHJ.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-5LRDF2WB.js.map +0 -1
- package/dist/chunk-CDG2GVBP.js.map +0 -1
- package/dist/chunk-GDWA3CH3.js.map +0 -1
- package/dist/chunk-IS5UBN2R.js.map +0 -1
- package/dist/chunk-LR5M4RTN.js.map +0 -1
- package/dist/chunk-M7HMBZ3R.js.map +0 -1
- package/dist/chunk-SS2O3MTC.js.map +0 -1
- package/dist/chunk-VR4VWXXU.js.map +0 -1
- package/dist/chunk-YAL3SUBG.js.map +0 -1
- package/dist/chunk-ZBXW244P.js.map +0 -1
- /package/dist/{chunk-HC5P6FZD.js.map → chunk-5BRRRTN6.js.map} +0 -0
- /package/dist/{chunk-IPNPHPNN.js.map → chunk-7WITSO22.js.map} +0 -0
- /package/dist/{chunk-ACU2RJUJ.js.map → chunk-F6WFNUAY.js.map} +0 -0
- /package/dist/{chunk-RQ6QZBIN.js.map → chunk-MRHKX5M5.js.map} +0 -0
- /package/dist/{chunk-OLNZJ3XV.js.map → chunk-Q63FFI6D.js.map} +0 -0
- /package/dist/{chunk-WRYQHVPD.js.map → chunk-XTFWT2XM.js.map} +0 -0
- /package/dist/{fast-analyzer-54AHLVO5.js.map → fast-analyzer-XXYMOXRK.js.map} +0 -0
- /package/dist/{github-ingester-TFBDUDIY.js.map → git-EO5SRFMN.js.map} +0 -0
- /package/dist/{goal-manager-563BNILQ.js.map → github-ingester-ZOKK6GRS.js.map} +0 -0
- /package/dist/{goal-validator-FJEDIYU7.js.map → goal-manager-YOB7VWK7.js.map} +0 -0
- /package/dist/{hypothesis-4KC7XRBZ.js.map → goal-validator-ULKIBDPX.js.map} +0 -0
- /package/dist/{issue-store-FOS4T736.js.map → hypothesis-7BFFT5JY.js.map} +0 -0
- /package/dist/{ledger-EDLPF6SB.js.map → issue-store-ZIRP23EP.js.map} +0 -0
- /package/dist/{linear-ingester-PLES2BRS.js.map → ledger-TWZTGDFA.js.map} +0 -0
- /package/dist/{output-manager-JNMEAXFO.js.map → linear-ingester-XXPAZZRW.js.map} +0 -0
- /package/dist/{tiered-storage-OP74NPJY.js.map → output-manager-RVJ37XKA.js.map} +0 -0
- /package/dist/{trie-agent-TM6ATSNR.js.map → tiered-storage-Z3YCR465.js.map} +0 -0
|
@@ -5,6 +5,10 @@ import {
|
|
|
5
5
|
getTrieDirectory,
|
|
6
6
|
getWorkingDirectory
|
|
7
7
|
} from "./chunk-VVITXIHN.js";
|
|
8
|
+
import {
|
|
9
|
+
getLastCommit,
|
|
10
|
+
isGitRepo
|
|
11
|
+
} from "./chunk-2HF65EHQ.js";
|
|
8
12
|
import {
|
|
9
13
|
__require
|
|
10
14
|
} from "./chunk-DGUM43GV.js";
|
|
@@ -12,7 +16,7 @@ import {
|
|
|
12
16
|
// src/memory/ledger.ts
|
|
13
17
|
import { createHash } from "crypto";
|
|
14
18
|
import { mkdir as mkdir2, readFile as readFile2, writeFile, stat as stat2, unlink as unlink2 } from "fs/promises";
|
|
15
|
-
import { existsSync as
|
|
19
|
+
import { existsSync as existsSync4 } from "fs";
|
|
16
20
|
import { createGzip, createGunzip } from "zlib";
|
|
17
21
|
import { pipeline } from "stream/promises";
|
|
18
22
|
import { createReadStream, createWriteStream } from "fs";
|
|
@@ -143,311 +147,10 @@ function isProcessRunning(pid) {
|
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
|
|
146
|
-
// src/agent/git.ts
|
|
147
|
-
import { existsSync as existsSync2 } from "fs";
|
|
148
|
-
import path from "path";
|
|
149
|
-
|
|
150
|
-
// src/utils/command-runner.ts
|
|
151
|
-
import { exec, execFile, execSync } from "child_process";
|
|
152
|
-
import { promisify } from "util";
|
|
153
|
-
|
|
154
|
-
// src/utils/audit-logger.ts
|
|
155
|
-
function formatAuditLog(_entry) {
|
|
156
|
-
return "Audit logging has been integrated into the decision ledger";
|
|
157
|
-
}
|
|
158
|
-
function getAuditStatistics() {
|
|
159
|
-
return {
|
|
160
|
-
totalScans: 0,
|
|
161
|
-
totalIssues: 0,
|
|
162
|
-
criticalCount: 0,
|
|
163
|
-
seriousCount: 0,
|
|
164
|
-
moderateCount: 0,
|
|
165
|
-
lowCount: 0,
|
|
166
|
-
totalExecutions: 0,
|
|
167
|
-
successfulExecutions: 0,
|
|
168
|
-
failedExecutions: 0,
|
|
169
|
-
uniqueSkills: 0,
|
|
170
|
-
totalCommands: 0,
|
|
171
|
-
blockedCommands: 0,
|
|
172
|
-
totalNetworkCalls: 0,
|
|
173
|
-
blockedNetworkCalls: 0
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
function createAuditEntry(skillName, skillSource, triggeredBy, targetPath) {
|
|
177
|
-
return {
|
|
178
|
-
skillName,
|
|
179
|
-
skillSource,
|
|
180
|
-
triggeredBy,
|
|
181
|
-
targetPath,
|
|
182
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
183
|
-
commands: []
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function completeAuditEntry(entry, success, error) {
|
|
187
|
-
const result = {
|
|
188
|
-
...entry,
|
|
189
|
-
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
190
|
-
success
|
|
191
|
-
};
|
|
192
|
-
if (error !== void 0) {
|
|
193
|
-
result.error = error;
|
|
194
|
-
}
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
async function logSkillExecution(_execution) {
|
|
198
|
-
}
|
|
199
|
-
async function getRecentAuditLogs(_limit = 10) {
|
|
200
|
-
return [];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// src/utils/command-runner.ts
|
|
204
|
-
var execAsync = promisify(exec);
|
|
205
|
-
var execFileAsync = promisify(execFile);
|
|
206
|
-
function redact(text) {
|
|
207
|
-
return text.replace(/\b(AWS|ANTHROPIC|OPENAI|GITHUB)_[A-Z0-9_]*\s*=\s*([^\s"'`]+)/gi, "$1_<REDACTED>=<REDACTED>").replace(/\bBearer\s+[A-Za-z0-9\-._~+/]+=*\b/g, "Bearer <REDACTED>").replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "ghp_<REDACTED>").replace(/\b(?:xox[baprs]-)[A-Za-z0-9-]{10,}\b/g, "<REDACTED_SLACK_TOKEN>").replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA<REDACTED>");
|
|
208
|
-
}
|
|
209
|
-
function clampOutput(text, maxChars) {
|
|
210
|
-
if (text.length <= maxChars) return text;
|
|
211
|
-
return text.slice(0, maxChars) + `
|
|
212
|
-
\u2026(truncated ${text.length - maxChars} chars)`;
|
|
213
|
-
}
|
|
214
|
-
function buildCommandRecord(command) {
|
|
215
|
-
return {
|
|
216
|
-
command,
|
|
217
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
async function finalizeAndWrite(entry, cmd, outcome, options) {
|
|
221
|
-
const duration = Date.now() - outcome.startedAt;
|
|
222
|
-
cmd.duration = duration;
|
|
223
|
-
if (outcome.exitCode !== void 0) {
|
|
224
|
-
cmd.exitCode = outcome.exitCode;
|
|
225
|
-
}
|
|
226
|
-
const captureOutput = options?.captureOutput ?? false;
|
|
227
|
-
const redactOutput = options?.redactOutput ?? true;
|
|
228
|
-
const maxOutputChars = options?.maxOutputChars ?? 2e3;
|
|
229
|
-
if (captureOutput) {
|
|
230
|
-
const out = outcome.stdout ?? "";
|
|
231
|
-
const err = outcome.stderr ?? "";
|
|
232
|
-
cmd.stdout = redactOutput ? redact(clampOutput(out, maxOutputChars)) : clampOutput(out, maxOutputChars);
|
|
233
|
-
cmd.stderr = redactOutput ? redact(clampOutput(err, maxOutputChars)) : clampOutput(err, maxOutputChars);
|
|
234
|
-
}
|
|
235
|
-
const completed = completeAuditEntry(entry, outcome.success, outcome.error);
|
|
236
|
-
await logSkillExecution(completed);
|
|
237
|
-
}
|
|
238
|
-
function runShellCommandSync(command, audit, options) {
|
|
239
|
-
const startedAt = Date.now();
|
|
240
|
-
const entry = createAuditEntry(audit.actor, audit.source ?? "trie", audit.triggeredBy, audit.targetPath);
|
|
241
|
-
const cmd = buildCommandRecord(command);
|
|
242
|
-
entry.commands?.push(cmd);
|
|
243
|
-
try {
|
|
244
|
-
const stdout = execSync(command, {
|
|
245
|
-
cwd: options?.cwd,
|
|
246
|
-
timeout: options?.timeoutMs,
|
|
247
|
-
maxBuffer: options?.maxBuffer,
|
|
248
|
-
encoding: "utf-8",
|
|
249
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
250
|
-
});
|
|
251
|
-
void finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout, stderr: "", startedAt }, options);
|
|
252
|
-
return { stdout: stdout ?? "", exitCode: 0 };
|
|
253
|
-
} catch (e) {
|
|
254
|
-
const err = e;
|
|
255
|
-
const stdout = typeof err.stdout === "string" ? err.stdout : "";
|
|
256
|
-
const stderr = typeof err.stderr === "string" ? err.stderr : "";
|
|
257
|
-
const exitCode = typeof err.status === "number" ? err.status : 1;
|
|
258
|
-
void finalizeAndWrite(
|
|
259
|
-
entry,
|
|
260
|
-
cmd,
|
|
261
|
-
{ success: false, exitCode, stdout, stderr, error: err.message, startedAt },
|
|
262
|
-
{ ...options, captureOutput: options?.captureOutput ?? true }
|
|
263
|
-
);
|
|
264
|
-
return { stdout, exitCode };
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
async function runExecFile(file, args, audit, options) {
|
|
268
|
-
const startedAt = Date.now();
|
|
269
|
-
const command = [file, ...args].join(" ");
|
|
270
|
-
const entry = createAuditEntry(audit.actor, audit.source ?? "trie", audit.triggeredBy, audit.targetPath);
|
|
271
|
-
const cmd = buildCommandRecord(command);
|
|
272
|
-
entry.commands?.push(cmd);
|
|
273
|
-
try {
|
|
274
|
-
const { stdout, stderr } = await execFileAsync(file, args, {
|
|
275
|
-
cwd: options?.cwd,
|
|
276
|
-
timeout: options?.timeoutMs,
|
|
277
|
-
maxBuffer: options?.maxBuffer
|
|
278
|
-
});
|
|
279
|
-
await finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), startedAt }, options);
|
|
280
|
-
return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), exitCode: 0 };
|
|
281
|
-
} catch (e) {
|
|
282
|
-
const err = e;
|
|
283
|
-
const stdout = typeof err.stdout === "string" ? err.stdout : "";
|
|
284
|
-
const stderr = typeof err.stderr === "string" ? err.stderr : "";
|
|
285
|
-
const exitCode = typeof err.code === "number" ? err.code : 1;
|
|
286
|
-
await finalizeAndWrite(
|
|
287
|
-
entry,
|
|
288
|
-
cmd,
|
|
289
|
-
{ success: false, exitCode, stdout, stderr, error: err.message, startedAt },
|
|
290
|
-
{ ...options, captureOutput: options?.captureOutput ?? true }
|
|
291
|
-
);
|
|
292
|
-
return { stdout, stderr, exitCode };
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// src/agent/git.ts
|
|
297
|
-
async function execGit(args, cwd) {
|
|
298
|
-
try {
|
|
299
|
-
const { stdout } = await runExecFile(
|
|
300
|
-
"git",
|
|
301
|
-
["-C", cwd, ...args],
|
|
302
|
-
{ actor: "internal:git", triggeredBy: "manual", targetPath: cwd },
|
|
303
|
-
{ maxBuffer: 10 * 1024 * 1024, captureOutput: false }
|
|
304
|
-
);
|
|
305
|
-
return stdout.trim();
|
|
306
|
-
} catch (error) {
|
|
307
|
-
const stderr = error?.stderr?.toString();
|
|
308
|
-
if (stderr?.includes("not a git repository") || stderr?.includes("does not have any commits")) {
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
throw error;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
async function ensureRepo(projectPath) {
|
|
315
|
-
const result = await execGit(["rev-parse", "--is-inside-work-tree"], projectPath);
|
|
316
|
-
return result === "true";
|
|
317
|
-
}
|
|
318
|
-
function parseNameStatus(output) {
|
|
319
|
-
return output.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
320
|
-
const parts = line.split(" ");
|
|
321
|
-
const status = parts[0] ?? "";
|
|
322
|
-
const filePath = parts[1] ?? "";
|
|
323
|
-
const oldPath = parts[2];
|
|
324
|
-
const change = { status, path: filePath };
|
|
325
|
-
if (oldPath) change.oldPath = oldPath;
|
|
326
|
-
return change;
|
|
327
|
-
}).filter((entry) => entry.path.length > 0);
|
|
328
|
-
}
|
|
329
|
-
async function getRecentCommits(projectPath, limit) {
|
|
330
|
-
const isRepo = await ensureRepo(projectPath);
|
|
331
|
-
if (!isRepo) return [];
|
|
332
|
-
const output = await execGit(
|
|
333
|
-
["log", `-n`, String(limit), "--pretty=format:%H%x09%an%x09%ad%x09%s", "--date=iso"],
|
|
334
|
-
projectPath
|
|
335
|
-
);
|
|
336
|
-
if (!output) return [];
|
|
337
|
-
return output.split("\n").map((line) => {
|
|
338
|
-
const [hash, author, date, message] = line.split(" ");
|
|
339
|
-
return { hash, author, date, message };
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
async function getLastCommit(projectPath) {
|
|
343
|
-
const commits = await getRecentCommits(projectPath, 1);
|
|
344
|
-
return commits[0] ?? null;
|
|
345
|
-
}
|
|
346
|
-
async function getStagedChanges(projectPath) {
|
|
347
|
-
const isRepo = await ensureRepo(projectPath);
|
|
348
|
-
if (!isRepo) return [];
|
|
349
|
-
const output = await execGit(["diff", "--cached", "--name-status"], projectPath);
|
|
350
|
-
if (!output) return [];
|
|
351
|
-
return parseNameStatus(output);
|
|
352
|
-
}
|
|
353
|
-
async function getUncommittedChanges(projectPath) {
|
|
354
|
-
const isRepo = await ensureRepo(projectPath);
|
|
355
|
-
if (!isRepo) return [];
|
|
356
|
-
const changes = [];
|
|
357
|
-
const unstaged = await execGit(["diff", "--name-status"], projectPath);
|
|
358
|
-
if (unstaged) {
|
|
359
|
-
changes.push(...parseNameStatus(unstaged));
|
|
360
|
-
}
|
|
361
|
-
const untracked = await execGit(["ls-files", "--others", "--exclude-standard"], projectPath);
|
|
362
|
-
if (untracked) {
|
|
363
|
-
changes.push(
|
|
364
|
-
...untracked.split("\n").map((p) => p.trim()).filter(Boolean).map((p) => ({ status: "??", path: p }))
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
return changes;
|
|
368
|
-
}
|
|
369
|
-
async function getGitChangedFiles(projectPath) {
|
|
370
|
-
const isRepo = await ensureRepo(projectPath);
|
|
371
|
-
if (!isRepo) return null;
|
|
372
|
-
const [staged, uncommitted] = await Promise.all([
|
|
373
|
-
getStagedChanges(projectPath).catch(() => []),
|
|
374
|
-
getUncommittedChanges(projectPath).catch(() => [])
|
|
375
|
-
]);
|
|
376
|
-
const paths = /* @__PURE__ */ new Set();
|
|
377
|
-
for (const change of [...staged, ...uncommitted]) {
|
|
378
|
-
if (change.path) paths.add(change.path);
|
|
379
|
-
if (change.oldPath) paths.add(change.oldPath);
|
|
380
|
-
}
|
|
381
|
-
return [...paths];
|
|
382
|
-
}
|
|
383
|
-
async function getDiff(projectPath, commitHash) {
|
|
384
|
-
const isRepo = await ensureRepo(projectPath);
|
|
385
|
-
if (!isRepo) return "";
|
|
386
|
-
const diff = await execGit(["show", commitHash, "--unified=3", "--no-color"], projectPath);
|
|
387
|
-
return diff ?? "";
|
|
388
|
-
}
|
|
389
|
-
async function getWorkingTreeDiff(projectPath, stagedOnly = false) {
|
|
390
|
-
const isRepo = await ensureRepo(projectPath);
|
|
391
|
-
if (!isRepo) return "";
|
|
392
|
-
const args = stagedOnly ? ["diff", "--cached", "--unified=3", "--no-color"] : ["diff", "--unified=3", "--no-color"];
|
|
393
|
-
const diff = await execGit(args, projectPath);
|
|
394
|
-
return diff ?? "";
|
|
395
|
-
}
|
|
396
|
-
async function isGitRepo(projectPath) {
|
|
397
|
-
const result = await execGit(["rev-parse", "--is-inside-work-tree"], projectPath);
|
|
398
|
-
return result === "true";
|
|
399
|
-
}
|
|
400
|
-
async function getChangedFilesSinceTimestamp(projectPath, timestamp) {
|
|
401
|
-
const isRepo = await isGitRepo(projectPath);
|
|
402
|
-
if (!isRepo) return null;
|
|
403
|
-
try {
|
|
404
|
-
const sinceDate = new Date(timestamp).toISOString();
|
|
405
|
-
const GIT_TIMEOUT_MS = 5e3;
|
|
406
|
-
const startTime = Date.now();
|
|
407
|
-
const committedChangesPromise = execGit(
|
|
408
|
-
["log", `--since=${sinceDate}`, "--name-only", "--pretty=format:"],
|
|
409
|
-
projectPath
|
|
410
|
-
);
|
|
411
|
-
const committedChangesTimeout = new Promise((resolve) => {
|
|
412
|
-
setTimeout(() => resolve(null), GIT_TIMEOUT_MS);
|
|
413
|
-
});
|
|
414
|
-
const committedChanges = await Promise.race([committedChangesPromise, committedChangesTimeout]);
|
|
415
|
-
if (Date.now() - startTime > GIT_TIMEOUT_MS) {
|
|
416
|
-
return null;
|
|
417
|
-
}
|
|
418
|
-
const stagedPromise = execGit(["diff", "--cached", "--name-only"], projectPath);
|
|
419
|
-
const unstagedPromise = execGit(["diff", "--name-only"], projectPath);
|
|
420
|
-
const untrackedPromise = execGit(
|
|
421
|
-
["ls-files", "--others", "--exclude-standard"],
|
|
422
|
-
projectPath
|
|
423
|
-
);
|
|
424
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
425
|
-
setTimeout(() => resolve(null), Math.max(0, GIT_TIMEOUT_MS - (Date.now() - startTime)));
|
|
426
|
-
});
|
|
427
|
-
const [stagedChanges, unstagedChanges, untrackedFiles] = await Promise.race([
|
|
428
|
-
Promise.all([stagedPromise, unstagedPromise, untrackedPromise]),
|
|
429
|
-
timeoutPromise.then(() => [null, null, null])
|
|
430
|
-
]);
|
|
431
|
-
const changedFiles = /* @__PURE__ */ new Set();
|
|
432
|
-
const addFiles = (output) => {
|
|
433
|
-
if (output) {
|
|
434
|
-
output.split("\n").map((f) => f.trim()).filter(Boolean).forEach((f) => changedFiles.add(path.join(projectPath, f)));
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
addFiles(committedChanges);
|
|
438
|
-
addFiles(stagedChanges);
|
|
439
|
-
addFiles(unstagedChanges);
|
|
440
|
-
addFiles(untrackedFiles);
|
|
441
|
-
return Array.from(changedFiles);
|
|
442
|
-
} catch {
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
150
|
// src/memory/crypto-keys.ts
|
|
448
151
|
import * as ed25519 from "@noble/ed25519";
|
|
449
152
|
import { randomBytes } from "crypto";
|
|
450
|
-
import { existsSync as
|
|
153
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
451
154
|
import { join } from "path";
|
|
452
155
|
function getKeysDirectory(workDir) {
|
|
453
156
|
const trieDir = getTrieDirectory(workDir || process.cwd());
|
|
@@ -466,7 +169,7 @@ async function generateKeyPair() {
|
|
|
466
169
|
}
|
|
467
170
|
function saveKeyPair(keyPair, workDir) {
|
|
468
171
|
const keysDir = getKeysDirectory(workDir);
|
|
469
|
-
if (!
|
|
172
|
+
if (!existsSync2(keysDir)) {
|
|
470
173
|
mkdirSync(keysDir, { recursive: true });
|
|
471
174
|
}
|
|
472
175
|
const keyPath = getDefaultKeyPath(workDir);
|
|
@@ -481,7 +184,7 @@ function saveKeyPair(keyPair, workDir) {
|
|
|
481
184
|
}
|
|
482
185
|
function loadKeyPair(workDir) {
|
|
483
186
|
const keyPath = getDefaultKeyPath(workDir);
|
|
484
|
-
if (!
|
|
187
|
+
if (!existsSync2(keyPath)) {
|
|
485
188
|
return null;
|
|
486
189
|
}
|
|
487
190
|
try {
|
|
@@ -544,23 +247,23 @@ function getPublicKey(workDir) {
|
|
|
544
247
|
}
|
|
545
248
|
function hasSigningKey(workDir) {
|
|
546
249
|
const keyPath = getDefaultKeyPath(workDir);
|
|
547
|
-
return
|
|
250
|
+
return existsSync2(keyPath);
|
|
548
251
|
}
|
|
549
252
|
|
|
550
253
|
// src/memory/git-integration.ts
|
|
551
|
-
import { exec
|
|
552
|
-
import { promisify
|
|
553
|
-
import { existsSync as
|
|
254
|
+
import { exec } from "child_process";
|
|
255
|
+
import { promisify } from "util";
|
|
256
|
+
import { existsSync as existsSync3 } from "fs";
|
|
554
257
|
import { join as join2 } from "path";
|
|
555
|
-
var
|
|
258
|
+
var execAsync = promisify(exec);
|
|
556
259
|
async function isGitIntegrationEnabled(workDir) {
|
|
557
260
|
try {
|
|
558
261
|
const gitDir = join2(workDir, ".git");
|
|
559
|
-
if (!
|
|
262
|
+
if (!existsSync3(gitDir)) {
|
|
560
263
|
return false;
|
|
561
264
|
}
|
|
562
265
|
const configPath = join2(getTrieDirectory(workDir), "config.json");
|
|
563
|
-
if (!
|
|
266
|
+
if (!existsSync3(configPath)) {
|
|
564
267
|
return true;
|
|
565
268
|
}
|
|
566
269
|
const config = JSON.parse(await import("fs/promises").then((fs) => fs.readFile(configPath, "utf-8")));
|
|
@@ -576,18 +279,18 @@ async function autoCommitLedger(workDir, message) {
|
|
|
576
279
|
return { committed: false, error: "Git integration disabled" };
|
|
577
280
|
}
|
|
578
281
|
const ledgerPath = join2(getTrieDirectory(workDir), "memory", "ledger.json");
|
|
579
|
-
const { stdout: statusOutput } = await
|
|
282
|
+
const { stdout: statusOutput } = await execAsync("git status --porcelain", { cwd: workDir });
|
|
580
283
|
const hasLedgerChanges = statusOutput.includes("ledger.json");
|
|
581
284
|
if (!hasLedgerChanges) {
|
|
582
285
|
return { committed: false, error: "No ledger changes to commit" };
|
|
583
286
|
}
|
|
584
|
-
await
|
|
287
|
+
await execAsync(`git add ${ledgerPath}`, { cwd: workDir });
|
|
585
288
|
const commitMessage = message || "ledger: append entries";
|
|
586
|
-
await
|
|
289
|
+
await execAsync(
|
|
587
290
|
`git commit -m "${commitMessage}"`,
|
|
588
291
|
{ cwd: workDir }
|
|
589
292
|
);
|
|
590
|
-
const { stdout: hashOutput } = await
|
|
293
|
+
const { stdout: hashOutput } = await execAsync("git rev-parse HEAD", { cwd: workDir });
|
|
591
294
|
const commitHash = hashOutput.trim();
|
|
592
295
|
return {
|
|
593
296
|
committed: true,
|
|
@@ -605,7 +308,7 @@ async function ensureKeysIgnored(workDir) {
|
|
|
605
308
|
const gitignorePath = join2(workDir, ".gitignore");
|
|
606
309
|
const fs = await import("fs/promises");
|
|
607
310
|
let gitignore = "";
|
|
608
|
-
if (
|
|
311
|
+
if (existsSync3(gitignorePath)) {
|
|
609
312
|
gitignore = await fs.readFile(gitignorePath, "utf-8");
|
|
610
313
|
}
|
|
611
314
|
if (gitignore.includes(".trie/keys/")) {
|
|
@@ -689,20 +392,73 @@ async function appendIssuesToLedger(issues, workDir, author) {
|
|
|
689
392
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
690
393
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
691
394
|
const shouldSign = hasSigningKey(projectDir);
|
|
692
|
-
let entries = issues.map((issue) =>
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
395
|
+
let entries = await Promise.all(issues.map(async (issue) => {
|
|
396
|
+
const context = {
|
|
397
|
+
detectionMethod: "automated-scan",
|
|
398
|
+
confidence: issue.confidence || 80,
|
|
399
|
+
ruleId: issue.agent,
|
|
400
|
+
exposureScope: "repository",
|
|
401
|
+
riskFactors: [],
|
|
402
|
+
escalatedTo: blockAuthor
|
|
403
|
+
};
|
|
404
|
+
if (issue.line !== void 0) {
|
|
405
|
+
context.line = issue.line;
|
|
406
|
+
}
|
|
407
|
+
if (lastCommit?.hash) {
|
|
408
|
+
context.gitCommit = lastCommit.hash;
|
|
409
|
+
}
|
|
410
|
+
if (lastCommit?.branch) {
|
|
411
|
+
context.gitBranch = lastCommit.branch;
|
|
412
|
+
}
|
|
413
|
+
if (issue.category === "security") {
|
|
414
|
+
context.complianceViolations = ["security-policy"];
|
|
415
|
+
context.requiresNotification = issue.severity === "critical";
|
|
416
|
+
}
|
|
417
|
+
if (issue.category === "pii" || issue.issue?.toLowerCase().includes("personal")) {
|
|
418
|
+
context.complianceViolations = ["GDPR", "privacy-policy"];
|
|
419
|
+
context.requiresNotification = true;
|
|
420
|
+
context.exposureScope = "public";
|
|
421
|
+
context.riskFactors.push("data-exposure", "privacy-violation");
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
const filePath = join3(projectDir, issue.file);
|
|
425
|
+
if (existsSync4(filePath)) {
|
|
426
|
+
const { readFile: readFile3, stat: stat3 } = await import("fs/promises");
|
|
427
|
+
const stats = await stat3(filePath);
|
|
428
|
+
context.fileSize = stats.size;
|
|
429
|
+
context.fileModified = stats.mtime.toISOString();
|
|
430
|
+
if (issue.line && issue.line > 0) {
|
|
431
|
+
const content = await readFile3(filePath, "utf-8");
|
|
432
|
+
const lines = content.split("\n");
|
|
433
|
+
const startLine = Math.max(0, issue.line - 3);
|
|
434
|
+
const endLine = Math.min(lines.length, issue.line + 2);
|
|
435
|
+
const snippet = lines.slice(startLine, endLine).join("\n");
|
|
436
|
+
context.codeSnippet = snippet.length > 500 ? snippet.slice(0, 500) + "..." : snippet;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
} catch (error) {
|
|
440
|
+
console.debug("Failed to collect file metadata:", error);
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
id: issue.id,
|
|
444
|
+
hash: issue.hash,
|
|
445
|
+
severity: issue.severity,
|
|
446
|
+
file: issue.file,
|
|
447
|
+
agent: issue.agent,
|
|
448
|
+
timestamp: issue.timestamp,
|
|
449
|
+
status: "active",
|
|
450
|
+
// Include semantic content for ambient awareness
|
|
451
|
+
issue: issue.issue,
|
|
452
|
+
fix: issue.fix,
|
|
453
|
+
// Enhanced forensic context
|
|
454
|
+
context
|
|
455
|
+
};
|
|
700
456
|
}));
|
|
701
457
|
if (shouldSign) {
|
|
702
458
|
entries = await Promise.all(entries.map((entry) => signLedgerEntry(entry, projectDir)));
|
|
703
459
|
}
|
|
704
460
|
const previousBlock = blocks[blocks.length - 1];
|
|
705
|
-
const block = previousBlock && previousBlock.date === today ? previousBlock : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, blockAuthor, lastCommit?.hash, blocks.length);
|
|
461
|
+
const block = previousBlock && previousBlock.date === today ? previousBlock : await createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, blockAuthor, projectDir, lastCommit?.hash, blocks.length);
|
|
706
462
|
if (block !== previousBlock) {
|
|
707
463
|
blocks.push(block);
|
|
708
464
|
}
|
|
@@ -774,7 +530,30 @@ function computeMerkleRoot(hashes) {
|
|
|
774
530
|
function computeBlockHash(previousHash, merkleRoot, date, version) {
|
|
775
531
|
return sha256(`${version}:${date}:${previousHash}:${merkleRoot}`);
|
|
776
532
|
}
|
|
777
|
-
function createSyncableBlock(date, now, previousHash, author, gitCommit, chainHeight = 0) {
|
|
533
|
+
async function createSyncableBlock(date, now, previousHash, author, projectDir, gitCommit, chainHeight = 0) {
|
|
534
|
+
const metadata = {};
|
|
535
|
+
try {
|
|
536
|
+
metadata.hostname = __require("os").hostname();
|
|
537
|
+
metadata.workingDirectory = projectDir;
|
|
538
|
+
metadata.scanId = `scan-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
539
|
+
metadata.toolVersion = process.env.npm_package_version || "unknown";
|
|
540
|
+
if (await isGitRepo(projectDir)) {
|
|
541
|
+
const { getLastCommit: getLastCommit2 } = await import("./git-EO5SRFMN.js");
|
|
542
|
+
const lastCommit = await getLastCommit2(projectDir);
|
|
543
|
+
if (lastCommit?.hash) {
|
|
544
|
+
metadata.gitHeadCommit = lastCommit.hash;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
metadata.summary = {
|
|
548
|
+
totalIssues: 0,
|
|
549
|
+
issuesBySeverity: {},
|
|
550
|
+
issuesByAgent: {},
|
|
551
|
+
newIssues: 0,
|
|
552
|
+
resolvedIssues: 0
|
|
553
|
+
};
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.debug("Failed to collect block metadata:", error);
|
|
556
|
+
}
|
|
778
557
|
return {
|
|
779
558
|
version: LEDGER_VERSION,
|
|
780
559
|
date,
|
|
@@ -786,6 +565,7 @@ function createSyncableBlock(date, now, previousHash, author, gitCommit, chainHe
|
|
|
786
565
|
updatedAt: now,
|
|
787
566
|
author,
|
|
788
567
|
chainHeight,
|
|
568
|
+
metadata,
|
|
789
569
|
...gitCommit && { gitCommit }
|
|
790
570
|
};
|
|
791
571
|
}
|
|
@@ -796,7 +576,7 @@ async function loadLedger(projectDir) {
|
|
|
796
576
|
async function loadLedgerWithHash(projectDir) {
|
|
797
577
|
const ledgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
|
|
798
578
|
try {
|
|
799
|
-
if (!
|
|
579
|
+
if (!existsSync4(ledgerPath)) {
|
|
800
580
|
return { blocks: [], contentHash: sha256("[]") };
|
|
801
581
|
}
|
|
802
582
|
const content = await readFile2(ledgerPath, "utf-8");
|
|
@@ -894,7 +674,7 @@ async function ensureSharedStorageStructure(projectDir) {
|
|
|
894
674
|
async function loadManifest(projectDir) {
|
|
895
675
|
const manifestPath = getManifestPath(projectDir);
|
|
896
676
|
try {
|
|
897
|
-
if (!
|
|
677
|
+
if (!existsSync4(manifestPath)) return null;
|
|
898
678
|
const content = await readFile2(manifestPath, "utf-8");
|
|
899
679
|
return JSON.parse(content);
|
|
900
680
|
} catch {
|
|
@@ -932,7 +712,7 @@ async function createDefaultManifest(_projectDir) {
|
|
|
932
712
|
async function loadSyncState(projectDir) {
|
|
933
713
|
const syncStatePath = getSyncStatePath(projectDir);
|
|
934
714
|
try {
|
|
935
|
-
if (!
|
|
715
|
+
if (!existsSync4(syncStatePath)) return null;
|
|
936
716
|
const content = await readFile2(syncStatePath, "utf-8");
|
|
937
717
|
return JSON.parse(content);
|
|
938
718
|
} catch {
|
|
@@ -1001,7 +781,7 @@ async function pushLedgerToShared(workDir) {
|
|
|
1001
781
|
for (const block of localBlocks) {
|
|
1002
782
|
const blockFilename = `${block.date}.json`;
|
|
1003
783
|
const blockPath = join3(activeDir, blockFilename);
|
|
1004
|
-
if (!
|
|
784
|
+
if (!existsSync4(blockPath) || block.updatedAt > manifest.lastSync) {
|
|
1005
785
|
await atomicWriteJSON(blockPath, block);
|
|
1006
786
|
manifest.index.byDate[block.date] = `active/${blockFilename}`;
|
|
1007
787
|
const blockAuthor = block.author;
|
|
@@ -1032,7 +812,7 @@ async function loadSharedBlocks(projectDir) {
|
|
|
1032
812
|
for (const filename of manifest.activeBlocks) {
|
|
1033
813
|
const blockPath = join3(activeDir, filename);
|
|
1034
814
|
try {
|
|
1035
|
-
if (
|
|
815
|
+
if (existsSync4(blockPath)) {
|
|
1036
816
|
const content = await readFile2(blockPath, "utf-8");
|
|
1037
817
|
const block = JSON.parse(content);
|
|
1038
818
|
blocks.push(block);
|
|
@@ -1060,8 +840,11 @@ async function mergeChains(localBlocks, remoteBlocks, strategy = "timestamp") {
|
|
|
1060
840
|
for (const block of remoteBlocks) {
|
|
1061
841
|
remoteByDate.set(block.date, block);
|
|
1062
842
|
}
|
|
1063
|
-
const allDates = /* @__PURE__ */ new Set([
|
|
1064
|
-
|
|
843
|
+
const allDates = /* @__PURE__ */ new Set([
|
|
844
|
+
...Array.from(localByDate.keys()),
|
|
845
|
+
...Array.from(remoteByDate.keys())
|
|
846
|
+
]);
|
|
847
|
+
for (const date of Array.from(allDates)) {
|
|
1065
848
|
const localBlock = localByDate.get(date);
|
|
1066
849
|
const remoteBlock = remoteByDate.get(date);
|
|
1067
850
|
if (localBlock && remoteBlock) {
|
|
@@ -1177,7 +960,7 @@ function mergeBlockEntries(localBlock, remoteBlock) {
|
|
|
1177
960
|
async function migrateLegacyLedger(workDir) {
|
|
1178
961
|
const projectDir = workDir || getWorkingDirectory(void 0, true);
|
|
1179
962
|
const legacyLedgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
|
|
1180
|
-
if (!
|
|
963
|
+
if (!existsSync4(legacyLedgerPath)) {
|
|
1181
964
|
return false;
|
|
1182
965
|
}
|
|
1183
966
|
try {
|
|
@@ -1212,7 +995,7 @@ async function migrateLegacyLedger(workDir) {
|
|
|
1212
995
|
async function detectLegacyLedger(workDir) {
|
|
1213
996
|
const projectDir = workDir || getWorkingDirectory(void 0, true);
|
|
1214
997
|
const legacyLedgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
|
|
1215
|
-
if (!
|
|
998
|
+
if (!existsSync4(legacyLedgerPath)) {
|
|
1216
999
|
return false;
|
|
1217
1000
|
}
|
|
1218
1001
|
try {
|
|
@@ -1263,9 +1046,9 @@ async function compressOldBlocks(workDir) {
|
|
|
1263
1046
|
blocksByMonth.get(monthKey).push(blockFile);
|
|
1264
1047
|
}
|
|
1265
1048
|
}
|
|
1266
|
-
for (const [monthKey, blockFiles] of blocksByMonth) {
|
|
1049
|
+
for (const [monthKey, blockFiles] of Array.from(blocksByMonth.entries())) {
|
|
1267
1050
|
const archivePath = join3(archivedDir, `${monthKey}.tar.gz`);
|
|
1268
|
-
if (
|
|
1051
|
+
if (existsSync4(archivePath)) {
|
|
1269
1052
|
continue;
|
|
1270
1053
|
}
|
|
1271
1054
|
console.log(`Archiving ${blockFiles.length} blocks for ${monthKey}...`);
|
|
@@ -1317,7 +1100,7 @@ async function compressOldBlocks(workDir) {
|
|
|
1317
1100
|
async function loadArchivedBlocks(projectDir, monthKey) {
|
|
1318
1101
|
const archivedDir = getArchivedBlocksDir(projectDir);
|
|
1319
1102
|
const archivePath = join3(archivedDir, `${monthKey}.tar.gz`);
|
|
1320
|
-
if (!
|
|
1103
|
+
if (!existsSync4(archivePath)) {
|
|
1321
1104
|
return [];
|
|
1322
1105
|
}
|
|
1323
1106
|
try {
|
|
@@ -1359,7 +1142,7 @@ async function getStorageStats(workDir) {
|
|
|
1359
1142
|
for (const blockFile of manifest.activeBlocks) {
|
|
1360
1143
|
const blockPath = join3(activeDir, blockFile);
|
|
1361
1144
|
try {
|
|
1362
|
-
if (
|
|
1145
|
+
if (existsSync4(blockPath)) {
|
|
1363
1146
|
const stats = await stat2(blockPath);
|
|
1364
1147
|
activeSize += stats.size;
|
|
1365
1148
|
}
|
|
@@ -1369,7 +1152,7 @@ async function getStorageStats(workDir) {
|
|
|
1369
1152
|
for (const archiveFile of manifest.archivedBlocks) {
|
|
1370
1153
|
const archivePath = join3(archivedDir, archiveFile);
|
|
1371
1154
|
try {
|
|
1372
|
-
if (
|
|
1155
|
+
if (existsSync4(archivePath)) {
|
|
1373
1156
|
const stats = await stat2(archivePath);
|
|
1374
1157
|
archivedSize += stats.size;
|
|
1375
1158
|
}
|
|
@@ -1503,7 +1286,7 @@ async function appendCorrectionEntries(correctionEntries, projectDir, author) {
|
|
|
1503
1286
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1504
1287
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1505
1288
|
const previousBlock = blocks[blocks.length - 1];
|
|
1506
|
-
const block = previousBlock && previousBlock.date === today ? previousBlock : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, author, void 0, blocks.length);
|
|
1289
|
+
const block = previousBlock && previousBlock.date === today ? previousBlock : await createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, author, projectDir, void 0, blocks.length);
|
|
1507
1290
|
if (block !== previousBlock) {
|
|
1508
1291
|
blocks.push(block);
|
|
1509
1292
|
}
|
|
@@ -1580,18 +1363,6 @@ async function getCorrectionStats(workDir) {
|
|
|
1580
1363
|
|
|
1581
1364
|
export {
|
|
1582
1365
|
withFileLock,
|
|
1583
|
-
formatAuditLog,
|
|
1584
|
-
getAuditStatistics,
|
|
1585
|
-
getRecentAuditLogs,
|
|
1586
|
-
runShellCommandSync,
|
|
1587
|
-
getRecentCommits,
|
|
1588
|
-
getStagedChanges,
|
|
1589
|
-
getUncommittedChanges,
|
|
1590
|
-
getGitChangedFiles,
|
|
1591
|
-
getDiff,
|
|
1592
|
-
getWorkingTreeDiff,
|
|
1593
|
-
isGitRepo,
|
|
1594
|
-
getChangedFilesSinceTimestamp,
|
|
1595
1366
|
generateKeyPair,
|
|
1596
1367
|
saveKeyPair,
|
|
1597
1368
|
loadKeyPair,
|
|
@@ -1622,4 +1393,4 @@ export {
|
|
|
1622
1393
|
getEntryCorrectionHistory,
|
|
1623
1394
|
getCorrectionStats
|
|
1624
1395
|
};
|
|
1625
|
-
//# sourceMappingURL=chunk-
|
|
1396
|
+
//# sourceMappingURL=chunk-ZJF5FTBX.js.map
|