opencode-swarm-plugin 0.42.9 → 0.43.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/.hive/issues.jsonl +14 -0
- package/.turbo/turbo-build.log +2 -2
- package/CHANGELOG.md +79 -0
- package/README.md +296 -6
- package/bin/swarm.test.ts +615 -0
- package/bin/swarm.ts +434 -0
- package/dist/dashboard.d.ts +83 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/error-enrichment.d.ts +49 -0
- package/dist/error-enrichment.d.ts.map +1 -0
- package/dist/export-tools.d.ts +76 -0
- package/dist/export-tools.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/observability-tools.d.ts +2 -2
- package/dist/query-tools.d.ts +59 -0
- package/dist/query-tools.d.ts.map +1 -0
- package/dist/replay-tools.d.ts +28 -0
- package/dist/replay-tools.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/dashboard.test.ts +611 -0
- package/src/dashboard.ts +462 -0
- package/src/error-enrichment.test.ts +403 -0
- package/src/error-enrichment.ts +219 -0
- package/src/export-tools.test.ts +476 -0
- package/src/export-tools.ts +257 -0
- package/src/query-tools.test.ts +636 -0
- package/src/query-tools.ts +324 -0
- package/src/replay-tools.test.ts +496 -0
- package/src/replay-tools.ts +240 -0
package/bin/swarm.test.ts
CHANGED
|
@@ -1449,3 +1449,618 @@ describe("swarm history", () => {
|
|
|
1449
1449
|
});
|
|
1450
1450
|
});
|
|
1451
1451
|
});
|
|
1452
|
+
|
|
1453
|
+
// ============================================================================
|
|
1454
|
+
// Observability Commands Tests (TDD - Phase 5)
|
|
1455
|
+
// ============================================================================
|
|
1456
|
+
|
|
1457
|
+
describe("swarm query", () => {
|
|
1458
|
+
test("executes SQL query with table format", () => {
|
|
1459
|
+
// Mock function - to be implemented in swarm.ts
|
|
1460
|
+
function executeQueryCommand(args: string[]): { format: string; query?: string; preset?: string } {
|
|
1461
|
+
let format = "table";
|
|
1462
|
+
let query: string | undefined;
|
|
1463
|
+
let preset: string | undefined;
|
|
1464
|
+
|
|
1465
|
+
for (let i = 0; i < args.length; i++) {
|
|
1466
|
+
if (args[i] === "--format") {
|
|
1467
|
+
format = args[i + 1] || "table";
|
|
1468
|
+
i++;
|
|
1469
|
+
} else if (args[i] === "--sql") {
|
|
1470
|
+
query = args[i + 1];
|
|
1471
|
+
i++;
|
|
1472
|
+
} else if (args[i] === "--preset") {
|
|
1473
|
+
preset = args[i + 1];
|
|
1474
|
+
i++;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
return { format, query, preset };
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
const result = executeQueryCommand(["--sql", "SELECT * FROM events", "--format", "table"]);
|
|
1482
|
+
|
|
1483
|
+
expect(result.query).toBe("SELECT * FROM events");
|
|
1484
|
+
expect(result.format).toBe("table");
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
test("executes preset query", () => {
|
|
1488
|
+
function executeQueryCommand(args: string[]): { format: string; query?: string; preset?: string } {
|
|
1489
|
+
let format = "table";
|
|
1490
|
+
let query: string | undefined;
|
|
1491
|
+
let preset: string | undefined;
|
|
1492
|
+
|
|
1493
|
+
for (let i = 0; i < args.length; i++) {
|
|
1494
|
+
if (args[i] === "--format") {
|
|
1495
|
+
format = args[i + 1] || "table";
|
|
1496
|
+
i++;
|
|
1497
|
+
} else if (args[i] === "--sql") {
|
|
1498
|
+
query = args[i + 1];
|
|
1499
|
+
i++;
|
|
1500
|
+
} else if (args[i] === "--preset") {
|
|
1501
|
+
preset = args[i + 1];
|
|
1502
|
+
i++;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
return { format, query, preset };
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
const result = executeQueryCommand(["--preset", "failed_decompositions", "--format", "csv"]);
|
|
1510
|
+
|
|
1511
|
+
expect(result.preset).toBe("failed_decompositions");
|
|
1512
|
+
expect(result.format).toBe("csv");
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
test("defaults to table format", () => {
|
|
1516
|
+
function executeQueryCommand(args: string[]): { format: string; query?: string; preset?: string } {
|
|
1517
|
+
let format = "table";
|
|
1518
|
+
let query: string | undefined;
|
|
1519
|
+
let preset: string | undefined;
|
|
1520
|
+
|
|
1521
|
+
for (let i = 0; i < args.length; i++) {
|
|
1522
|
+
if (args[i] === "--format") {
|
|
1523
|
+
format = args[i + 1] || "table";
|
|
1524
|
+
i++;
|
|
1525
|
+
} else if (args[i] === "--sql") {
|
|
1526
|
+
query = args[i + 1];
|
|
1527
|
+
i++;
|
|
1528
|
+
} else if (args[i] === "--preset") {
|
|
1529
|
+
preset = args[i + 1];
|
|
1530
|
+
i++;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
return { format, query, preset };
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
const result = executeQueryCommand(["--sql", "SELECT * FROM events"]);
|
|
1538
|
+
|
|
1539
|
+
expect(result.format).toBe("table");
|
|
1540
|
+
});
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1543
|
+
describe("swarm dashboard", () => {
|
|
1544
|
+
test("parses epic filter flag", () => {
|
|
1545
|
+
function parseDashboardArgs(args: string[]): { epic?: string; refresh: number } {
|
|
1546
|
+
let epic: string | undefined;
|
|
1547
|
+
let refresh = 1000;
|
|
1548
|
+
|
|
1549
|
+
for (let i = 0; i < args.length; i++) {
|
|
1550
|
+
if (args[i] === "--epic") {
|
|
1551
|
+
epic = args[i + 1];
|
|
1552
|
+
i++;
|
|
1553
|
+
} else if (args[i] === "--refresh") {
|
|
1554
|
+
const ms = parseInt(args[i + 1], 10);
|
|
1555
|
+
if (!isNaN(ms) && ms > 0) {
|
|
1556
|
+
refresh = ms;
|
|
1557
|
+
}
|
|
1558
|
+
i++;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
return { epic, refresh };
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
const result = parseDashboardArgs(["--epic", "mjkw1234567"]);
|
|
1566
|
+
|
|
1567
|
+
expect(result.epic).toBe("mjkw1234567");
|
|
1568
|
+
expect(result.refresh).toBe(1000); // default
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
test("parses refresh interval flag", () => {
|
|
1572
|
+
function parseDashboardArgs(args: string[]): { epic?: string; refresh: number } {
|
|
1573
|
+
let epic: string | undefined;
|
|
1574
|
+
let refresh = 1000;
|
|
1575
|
+
|
|
1576
|
+
for (let i = 0; i < args.length; i++) {
|
|
1577
|
+
if (args[i] === "--epic") {
|
|
1578
|
+
epic = args[i + 1];
|
|
1579
|
+
i++;
|
|
1580
|
+
} else if (args[i] === "--refresh") {
|
|
1581
|
+
const ms = parseInt(args[i + 1], 10);
|
|
1582
|
+
if (!isNaN(ms) && ms > 0) {
|
|
1583
|
+
refresh = ms;
|
|
1584
|
+
}
|
|
1585
|
+
i++;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
return { epic, refresh };
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
const result = parseDashboardArgs(["--refresh", "2000"]);
|
|
1593
|
+
|
|
1594
|
+
expect(result.refresh).toBe(2000);
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
test("defaults to 1000ms refresh", () => {
|
|
1598
|
+
function parseDashboardArgs(args: string[]): { epic?: string; refresh: number } {
|
|
1599
|
+
let epic: string | undefined;
|
|
1600
|
+
let refresh = 1000;
|
|
1601
|
+
|
|
1602
|
+
for (let i = 0; i < args.length; i++) {
|
|
1603
|
+
if (args[i] === "--epic") {
|
|
1604
|
+
epic = args[i + 1];
|
|
1605
|
+
i++;
|
|
1606
|
+
} else if (args[i] === "--refresh") {
|
|
1607
|
+
const ms = parseInt(args[i + 1], 10);
|
|
1608
|
+
if (!isNaN(ms) && ms > 0) {
|
|
1609
|
+
refresh = ms;
|
|
1610
|
+
}
|
|
1611
|
+
i++;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
return { epic, refresh };
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
const result = parseDashboardArgs([]);
|
|
1619
|
+
|
|
1620
|
+
expect(result.refresh).toBe(1000);
|
|
1621
|
+
});
|
|
1622
|
+
});
|
|
1623
|
+
|
|
1624
|
+
describe("swarm replay", () => {
|
|
1625
|
+
test("parses speed multiplier flag", () => {
|
|
1626
|
+
function parseReplayArgs(args: string[]): {
|
|
1627
|
+
epicId?: string;
|
|
1628
|
+
speed: number;
|
|
1629
|
+
types: string[];
|
|
1630
|
+
agent?: string;
|
|
1631
|
+
since?: Date;
|
|
1632
|
+
until?: Date;
|
|
1633
|
+
} {
|
|
1634
|
+
let epicId: string | undefined;
|
|
1635
|
+
let speed = 1;
|
|
1636
|
+
let types: string[] = [];
|
|
1637
|
+
let agent: string | undefined;
|
|
1638
|
+
let since: Date | undefined;
|
|
1639
|
+
let until: Date | undefined;
|
|
1640
|
+
|
|
1641
|
+
// First positional arg is epic ID
|
|
1642
|
+
if (args.length > 0 && !args[0].startsWith("--")) {
|
|
1643
|
+
epicId = args[0];
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
for (let i = 0; i < args.length; i++) {
|
|
1647
|
+
if (args[i] === "--speed") {
|
|
1648
|
+
const val = args[i + 1];
|
|
1649
|
+
if (val === "instant") {
|
|
1650
|
+
speed = Infinity;
|
|
1651
|
+
} else {
|
|
1652
|
+
const parsed = parseFloat(val?.replace("x", "") || "1");
|
|
1653
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
1654
|
+
speed = parsed;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
i++;
|
|
1658
|
+
} else if (args[i] === "--type") {
|
|
1659
|
+
types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
|
|
1660
|
+
i++;
|
|
1661
|
+
} else if (args[i] === "--agent") {
|
|
1662
|
+
agent = args[i + 1];
|
|
1663
|
+
i++;
|
|
1664
|
+
} else if (args[i] === "--since") {
|
|
1665
|
+
const dateStr = args[i + 1];
|
|
1666
|
+
if (dateStr) {
|
|
1667
|
+
since = new Date(dateStr);
|
|
1668
|
+
}
|
|
1669
|
+
i++;
|
|
1670
|
+
} else if (args[i] === "--until") {
|
|
1671
|
+
const dateStr = args[i + 1];
|
|
1672
|
+
if (dateStr) {
|
|
1673
|
+
until = new Date(dateStr);
|
|
1674
|
+
}
|
|
1675
|
+
i++;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
return { epicId, speed, types, agent, since, until };
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
const result = parseReplayArgs(["mjkw1234567", "--speed", "2x"]);
|
|
1683
|
+
|
|
1684
|
+
expect(result.epicId).toBe("mjkw1234567");
|
|
1685
|
+
expect(result.speed).toBe(2);
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
test("parses instant speed", () => {
|
|
1689
|
+
function parseReplayArgs(args: string[]): {
|
|
1690
|
+
epicId?: string;
|
|
1691
|
+
speed: number;
|
|
1692
|
+
types: string[];
|
|
1693
|
+
agent?: string;
|
|
1694
|
+
since?: Date;
|
|
1695
|
+
until?: Date;
|
|
1696
|
+
} {
|
|
1697
|
+
let epicId: string | undefined;
|
|
1698
|
+
let speed = 1;
|
|
1699
|
+
let types: string[] = [];
|
|
1700
|
+
let agent: string | undefined;
|
|
1701
|
+
let since: Date | undefined;
|
|
1702
|
+
let until: Date | undefined;
|
|
1703
|
+
|
|
1704
|
+
if (args.length > 0 && !args[0].startsWith("--")) {
|
|
1705
|
+
epicId = args[0];
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
for (let i = 0; i < args.length; i++) {
|
|
1709
|
+
if (args[i] === "--speed") {
|
|
1710
|
+
const val = args[i + 1];
|
|
1711
|
+
if (val === "instant") {
|
|
1712
|
+
speed = Infinity;
|
|
1713
|
+
} else {
|
|
1714
|
+
const parsed = parseFloat(val?.replace("x", "") || "1");
|
|
1715
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
1716
|
+
speed = parsed;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
i++;
|
|
1720
|
+
} else if (args[i] === "--type") {
|
|
1721
|
+
types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
|
|
1722
|
+
i++;
|
|
1723
|
+
} else if (args[i] === "--agent") {
|
|
1724
|
+
agent = args[i + 1];
|
|
1725
|
+
i++;
|
|
1726
|
+
} else if (args[i] === "--since") {
|
|
1727
|
+
const dateStr = args[i + 1];
|
|
1728
|
+
if (dateStr) {
|
|
1729
|
+
since = new Date(dateStr);
|
|
1730
|
+
}
|
|
1731
|
+
i++;
|
|
1732
|
+
} else if (args[i] === "--until") {
|
|
1733
|
+
const dateStr = args[i + 1];
|
|
1734
|
+
if (dateStr) {
|
|
1735
|
+
until = new Date(dateStr);
|
|
1736
|
+
}
|
|
1737
|
+
i++;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
return { epicId, speed, types, agent, since, until };
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
const result = parseReplayArgs(["mjkw1234567", "--speed", "instant"]);
|
|
1745
|
+
|
|
1746
|
+
expect(result.speed).toBe(Infinity);
|
|
1747
|
+
});
|
|
1748
|
+
|
|
1749
|
+
test("parses event type filters", () => {
|
|
1750
|
+
function parseReplayArgs(args: string[]): {
|
|
1751
|
+
epicId?: string;
|
|
1752
|
+
speed: number;
|
|
1753
|
+
types: string[];
|
|
1754
|
+
agent?: string;
|
|
1755
|
+
since?: Date;
|
|
1756
|
+
until?: Date;
|
|
1757
|
+
} {
|
|
1758
|
+
let epicId: string | undefined;
|
|
1759
|
+
let speed = 1;
|
|
1760
|
+
let types: string[] = [];
|
|
1761
|
+
let agent: string | undefined;
|
|
1762
|
+
let since: Date | undefined;
|
|
1763
|
+
let until: Date | undefined;
|
|
1764
|
+
|
|
1765
|
+
if (args.length > 0 && !args[0].startsWith("--")) {
|
|
1766
|
+
epicId = args[0];
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
for (let i = 0; i < args.length; i++) {
|
|
1770
|
+
if (args[i] === "--speed") {
|
|
1771
|
+
const val = args[i + 1];
|
|
1772
|
+
if (val === "instant") {
|
|
1773
|
+
speed = Infinity;
|
|
1774
|
+
} else {
|
|
1775
|
+
const parsed = parseFloat(val?.replace("x", "") || "1");
|
|
1776
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
1777
|
+
speed = parsed;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
i++;
|
|
1781
|
+
} else if (args[i] === "--type") {
|
|
1782
|
+
types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
|
|
1783
|
+
i++;
|
|
1784
|
+
} else if (args[i] === "--agent") {
|
|
1785
|
+
agent = args[i + 1];
|
|
1786
|
+
i++;
|
|
1787
|
+
} else if (args[i] === "--since") {
|
|
1788
|
+
const dateStr = args[i + 1];
|
|
1789
|
+
if (dateStr) {
|
|
1790
|
+
since = new Date(dateStr);
|
|
1791
|
+
}
|
|
1792
|
+
i++;
|
|
1793
|
+
} else if (args[i] === "--until") {
|
|
1794
|
+
const dateStr = args[i + 1];
|
|
1795
|
+
if (dateStr) {
|
|
1796
|
+
until = new Date(dateStr);
|
|
1797
|
+
}
|
|
1798
|
+
i++;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
return { epicId, speed, types, agent, since, until };
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
const result = parseReplayArgs(["--type", "DECISION,VIOLATION"]);
|
|
1806
|
+
|
|
1807
|
+
expect(result.types).toEqual(["DECISION", "VIOLATION"]);
|
|
1808
|
+
});
|
|
1809
|
+
|
|
1810
|
+
test("parses agent filter", () => {
|
|
1811
|
+
function parseReplayArgs(args: string[]): {
|
|
1812
|
+
epicId?: string;
|
|
1813
|
+
speed: number;
|
|
1814
|
+
types: string[];
|
|
1815
|
+
agent?: string;
|
|
1816
|
+
since?: Date;
|
|
1817
|
+
until?: Date;
|
|
1818
|
+
} {
|
|
1819
|
+
let epicId: string | undefined;
|
|
1820
|
+
let speed = 1;
|
|
1821
|
+
let types: string[] = [];
|
|
1822
|
+
let agent: string | undefined;
|
|
1823
|
+
let since: Date | undefined;
|
|
1824
|
+
let until: Date | undefined;
|
|
1825
|
+
|
|
1826
|
+
if (args.length > 0 && !args[0].startsWith("--")) {
|
|
1827
|
+
epicId = args[0];
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
for (let i = 0; i < args.length; i++) {
|
|
1831
|
+
if (args[i] === "--speed") {
|
|
1832
|
+
const val = args[i + 1];
|
|
1833
|
+
if (val === "instant") {
|
|
1834
|
+
speed = Infinity;
|
|
1835
|
+
} else {
|
|
1836
|
+
const parsed = parseFloat(val?.replace("x", "") || "1");
|
|
1837
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
1838
|
+
speed = parsed;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
i++;
|
|
1842
|
+
} else if (args[i] === "--type") {
|
|
1843
|
+
types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
|
|
1844
|
+
i++;
|
|
1845
|
+
} else if (args[i] === "--agent") {
|
|
1846
|
+
agent = args[i + 1];
|
|
1847
|
+
i++;
|
|
1848
|
+
} else if (args[i] === "--since") {
|
|
1849
|
+
const dateStr = args[i + 1];
|
|
1850
|
+
if (dateStr) {
|
|
1851
|
+
since = new Date(dateStr);
|
|
1852
|
+
}
|
|
1853
|
+
i++;
|
|
1854
|
+
} else if (args[i] === "--until") {
|
|
1855
|
+
const dateStr = args[i + 1];
|
|
1856
|
+
if (dateStr) {
|
|
1857
|
+
until = new Date(dateStr);
|
|
1858
|
+
}
|
|
1859
|
+
i++;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
return { epicId, speed, types, agent, since, until };
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
const result = parseReplayArgs(["--agent", "WildLake"]);
|
|
1867
|
+
|
|
1868
|
+
expect(result.agent).toBe("WildLake");
|
|
1869
|
+
});
|
|
1870
|
+
|
|
1871
|
+
test("parses time range filters", () => {
|
|
1872
|
+
function parseReplayArgs(args: string[]): {
|
|
1873
|
+
epicId?: string;
|
|
1874
|
+
speed: number;
|
|
1875
|
+
types: string[];
|
|
1876
|
+
agent?: string;
|
|
1877
|
+
since?: Date;
|
|
1878
|
+
until?: Date;
|
|
1879
|
+
} {
|
|
1880
|
+
let epicId: string | undefined;
|
|
1881
|
+
let speed = 1;
|
|
1882
|
+
let types: string[] = [];
|
|
1883
|
+
let agent: string | undefined;
|
|
1884
|
+
let since: Date | undefined;
|
|
1885
|
+
let until: Date | undefined;
|
|
1886
|
+
|
|
1887
|
+
if (args.length > 0 && !args[0].startsWith("--")) {
|
|
1888
|
+
epicId = args[0];
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
for (let i = 0; i < args.length; i++) {
|
|
1892
|
+
if (args[i] === "--speed") {
|
|
1893
|
+
const val = args[i + 1];
|
|
1894
|
+
if (val === "instant") {
|
|
1895
|
+
speed = Infinity;
|
|
1896
|
+
} else {
|
|
1897
|
+
const parsed = parseFloat(val?.replace("x", "") || "1");
|
|
1898
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
1899
|
+
speed = parsed;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
i++;
|
|
1903
|
+
} else if (args[i] === "--type") {
|
|
1904
|
+
types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
|
|
1905
|
+
i++;
|
|
1906
|
+
} else if (args[i] === "--agent") {
|
|
1907
|
+
agent = args[i + 1];
|
|
1908
|
+
i++;
|
|
1909
|
+
} else if (args[i] === "--since") {
|
|
1910
|
+
const dateStr = args[i + 1];
|
|
1911
|
+
if (dateStr) {
|
|
1912
|
+
since = new Date(dateStr);
|
|
1913
|
+
}
|
|
1914
|
+
i++;
|
|
1915
|
+
} else if (args[i] === "--until") {
|
|
1916
|
+
const dateStr = args[i + 1];
|
|
1917
|
+
if (dateStr) {
|
|
1918
|
+
until = new Date(dateStr);
|
|
1919
|
+
}
|
|
1920
|
+
i++;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
return { epicId, speed, types, agent, since, until };
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
const result = parseReplayArgs([
|
|
1928
|
+
"--since",
|
|
1929
|
+
"2025-12-01T00:00:00Z",
|
|
1930
|
+
"--until",
|
|
1931
|
+
"2025-12-31T23:59:59Z",
|
|
1932
|
+
]);
|
|
1933
|
+
|
|
1934
|
+
expect(result.since).toBeInstanceOf(Date);
|
|
1935
|
+
expect(result.until).toBeInstanceOf(Date);
|
|
1936
|
+
expect(result.since!.getFullYear()).toBe(2025);
|
|
1937
|
+
expect(result.until!.getMonth()).toBe(11); // December is month 11
|
|
1938
|
+
});
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
describe("swarm export", () => {
|
|
1942
|
+
test("parses format flag", () => {
|
|
1943
|
+
function parseExportArgs(args: string[]): {
|
|
1944
|
+
format: string;
|
|
1945
|
+
epic?: string;
|
|
1946
|
+
output?: string;
|
|
1947
|
+
} {
|
|
1948
|
+
let format = "json";
|
|
1949
|
+
let epic: string | undefined;
|
|
1950
|
+
let output: string | undefined;
|
|
1951
|
+
|
|
1952
|
+
for (let i = 0; i < args.length; i++) {
|
|
1953
|
+
if (args[i] === "--format") {
|
|
1954
|
+
format = args[i + 1] || "json";
|
|
1955
|
+
i++;
|
|
1956
|
+
} else if (args[i] === "--epic") {
|
|
1957
|
+
epic = args[i + 1];
|
|
1958
|
+
i++;
|
|
1959
|
+
} else if (args[i] === "--output") {
|
|
1960
|
+
output = args[i + 1];
|
|
1961
|
+
i++;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
return { format, epic, output };
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
const result = parseExportArgs(["--format", "otlp"]);
|
|
1969
|
+
|
|
1970
|
+
expect(result.format).toBe("otlp");
|
|
1971
|
+
});
|
|
1972
|
+
|
|
1973
|
+
test("parses epic filter", () => {
|
|
1974
|
+
function parseExportArgs(args: string[]): {
|
|
1975
|
+
format: string;
|
|
1976
|
+
epic?: string;
|
|
1977
|
+
output?: string;
|
|
1978
|
+
} {
|
|
1979
|
+
let format = "json";
|
|
1980
|
+
let epic: string | undefined;
|
|
1981
|
+
let output: string | undefined;
|
|
1982
|
+
|
|
1983
|
+
for (let i = 0; i < args.length; i++) {
|
|
1984
|
+
if (args[i] === "--format") {
|
|
1985
|
+
format = args[i + 1] || "json";
|
|
1986
|
+
i++;
|
|
1987
|
+
} else if (args[i] === "--epic") {
|
|
1988
|
+
epic = args[i + 1];
|
|
1989
|
+
i++;
|
|
1990
|
+
} else if (args[i] === "--output") {
|
|
1991
|
+
output = args[i + 1];
|
|
1992
|
+
i++;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
return { format, epic, output };
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
const result = parseExportArgs(["--epic", "mjkw1234567"]);
|
|
2000
|
+
|
|
2001
|
+
expect(result.epic).toBe("mjkw1234567");
|
|
2002
|
+
});
|
|
2003
|
+
|
|
2004
|
+
test("parses output file path", () => {
|
|
2005
|
+
function parseExportArgs(args: string[]): {
|
|
2006
|
+
format: string;
|
|
2007
|
+
epic?: string;
|
|
2008
|
+
output?: string;
|
|
2009
|
+
} {
|
|
2010
|
+
let format = "json";
|
|
2011
|
+
let epic: string | undefined;
|
|
2012
|
+
let output: string | undefined;
|
|
2013
|
+
|
|
2014
|
+
for (let i = 0; i < args.length; i++) {
|
|
2015
|
+
if (args[i] === "--format") {
|
|
2016
|
+
format = args[i + 1] || "json";
|
|
2017
|
+
i++;
|
|
2018
|
+
} else if (args[i] === "--epic") {
|
|
2019
|
+
epic = args[i + 1];
|
|
2020
|
+
i++;
|
|
2021
|
+
} else if (args[i] === "--output") {
|
|
2022
|
+
output = args[i + 1];
|
|
2023
|
+
i++;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
return { format, epic, output };
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
const result = parseExportArgs(["--output", "/tmp/export.json"]);
|
|
2031
|
+
|
|
2032
|
+
expect(result.output).toBe("/tmp/export.json");
|
|
2033
|
+
});
|
|
2034
|
+
|
|
2035
|
+
test("defaults to json format", () => {
|
|
2036
|
+
function parseExportArgs(args: string[]): {
|
|
2037
|
+
format: string;
|
|
2038
|
+
epic?: string;
|
|
2039
|
+
output?: string;
|
|
2040
|
+
} {
|
|
2041
|
+
let format = "json";
|
|
2042
|
+
let epic: string | undefined;
|
|
2043
|
+
let output: string | undefined;
|
|
2044
|
+
|
|
2045
|
+
for (let i = 0; i < args.length; i++) {
|
|
2046
|
+
if (args[i] === "--format") {
|
|
2047
|
+
format = args[i + 1] || "json";
|
|
2048
|
+
i++;
|
|
2049
|
+
} else if (args[i] === "--epic") {
|
|
2050
|
+
epic = args[i + 1];
|
|
2051
|
+
i++;
|
|
2052
|
+
} else if (args[i] === "--output") {
|
|
2053
|
+
output = args[i + 1];
|
|
2054
|
+
i++;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
return { format, epic, output };
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
const result = parseExportArgs([]);
|
|
2062
|
+
|
|
2063
|
+
expect(result.format).toBe("json");
|
|
2064
|
+
});
|
|
2065
|
+
});
|
|
2066
|
+
|