@rel-time/mcp-server 1.2.12 → 1.2.14
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/index.js +335 -27
- package/package.json +1 -1
- package/server.json +2 -2
package/index.js
CHANGED
|
@@ -56,7 +56,7 @@ let LAST_INVOICE_PACK = null;
|
|
|
56
56
|
|
|
57
57
|
const SERVER_INFO = {
|
|
58
58
|
name: "rel-time-mcp-server",
|
|
59
|
-
version: "1.2.
|
|
59
|
+
version: "1.2.14",
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -341,6 +341,30 @@ function injectPngVerifyBuffer(pngBuffer, verifyUrl) {
|
|
|
341
341
|
]);
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Builds an OS-safe filename (<= 240 UTF-8 bytes) so macOS/Linux 255-byte limits
|
|
346
|
+
* (`ENAMETOOLONG`) never fail on long AI-prompt filenames.
|
|
347
|
+
*/
|
|
348
|
+
function safeArtifactFilename(prefix, rawName, ext, hashHex = "") {
|
|
349
|
+
const candidate = `${prefix}${rawName}${ext}`;
|
|
350
|
+
if (Buffer.byteLength(candidate, "utf8") <= 240) {
|
|
351
|
+
return candidate;
|
|
352
|
+
}
|
|
353
|
+
const suffixTag = hashHex
|
|
354
|
+
? `~${String(hashHex).slice(0, 8)}`
|
|
355
|
+
: `~${crypto.createHash("sha256").update(String(rawName), "utf8").digest("hex").slice(0, 8)}`;
|
|
356
|
+
const maxBodyBytes = Math.max(32, 240 - Buffer.byteLength(prefix, "utf8") - Buffer.byteLength(suffixTag, "utf8") - Buffer.byteLength(ext, "utf8"));
|
|
357
|
+
let trimmed = "";
|
|
358
|
+
let usedBytes = 0;
|
|
359
|
+
for (const ch of String(rawName)) {
|
|
360
|
+
const chBytes = Buffer.byteLength(ch, "utf8");
|
|
361
|
+
if (usedBytes + chBytes > maxBodyBytes) break;
|
|
362
|
+
trimmed += ch;
|
|
363
|
+
usedBytes += chBytes;
|
|
364
|
+
}
|
|
365
|
+
return `${prefix}${trimmed.trim()}${suffixTag}${ext}`;
|
|
366
|
+
}
|
|
367
|
+
|
|
344
368
|
/**
|
|
345
369
|
* Stamps the Option 1A (+14° Bitcoin Tilt, pure crisp 64-ray Sun-Stamp, 0% glare, no pill) onto a local Image or PDF.
|
|
346
370
|
* Returns { stamped: true, output_path, format } or { stamped: false, reason }.
|
|
@@ -375,7 +399,9 @@ async function stampLocalFileOptionA(filePath, svgContent, customOutputPath = nu
|
|
|
375
399
|
.replace(/<\/a>/gi, "");
|
|
376
400
|
|
|
377
401
|
if (isImage) {
|
|
378
|
-
const outPath = customOutputPath
|
|
402
|
+
const outPath = customOutputPath
|
|
403
|
+
? path.resolve(customOutputPath)
|
|
404
|
+
: path.join(dir, safeArtifactFilename("reltime-stamped-", baseName, ".png", verifyHash));
|
|
379
405
|
const img = sharp(filePath);
|
|
380
406
|
const meta = await img.metadata();
|
|
381
407
|
const w = (meta.autoOrient && meta.autoOrient.width) || meta.width || 1200;
|
|
@@ -410,7 +436,9 @@ async function stampLocalFileOptionA(filePath, svgContent, customOutputPath = nu
|
|
|
410
436
|
}
|
|
411
437
|
|
|
412
438
|
if (isPdf) {
|
|
413
|
-
const outPath = customOutputPath
|
|
439
|
+
const outPath = customOutputPath
|
|
440
|
+
? path.resolve(customOutputPath)
|
|
441
|
+
: path.join(dir, safeArtifactFilename("reltime-stamped-", baseName, ".pdf", verifyHash));
|
|
414
442
|
const pdfBytes = fs.readFileSync(filePath);
|
|
415
443
|
const pdfDoc = await PDFDocument.load(pdfBytes, { ignoreEncryption: true });
|
|
416
444
|
const pages = pdfDoc.getPages();
|
|
@@ -639,6 +667,15 @@ function generateAuditReportHtml(audit) {
|
|
|
639
667
|
}</span>
|
|
640
668
|
</div>
|
|
641
669
|
</div>
|
|
670
|
+
<div class="filter-bar no-print">
|
|
671
|
+
<div class="tab-group" id="localTabGroup">
|
|
672
|
+
<button class="filter-tab local-filter-tab active" onclick="setLocalPill(this, 'all')">All (${localCheck.summary.total_files_scanned})</button>
|
|
673
|
+
<button class="filter-tab local-filter-tab" onclick="setLocalPill(this, 'local-settled')">Settled (${localCheck.summary.verified_settled_count})</button>
|
|
674
|
+
<button class="filter-tab local-filter-tab" onclick="setLocalPill(this, 'local-pending')">Pending (${localCheck.summary.verified_pending_count})</button>
|
|
675
|
+
<button class="filter-tab local-filter-tab" onclick="setLocalPill(this, 'local-alert')">Unanchored / Modified (${localCheck.summary.unanchored_or_modified_count})</button>
|
|
676
|
+
</div>
|
|
677
|
+
<input id="localSearchInput" class="search-input" type="text" placeholder="QUERY FILE NAME / SHA-256 / PASSKEY / BLOCK..." oninput="resetAndFilterLocal()" />
|
|
678
|
+
</div>
|
|
642
679
|
<div class="table-wrap">
|
|
643
680
|
<table>
|
|
644
681
|
<thead>
|
|
@@ -653,9 +690,16 @@ function generateAuditReportHtml(audit) {
|
|
|
653
690
|
<th style="text-align:right">Receipt</th>
|
|
654
691
|
</tr>
|
|
655
692
|
</thead>
|
|
656
|
-
<tbody>
|
|
693
|
+
<tbody id="localVerifyBody">
|
|
657
694
|
${localCheck.files
|
|
658
695
|
.map((f, idx) => {
|
|
696
|
+
const localRowClass =
|
|
697
|
+
f.integrity_status === "VERIFIED_SETTLED"
|
|
698
|
+
? "local-settled"
|
|
699
|
+
: f.integrity_status === "VERIFIED_PENDING"
|
|
700
|
+
? "local-pending"
|
|
701
|
+
: "local-alert";
|
|
702
|
+
|
|
659
703
|
const statusTag =
|
|
660
704
|
f.integrity_status === "VERIFIED_SETTLED"
|
|
661
705
|
? `<span class="status-cell"><span class="dot dot-settled"></span><span class="mono" style="color:var(--text)">VERIFIED · SETTLED</span></span>`
|
|
@@ -682,7 +726,9 @@ function generateAuditReportHtml(audit) {
|
|
|
682
726
|
: `<span class="mono muted">—</span>`;
|
|
683
727
|
|
|
684
728
|
return `
|
|
685
|
-
<tr
|
|
729
|
+
<tr class="local-row ${localRowClass}" data-search="${escapeHtml(
|
|
730
|
+
`${f.file_name} ${f.local_sha256} ${f.signer_public_key || ""} ${f.block_height || ""} ${f.anchor_mode || ""}`.toLowerCase()
|
|
731
|
+
)}">
|
|
686
732
|
<td class="mono muted">${String(idx + 1).padStart(2, "0")}</td>
|
|
687
733
|
<td>
|
|
688
734
|
<span style="font-weight:600;color:var(--text)">${escapeHtml(f.file_name)}</span>
|
|
@@ -702,6 +748,26 @@ function generateAuditReportHtml(audit) {
|
|
|
702
748
|
</tbody>
|
|
703
749
|
</table>
|
|
704
750
|
</div>
|
|
751
|
+
<div class="pagination-bar no-print" id="localPaginationBar">
|
|
752
|
+
<div class="pagination-info mono">
|
|
753
|
+
<span id="localRangeLabel">SHOWING 1–25</span>
|
|
754
|
+
<span class="muted">·</span>
|
|
755
|
+
<label class="mono muted" for="localPageSizeSelect">ROWS:</label>
|
|
756
|
+
<select id="localPageSizeSelect" class="page-size-select mono" onchange="changeLocalPageSize(this.value)">
|
|
757
|
+
<option value="25" selected>25 / PAGE</option>
|
|
758
|
+
<option value="50">50 / PAGE</option>
|
|
759
|
+
<option value="100">100 / PAGE</option>
|
|
760
|
+
<option value="0">ALL (FULL LIST)</option>
|
|
761
|
+
</select>
|
|
762
|
+
</div>
|
|
763
|
+
<div class="pagination-controls">
|
|
764
|
+
<button type="button" class="page-btn mono" id="localFirstBtn" onclick="goLocalPage(1)">[ ⟪ FIRST ]</button>
|
|
765
|
+
<button type="button" class="page-btn mono" id="localPrevBtn" onclick="stepLocalPage(-1)">[ ‹ PREV ]</button>
|
|
766
|
+
<span class="page-indicator mono" id="localPageIndicator">PAGE 1 OF 1</span>
|
|
767
|
+
<button type="button" class="page-btn mono" id="localNextBtn" onclick="stepLocalPage(1)">[ NEXT › ]</button>
|
|
768
|
+
<button type="button" class="page-btn mono" id="localLastBtn" onclick="goLocalLastPage()">[ LAST ⟫ ]</button>
|
|
769
|
+
</div>
|
|
770
|
+
</div>
|
|
705
771
|
</section>`
|
|
706
772
|
: "";
|
|
707
773
|
|
|
@@ -1294,9 +1360,68 @@ function generateAuditReportHtml(audit) {
|
|
|
1294
1360
|
font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
|
|
1295
1361
|
font-size: 11.5px;
|
|
1296
1362
|
}
|
|
1363
|
+
.pagination-bar {
|
|
1364
|
+
display: flex;
|
|
1365
|
+
justify-content: space-between;
|
|
1366
|
+
align-items: center;
|
|
1367
|
+
flex-wrap: wrap;
|
|
1368
|
+
gap: 12px;
|
|
1369
|
+
margin-top: 14px;
|
|
1370
|
+
padding-top: 12px;
|
|
1371
|
+
border-top: 1px solid var(--border);
|
|
1372
|
+
}
|
|
1373
|
+
.pagination-info {
|
|
1374
|
+
display: flex;
|
|
1375
|
+
align-items: center;
|
|
1376
|
+
gap: 8px;
|
|
1377
|
+
font-size: 11px;
|
|
1378
|
+
color: var(--text-secondary);
|
|
1379
|
+
}
|
|
1380
|
+
.page-size-select {
|
|
1381
|
+
background: var(--bg);
|
|
1382
|
+
color: var(--text);
|
|
1383
|
+
border: 1px solid var(--border-strong);
|
|
1384
|
+
padding: 4px 8px;
|
|
1385
|
+
font-size: 10.5px;
|
|
1386
|
+
cursor: pointer;
|
|
1387
|
+
}
|
|
1388
|
+
.pagination-controls {
|
|
1389
|
+
display: flex;
|
|
1390
|
+
align-items: center;
|
|
1391
|
+
gap: 6px;
|
|
1392
|
+
}
|
|
1393
|
+
.page-btn {
|
|
1394
|
+
background: var(--bg);
|
|
1395
|
+
color: var(--text-secondary);
|
|
1396
|
+
border: 1px solid var(--border-strong);
|
|
1397
|
+
padding: 5px 10px;
|
|
1398
|
+
font-size: 10.5px;
|
|
1399
|
+
font-weight: 600;
|
|
1400
|
+
cursor: pointer;
|
|
1401
|
+
transition: all 0.12s ease;
|
|
1402
|
+
}
|
|
1403
|
+
.page-btn:hover:not(:disabled) {
|
|
1404
|
+
border-color: var(--amber);
|
|
1405
|
+
color: var(--amber);
|
|
1406
|
+
}
|
|
1407
|
+
.page-btn:disabled {
|
|
1408
|
+
opacity: 0.35;
|
|
1409
|
+
cursor: not-allowed;
|
|
1410
|
+
}
|
|
1411
|
+
.page-indicator {
|
|
1412
|
+
font-size: 11px;
|
|
1413
|
+
font-weight: 600;
|
|
1414
|
+
color: var(--text);
|
|
1415
|
+
padding: 0 8px;
|
|
1416
|
+
}
|
|
1417
|
+
tr.filter-hidden,
|
|
1418
|
+
tr.page-hidden {
|
|
1419
|
+
display: none;
|
|
1420
|
+
}
|
|
1297
1421
|
@media print {
|
|
1298
1422
|
body { background: var(--bg) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; padding: 10px; }
|
|
1299
1423
|
.no-print { display: none !important; }
|
|
1424
|
+
tr.page-hidden { display: table-row !important; }
|
|
1300
1425
|
}
|
|
1301
1426
|
</style>
|
|
1302
1427
|
</head>
|
|
@@ -1452,15 +1577,15 @@ function generateAuditReportHtml(audit) {
|
|
|
1452
1577
|
</div>
|
|
1453
1578
|
</div>
|
|
1454
1579
|
<div class="filter-bar no-print">
|
|
1455
|
-
<div class="tab-group">
|
|
1456
|
-
<button class="filter-tab active" onclick="setPill(this, 'all')">All (${entries.length})</button>
|
|
1457
|
-
<button class="filter-tab" onclick="setPill(this, 'status-settled')">Settled (${settledCount})</button>
|
|
1458
|
-
<button class="filter-tab" onclick="setPill(this, 'status-pending')">Pending (${pendingCount})</button>
|
|
1459
|
-
<button class="filter-tab" onclick="setPill(this, 'mode-biometric')">Passkey (${biometricCount})</button>
|
|
1460
|
-
<button class="filter-tab" onclick="setPill(this, 'mode-temporal')">Temporal VDF (${temporalCount})</button>
|
|
1461
|
-
<button class="filter-tab" onclick="setPill(this, 'mode-standard')">Standard (${standardCount})</button>
|
|
1580
|
+
<div class="tab-group" id="ledgerTabGroup">
|
|
1581
|
+
<button class="filter-tab ledger-filter-tab active" onclick="setPill(this, 'all')">All (${entries.length})</button>
|
|
1582
|
+
<button class="filter-tab ledger-filter-tab" onclick="setPill(this, 'status-settled')">Settled (${settledCount})</button>
|
|
1583
|
+
<button class="filter-tab ledger-filter-tab" onclick="setPill(this, 'status-pending')">Pending (${pendingCount})</button>
|
|
1584
|
+
<button class="filter-tab ledger-filter-tab" onclick="setPill(this, 'mode-biometric')">Passkey (${biometricCount})</button>
|
|
1585
|
+
<button class="filter-tab ledger-filter-tab" onclick="setPill(this, 'mode-temporal')">Temporal VDF (${temporalCount})</button>
|
|
1586
|
+
<button class="filter-tab ledger-filter-tab" onclick="setPill(this, 'mode-standard')">Standard (${standardCount})</button>
|
|
1462
1587
|
</div>
|
|
1463
|
-
<input id="searchInput" class="search-input" type="text" placeholder="QUERY SHA-256 / T_INDEX / PASSKEY / TXID / BLOCK..." oninput="
|
|
1588
|
+
<input id="searchInput" class="search-input" type="text" placeholder="QUERY SHA-256 / T_INDEX / PASSKEY / TXID / BLOCK..." oninput="resetAndFilterLedger()" />
|
|
1464
1589
|
</div>
|
|
1465
1590
|
<div class="table-wrap">
|
|
1466
1591
|
<table>
|
|
@@ -1481,11 +1606,40 @@ function generateAuditReportHtml(audit) {
|
|
|
1481
1606
|
</tbody>
|
|
1482
1607
|
</table>
|
|
1483
1608
|
</div>
|
|
1609
|
+
<div class="pagination-bar no-print" id="ledgerPaginationBar">
|
|
1610
|
+
<div class="pagination-info mono">
|
|
1611
|
+
<span id="ledgerRangeLabel">SHOWING 1–25</span>
|
|
1612
|
+
<span class="muted">·</span>
|
|
1613
|
+
<label class="mono muted" for="ledgerPageSizeSelect">ROWS:</label>
|
|
1614
|
+
<select id="ledgerPageSizeSelect" class="page-size-select mono" onchange="changeLedgerPageSize(this.value)">
|
|
1615
|
+
<option value="25" selected>25 / PAGE</option>
|
|
1616
|
+
<option value="50">50 / PAGE</option>
|
|
1617
|
+
<option value="100">100 / PAGE</option>
|
|
1618
|
+
<option value="0">ALL (FULL LIST)</option>
|
|
1619
|
+
</select>
|
|
1620
|
+
</div>
|
|
1621
|
+
<div class="pagination-controls">
|
|
1622
|
+
<button type="button" class="page-btn mono" id="ledgerFirstBtn" onclick="goLedgerPage(1)">[ ⟪ FIRST ]</button>
|
|
1623
|
+
<button type="button" class="page-btn mono" id="ledgerPrevBtn" onclick="stepLedgerPage(-1)">[ ‹ PREV ]</button>
|
|
1624
|
+
<span class="page-indicator mono" id="ledgerPageIndicator">PAGE 1 OF 1</span>
|
|
1625
|
+
<button type="button" class="page-btn mono" id="ledgerNextBtn" onclick="stepLedgerPage(1)">[ NEXT › ]</button>
|
|
1626
|
+
<button type="button" class="page-btn mono" id="ledgerLastBtn" onclick="goLedgerLastPage()">[ LAST ⟫ ]</button>
|
|
1627
|
+
</div>
|
|
1628
|
+
</div>
|
|
1484
1629
|
</section>
|
|
1485
1630
|
</div>
|
|
1486
1631
|
|
|
1487
1632
|
<script>
|
|
1488
1633
|
let currentFilter = 'all';
|
|
1634
|
+
let ledgerPage = 1;
|
|
1635
|
+
let ledgerPageSize = 25;
|
|
1636
|
+
let ledgerTotalPages = 1;
|
|
1637
|
+
|
|
1638
|
+
let currentLocalFilter = 'all';
|
|
1639
|
+
let localPage = 1;
|
|
1640
|
+
let localPageSize = 25;
|
|
1641
|
+
let localTotalPages = 1;
|
|
1642
|
+
|
|
1489
1643
|
function applyTheme(theme) {
|
|
1490
1644
|
const root = document.documentElement;
|
|
1491
1645
|
const btn = document.getElementById('themeToggleBtn');
|
|
@@ -1508,20 +1662,158 @@ function generateAuditReportHtml(audit) {
|
|
|
1508
1662
|
if (saved === 'light' || saved === 'dark') applyTheme(saved);
|
|
1509
1663
|
} catch (e) {}
|
|
1510
1664
|
})();
|
|
1665
|
+
|
|
1666
|
+
// Section 01: Local Directory Cross-Reference Pagination & Filtering
|
|
1667
|
+
function setLocalPill(btn, filter) {
|
|
1668
|
+
currentLocalFilter = filter;
|
|
1669
|
+
document.querySelectorAll('.local-filter-tab').forEach(el => el.classList.remove('active'));
|
|
1670
|
+
btn.classList.add('active');
|
|
1671
|
+
localPage = 1;
|
|
1672
|
+
filterLocalTable();
|
|
1673
|
+
}
|
|
1674
|
+
function resetAndFilterLocal() {
|
|
1675
|
+
localPage = 1;
|
|
1676
|
+
filterLocalTable();
|
|
1677
|
+
}
|
|
1678
|
+
function changeLocalPageSize(val) {
|
|
1679
|
+
localPageSize = Number(val) || 0;
|
|
1680
|
+
localPage = 1;
|
|
1681
|
+
filterLocalTable();
|
|
1682
|
+
}
|
|
1683
|
+
function goLocalPage(p) {
|
|
1684
|
+
localPage = Math.max(1, Math.min(localTotalPages, p));
|
|
1685
|
+
filterLocalTable();
|
|
1686
|
+
}
|
|
1687
|
+
function stepLocalPage(delta) {
|
|
1688
|
+
goLocalPage(localPage + delta);
|
|
1689
|
+
}
|
|
1690
|
+
function goLocalLastPage() {
|
|
1691
|
+
goLocalPage(localTotalPages);
|
|
1692
|
+
}
|
|
1693
|
+
function filterLocalTable() {
|
|
1694
|
+
const rows = Array.from(document.querySelectorAll('.local-row'));
|
|
1695
|
+
if (!rows.length) return;
|
|
1696
|
+
const qEl = document.getElementById('localSearchInput');
|
|
1697
|
+
const q = (qEl ? qEl.value : '').trim().toLowerCase();
|
|
1698
|
+
const matched = [];
|
|
1699
|
+
rows.forEach(row => {
|
|
1700
|
+
const matchesFilter = currentLocalFilter === 'all' || row.classList.contains(currentLocalFilter);
|
|
1701
|
+
const matchesQuery = !q || (row.getAttribute('data-search') || '').includes(q);
|
|
1702
|
+
if (matchesFilter && matchesQuery) {
|
|
1703
|
+
row.classList.remove('filter-hidden');
|
|
1704
|
+
matched.push(row);
|
|
1705
|
+
} else {
|
|
1706
|
+
row.classList.add('filter-hidden');
|
|
1707
|
+
row.classList.remove('page-hidden');
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
|
|
1711
|
+
const total = matched.length;
|
|
1712
|
+
localTotalPages = localPageSize > 0 ? Math.max(1, Math.ceil(total / localPageSize)) : 1;
|
|
1713
|
+
if (localPage > localTotalPages) localPage = localTotalPages;
|
|
1714
|
+
const startIdx = localPageSize > 0 ? (localPage - 1) * localPageSize : 0;
|
|
1715
|
+
const endIdx = localPageSize > 0 ? Math.min(total, startIdx + localPageSize) : total;
|
|
1716
|
+
|
|
1717
|
+
matched.forEach((row, idx) => {
|
|
1718
|
+
if (localPageSize > 0 && (idx < startIdx || idx >= endIdx)) {
|
|
1719
|
+
row.classList.add('page-hidden');
|
|
1720
|
+
} else {
|
|
1721
|
+
row.classList.remove('page-hidden');
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
const rangeEl = document.getElementById('localRangeLabel');
|
|
1726
|
+
if (rangeEl) {
|
|
1727
|
+
rangeEl.textContent = total === 0 ? 'SHOWING 0 OF 0 FILES' : 'SHOWING ' + (startIdx + 1) + '–' + endIdx + ' OF ' + total.toLocaleString() + ' FILES';
|
|
1728
|
+
}
|
|
1729
|
+
const indEl = document.getElementById('localPageIndicator');
|
|
1730
|
+
if (indEl) indEl.textContent = 'PAGE ' + localPage + ' OF ' + localTotalPages;
|
|
1731
|
+
const firstBtn = document.getElementById('localFirstBtn');
|
|
1732
|
+
const prevBtn = document.getElementById('localPrevBtn');
|
|
1733
|
+
const nextBtn = document.getElementById('localNextBtn');
|
|
1734
|
+
const lastBtn = document.getElementById('localLastBtn');
|
|
1735
|
+
if (firstBtn) firstBtn.disabled = localPage <= 1;
|
|
1736
|
+
if (prevBtn) prevBtn.disabled = localPage <= 1;
|
|
1737
|
+
if (nextBtn) nextBtn.disabled = localPage >= localTotalPages;
|
|
1738
|
+
if (lastBtn) lastBtn.disabled = localPage >= localTotalPages;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
// Section 03: Chronological Timechain Ledger Pagination & Filtering
|
|
1511
1742
|
function setPill(btn, filter) {
|
|
1512
1743
|
currentFilter = filter;
|
|
1513
|
-
document.querySelectorAll('.filter-tab').forEach(el => el.classList.remove('active'));
|
|
1744
|
+
document.querySelectorAll('.ledger-filter-tab').forEach(el => el.classList.remove('active'));
|
|
1514
1745
|
btn.classList.add('active');
|
|
1746
|
+
ledgerPage = 1;
|
|
1747
|
+
filterLedger();
|
|
1748
|
+
}
|
|
1749
|
+
function resetAndFilterLedger() {
|
|
1750
|
+
ledgerPage = 1;
|
|
1751
|
+
filterLedger();
|
|
1752
|
+
}
|
|
1753
|
+
function changeLedgerPageSize(val) {
|
|
1754
|
+
ledgerPageSize = Number(val) || 0;
|
|
1755
|
+
ledgerPage = 1;
|
|
1515
1756
|
filterLedger();
|
|
1516
1757
|
}
|
|
1758
|
+
function goLedgerPage(p) {
|
|
1759
|
+
ledgerPage = Math.max(1, Math.min(ledgerTotalPages, p));
|
|
1760
|
+
filterLedger();
|
|
1761
|
+
}
|
|
1762
|
+
function stepLedgerPage(delta) {
|
|
1763
|
+
goLedgerPage(ledgerPage + delta);
|
|
1764
|
+
}
|
|
1765
|
+
function goLedgerLastPage() {
|
|
1766
|
+
goLedgerPage(ledgerTotalPages);
|
|
1767
|
+
}
|
|
1517
1768
|
function filterLedger() {
|
|
1518
|
-
const
|
|
1519
|
-
document.
|
|
1769
|
+
const rows = Array.from(document.querySelectorAll('.ledger-row'));
|
|
1770
|
+
const qEl = document.getElementById('searchInput');
|
|
1771
|
+
const q = (qEl ? qEl.value : '').trim().toLowerCase();
|
|
1772
|
+
const matched = [];
|
|
1773
|
+
rows.forEach(row => {
|
|
1520
1774
|
const matchesFilter = currentFilter === 'all' || row.classList.contains(currentFilter);
|
|
1521
1775
|
const matchesQuery = !q || (row.getAttribute('data-search') || '').includes(q);
|
|
1522
|
-
|
|
1776
|
+
if (matchesFilter && matchesQuery) {
|
|
1777
|
+
row.classList.remove('filter-hidden');
|
|
1778
|
+
matched.push(row);
|
|
1779
|
+
} else {
|
|
1780
|
+
row.classList.add('filter-hidden');
|
|
1781
|
+
row.classList.remove('page-hidden');
|
|
1782
|
+
}
|
|
1523
1783
|
});
|
|
1524
|
-
|
|
1784
|
+
|
|
1785
|
+
const total = matched.length;
|
|
1786
|
+
ledgerTotalPages = ledgerPageSize > 0 ? Math.max(1, Math.ceil(total / ledgerPageSize)) : 1;
|
|
1787
|
+
if (ledgerPage > ledgerTotalPages) ledgerPage = ledgerTotalPages;
|
|
1788
|
+
const startIdx = ledgerPageSize > 0 ? (ledgerPage - 1) * ledgerPageSize : 0;
|
|
1789
|
+
const endIdx = ledgerPageSize > 0 ? Math.min(total, startIdx + ledgerPageSize) : total;
|
|
1790
|
+
|
|
1791
|
+
matched.forEach((row, idx) => {
|
|
1792
|
+
if (ledgerPageSize > 0 && (idx < startIdx || idx >= endIdx)) {
|
|
1793
|
+
row.classList.add('page-hidden');
|
|
1794
|
+
} else {
|
|
1795
|
+
row.classList.remove('page-hidden');
|
|
1796
|
+
}
|
|
1797
|
+
});
|
|
1798
|
+
|
|
1799
|
+
const rangeEl = document.getElementById('ledgerRangeLabel');
|
|
1800
|
+
if (rangeEl) {
|
|
1801
|
+
rangeEl.textContent = total === 0 ? 'SHOWING 0 OF 0 RECORDS' : 'SHOWING ' + (startIdx + 1) + '–' + endIdx + ' OF ' + total.toLocaleString() + ' RECORDS';
|
|
1802
|
+
}
|
|
1803
|
+
const indEl = document.getElementById('ledgerPageIndicator');
|
|
1804
|
+
if (indEl) indEl.textContent = 'PAGE ' + ledgerPage + ' OF ' + ledgerTotalPages;
|
|
1805
|
+
const firstBtn = document.getElementById('ledgerFirstBtn');
|
|
1806
|
+
const prevBtn = document.getElementById('ledgerPrevBtn');
|
|
1807
|
+
const nextBtn = document.getElementById('ledgerNextBtn');
|
|
1808
|
+
const lastBtn = document.getElementById('ledgerLastBtn');
|
|
1809
|
+
if (firstBtn) firstBtn.disabled = ledgerPage <= 1;
|
|
1810
|
+
if (prevBtn) prevBtn.disabled = ledgerPage <= 1;
|
|
1811
|
+
if (nextBtn) nextBtn.disabled = ledgerPage >= ledgerTotalPages;
|
|
1812
|
+
if (lastBtn) lastBtn.disabled = ledgerPage >= ledgerTotalPages;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
filterLocalTable();
|
|
1816
|
+
filterLedger();
|
|
1525
1817
|
</script>
|
|
1526
1818
|
</body>
|
|
1527
1819
|
</html>`;
|
|
@@ -2521,7 +2813,10 @@ async function executeTool(name, args = {}) {
|
|
|
2521
2813
|
let savedSvgPath = null;
|
|
2522
2814
|
if (args.save_sun_stamp_svg !== false && svgContent) {
|
|
2523
2815
|
try {
|
|
2524
|
-
savedSvgPath = path.join(
|
|
2816
|
+
savedSvgPath = path.join(
|
|
2817
|
+
path.dirname(filePath),
|
|
2818
|
+
safeArtifactFilename("reltime-stamp-", path.basename(filePath), ".svg", clientHash)
|
|
2819
|
+
);
|
|
2525
2820
|
fs.writeFileSync(savedSvgPath, svgContent, "utf8");
|
|
2526
2821
|
} catch (e) {
|
|
2527
2822
|
savedSvgPath = null;
|
|
@@ -2531,7 +2826,7 @@ async function executeTool(name, args = {}) {
|
|
|
2531
2826
|
// Save initial Doomsday Proof JSON alongside the file
|
|
2532
2827
|
const savedProofJsonPath = path.join(
|
|
2533
2828
|
path.dirname(filePath),
|
|
2534
|
-
|
|
2829
|
+
safeArtifactFilename("reltime-doomsday-proof-", path.basename(filePath), ".json", clientHash)
|
|
2535
2830
|
);
|
|
2536
2831
|
fs.writeFileSync(
|
|
2537
2832
|
savedProofJsonPath,
|
|
@@ -2593,7 +2888,7 @@ async function executeTool(name, args = {}) {
|
|
|
2593
2888
|
});
|
|
2594
2889
|
savedCertificateHtmlPath = path.join(
|
|
2595
2890
|
path.dirname(filePath),
|
|
2596
|
-
|
|
2891
|
+
safeArtifactFilename("reltime-certificate-", path.basename(filePath), ".html", clientHash)
|
|
2597
2892
|
);
|
|
2598
2893
|
fs.writeFileSync(savedCertificateHtmlPath, certHtml, "utf8");
|
|
2599
2894
|
if (args.open_certificate_in_browser) {
|
|
@@ -2705,12 +3000,24 @@ async function executeTool(name, args = {}) {
|
|
|
2705
3000
|
for (const fPath of targetFiles) {
|
|
2706
3001
|
const relPath = path.relative(folderPath, fPath);
|
|
2707
3002
|
const baseName = path.basename(fPath);
|
|
2708
|
-
const sidecarProof = path.join(
|
|
2709
|
-
|
|
2710
|
-
|
|
3003
|
+
const sidecarProof = path.join(
|
|
3004
|
+
path.dirname(fPath),
|
|
3005
|
+
safeArtifactFilename("reltime-doomsday-proof-", baseName, ".json")
|
|
3006
|
+
);
|
|
3007
|
+
const legacySidecarProof = path.join(path.dirname(fPath), `reltime-doomsday-proof-${baseName}.json`);
|
|
3008
|
+
const subfolderProof = path.join(
|
|
3009
|
+
proofsDir,
|
|
3010
|
+
safeArtifactFilename("reltime-doomsday-proof-", relPath.replace(/[\\/]/g, "__"), ".json")
|
|
3011
|
+
);
|
|
3012
|
+
if (
|
|
3013
|
+
existingManifest.anchored_files[relPath] ||
|
|
3014
|
+
fs.existsSync(sidecarProof) ||
|
|
3015
|
+
(Buffer.byteLength(`reltime-doomsday-proof-${baseName}.json`, "utf8") <= 255 && fs.existsSync(legacySidecarProof)) ||
|
|
3016
|
+
fs.existsSync(subfolderProof)
|
|
3017
|
+
) {
|
|
2711
3018
|
skipped.push(relPath);
|
|
2712
3019
|
} else {
|
|
2713
|
-
toProcess.push({ fPath, relPath, baseName, subfolderProof });
|
|
3020
|
+
toProcess.push({ fPath, relPath, baseName, subfolderProof, sidecarProof });
|
|
2714
3021
|
}
|
|
2715
3022
|
}
|
|
2716
3023
|
|
|
@@ -2779,8 +3086,7 @@ async function executeTool(name, args = {}) {
|
|
|
2779
3086
|
if (artifactMode === "proofs_subfolder") {
|
|
2780
3087
|
fs.writeFileSync(item.subfolderProof, JSON.stringify(proofRecord, null, 2), "utf8");
|
|
2781
3088
|
} else if (artifactMode === "full") {
|
|
2782
|
-
|
|
2783
|
-
fs.writeFileSync(sidecarPath, JSON.stringify(proofRecord, null, 2), "utf8");
|
|
3089
|
+
fs.writeFileSync(item.sidecarProof, JSON.stringify(proofRecord, null, 2), "utf8");
|
|
2784
3090
|
}
|
|
2785
3091
|
|
|
2786
3092
|
existingManifest.anchored_files[item.relPath] = proofRecord;
|
|
@@ -3232,10 +3538,12 @@ async function executeTool(name, args = {}) {
|
|
|
3232
3538
|
if (item.startsWith(".")) continue;
|
|
3233
3539
|
if (
|
|
3234
3540
|
item.startsWith("reltime-stamp-") ||
|
|
3541
|
+
item.startsWith("reltime-stamped-") ||
|
|
3235
3542
|
item.startsWith("reltime-doomsday-proof-") ||
|
|
3236
3543
|
item.startsWith("reltime-proof-") ||
|
|
3237
3544
|
item.startsWith("reltime-certificate-") ||
|
|
3238
3545
|
item.startsWith("reltime-audit-report-") ||
|
|
3546
|
+
item.startsWith("reltime-audit-trail-") ||
|
|
3239
3547
|
item === "reltime-batch-manifest.json" ||
|
|
3240
3548
|
item === "_reltime_proofs"
|
|
3241
3549
|
) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rel-time/mcp-server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.14",
|
|
4
4
|
"mcpName": "io.github.relsun369-dev/rel-time",
|
|
5
5
|
"description": "Official Model Context Protocol (MCP) server for Rel-Time (rel-time.com) — Zero-Knowledge Bitcoin & VDF Provenance, Local File Hashing, and Sun-Stamp Generation for Claude, Cursor, Windsurf, and Antigravity.",
|
|
6
6
|
"main": "index.js",
|
package/server.json
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"url": "https://github.com/relsun369-dev/reltime-mcp",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "1.2.
|
|
11
|
+
"version": "1.2.14",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
16
16
|
"identifier": "@rel-time/mcp-server",
|
|
17
|
-
"version": "1.2.
|
|
17
|
+
"version": "1.2.14",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
}
|