@markmdev/pebble 0.1.0 → 0.1.1
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/index.js
CHANGED
|
@@ -886,6 +886,7 @@ function listCommand(program2) {
|
|
|
886
886
|
program2.command("list").description("List issues").option("--status <status>", "Filter by status").option("-t, --type <type>", "Filter by type").option("--priority <priority>", "Filter by priority").option("--parent <id>", "Filter by parent epic").action(async (options) => {
|
|
887
887
|
const pretty = program2.opts().pretty ?? false;
|
|
888
888
|
try {
|
|
889
|
+
getOrCreatePebbleDir();
|
|
889
890
|
const filters = {};
|
|
890
891
|
if (options.status !== void 0) {
|
|
891
892
|
const status = options.status;
|
|
@@ -924,6 +925,7 @@ function showCommand(program2) {
|
|
|
924
925
|
program2.command("show <id>").description("Show issue details").action(async (id) => {
|
|
925
926
|
const pretty = program2.opts().pretty ?? false;
|
|
926
927
|
try {
|
|
928
|
+
getOrCreatePebbleDir();
|
|
927
929
|
const resolvedId = resolveId(id);
|
|
928
930
|
const issue = getIssue(resolvedId);
|
|
929
931
|
if (!issue) {
|
|
@@ -941,6 +943,7 @@ function readyCommand(program2) {
|
|
|
941
943
|
program2.command("ready").description("Show issues ready for work (no open blockers)").action(async () => {
|
|
942
944
|
const pretty = program2.opts().pretty ?? false;
|
|
943
945
|
try {
|
|
946
|
+
getOrCreatePebbleDir();
|
|
944
947
|
const issues = getReady();
|
|
945
948
|
outputIssueList(issues, pretty);
|
|
946
949
|
} catch (error) {
|
|
@@ -954,6 +957,7 @@ function blockedCommand(program2) {
|
|
|
954
957
|
program2.command("blocked").description("Show blocked issues (have open blockers)").action(async () => {
|
|
955
958
|
const pretty = program2.opts().pretty ?? false;
|
|
956
959
|
try {
|
|
960
|
+
getOrCreatePebbleDir();
|
|
957
961
|
const issues = getBlocked();
|
|
958
962
|
outputIssueList(issues, pretty);
|
|
959
963
|
} catch (error) {
|
|
@@ -1157,6 +1161,7 @@ function graphCommand(program2) {
|
|
|
1157
1161
|
program2.command("graph").description("Show dependency graph").option("--root <id>", "Filter to subtree rooted at issue").action(async (options) => {
|
|
1158
1162
|
const pretty = program2.opts().pretty ?? false;
|
|
1159
1163
|
try {
|
|
1164
|
+
getOrCreatePebbleDir();
|
|
1160
1165
|
let issues;
|
|
1161
1166
|
if (options.root) {
|
|
1162
1167
|
const rootId = resolveId(options.root);
|
|
@@ -1342,6 +1347,27 @@ function mergeIssuesFromFiles(filePaths) {
|
|
|
1342
1347
|
_sources: Array.from(sources)
|
|
1343
1348
|
}));
|
|
1344
1349
|
}
|
|
1350
|
+
function findIssueInSources(issueId, filePaths) {
|
|
1351
|
+
const allIssues = mergeIssuesFromFiles(filePaths);
|
|
1352
|
+
let found = allIssues.find((i) => i.id === issueId);
|
|
1353
|
+
if (!found) {
|
|
1354
|
+
const matches = allIssues.filter((i) => i.id.startsWith(issueId));
|
|
1355
|
+
if (matches.length === 1) {
|
|
1356
|
+
found = matches[0];
|
|
1357
|
+
} else if (matches.length > 1) {
|
|
1358
|
+
return null;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (!found) {
|
|
1362
|
+
return null;
|
|
1363
|
+
}
|
|
1364
|
+
const targetFile = found._sources[0];
|
|
1365
|
+
return { issue: found, targetFile };
|
|
1366
|
+
}
|
|
1367
|
+
function appendEventToFile(event, filePath) {
|
|
1368
|
+
const line = JSON.stringify(event) + "\n";
|
|
1369
|
+
fs2.appendFileSync(filePath, line, "utf-8");
|
|
1370
|
+
}
|
|
1345
1371
|
function uiCommand(program2) {
|
|
1346
1372
|
const defaultPort = process.env.PEBBLE_UI_PORT || "3333";
|
|
1347
1373
|
program2.command("ui").description("Serve the React UI").option("--port <port>", "Port to serve on", defaultPort).option("--no-open", "Do not open browser automatically").option("--files <paths>", "Comma-separated paths to issues.jsonl files for multi-worktree view").action(async (options) => {
|
|
@@ -1422,26 +1448,16 @@ function uiCommand(program2) {
|
|
|
1422
1448
|
});
|
|
1423
1449
|
app.get("/api/issues", (_req, res) => {
|
|
1424
1450
|
try {
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
res.json(issues);
|
|
1428
|
-
} else {
|
|
1429
|
-
const issues = getIssues({});
|
|
1430
|
-
res.json(issues);
|
|
1431
|
-
}
|
|
1451
|
+
const issues = mergeIssuesFromFiles(issueFiles);
|
|
1452
|
+
res.json(issues);
|
|
1432
1453
|
} catch (error) {
|
|
1433
1454
|
res.status(500).json({ error: error.message });
|
|
1434
1455
|
}
|
|
1435
1456
|
});
|
|
1436
1457
|
app.get("/api/events", (_req, res) => {
|
|
1437
1458
|
try {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
res.json(events);
|
|
1441
|
-
} else {
|
|
1442
|
-
const events = readEvents();
|
|
1443
|
-
res.json(events);
|
|
1444
|
-
}
|
|
1459
|
+
const events = readEventsFromFiles(issueFiles);
|
|
1460
|
+
res.json(events);
|
|
1445
1461
|
} catch (error) {
|
|
1446
1462
|
res.status(500).json({ error: error.message });
|
|
1447
1463
|
}
|
|
@@ -1653,12 +1669,28 @@ data: ${message}
|
|
|
1653
1669
|
});
|
|
1654
1670
|
app.put("/api/issues/:id", (req, res) => {
|
|
1655
1671
|
try {
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
if (
|
|
1660
|
-
|
|
1661
|
-
|
|
1672
|
+
let issue;
|
|
1673
|
+
let issueId;
|
|
1674
|
+
let targetFile;
|
|
1675
|
+
if (isMultiWorktree()) {
|
|
1676
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
1677
|
+
if (!found) {
|
|
1678
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
issue = found.issue;
|
|
1682
|
+
issueId = issue.id;
|
|
1683
|
+
targetFile = found.targetFile;
|
|
1684
|
+
} else {
|
|
1685
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
1686
|
+
issueId = resolveId(req.params.id);
|
|
1687
|
+
const localIssue = getIssue(issueId);
|
|
1688
|
+
if (!localIssue) {
|
|
1689
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
issue = localIssue;
|
|
1693
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
1662
1694
|
}
|
|
1663
1695
|
const { title, type, priority, status, description, parent } = req.body;
|
|
1664
1696
|
const updates = {};
|
|
@@ -1695,14 +1727,26 @@ data: ${message}
|
|
|
1695
1727
|
}
|
|
1696
1728
|
if (parent !== void 0) {
|
|
1697
1729
|
if (parent !== null) {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1730
|
+
if (isMultiWorktree()) {
|
|
1731
|
+
const parentFound = findIssueInSources(parent, issueFiles);
|
|
1732
|
+
if (!parentFound) {
|
|
1733
|
+
res.status(400).json({ error: `Parent issue not found: ${parent}` });
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
if (parentFound.issue.type !== "epic") {
|
|
1737
|
+
res.status(400).json({ error: "Parent must be an epic" });
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
} else {
|
|
1741
|
+
const parentIssue = getIssue(parent);
|
|
1742
|
+
if (!parentIssue) {
|
|
1743
|
+
res.status(400).json({ error: `Parent issue not found: ${parent}` });
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
if (parentIssue.type !== "epic") {
|
|
1747
|
+
res.status(400).json({ error: "Parent must be an epic" });
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1706
1750
|
}
|
|
1707
1751
|
}
|
|
1708
1752
|
updates.parent = parent;
|
|
@@ -1718,27 +1762,47 @@ data: ${message}
|
|
|
1718
1762
|
timestamp,
|
|
1719
1763
|
data: updates
|
|
1720
1764
|
};
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1765
|
+
appendEventToFile(event, targetFile);
|
|
1766
|
+
if (isMultiWorktree()) {
|
|
1767
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
1768
|
+
res.json(updated?.issue || { ...issue, ...updates, updatedAt: timestamp });
|
|
1769
|
+
} else {
|
|
1770
|
+
res.json(getIssue(issueId));
|
|
1771
|
+
}
|
|
1724
1772
|
} catch (error) {
|
|
1725
1773
|
res.status(500).json({ error: error.message });
|
|
1726
1774
|
}
|
|
1727
1775
|
});
|
|
1728
1776
|
app.post("/api/issues/:id/close", (req, res) => {
|
|
1729
1777
|
try {
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
if (
|
|
1734
|
-
|
|
1735
|
-
|
|
1778
|
+
let issue;
|
|
1779
|
+
let issueId;
|
|
1780
|
+
let targetFile;
|
|
1781
|
+
if (isMultiWorktree()) {
|
|
1782
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
1783
|
+
if (!found) {
|
|
1784
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
issue = found.issue;
|
|
1788
|
+
issueId = issue.id;
|
|
1789
|
+
targetFile = found.targetFile;
|
|
1790
|
+
} else {
|
|
1791
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
1792
|
+
issueId = resolveId(req.params.id);
|
|
1793
|
+
const localIssue = getIssue(issueId);
|
|
1794
|
+
if (!localIssue) {
|
|
1795
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
issue = localIssue;
|
|
1799
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
1736
1800
|
}
|
|
1737
1801
|
if (issue.status === "closed") {
|
|
1738
1802
|
res.status(400).json({ error: "Issue is already closed" });
|
|
1739
1803
|
return;
|
|
1740
1804
|
}
|
|
1741
|
-
if (issue.type === "epic" && hasOpenChildren(issueId)) {
|
|
1805
|
+
if (!isMultiWorktree() && issue.type === "epic" && hasOpenChildren(issueId)) {
|
|
1742
1806
|
res.status(400).json({ error: "Cannot close epic with open children" });
|
|
1743
1807
|
return;
|
|
1744
1808
|
}
|
|
@@ -1750,21 +1814,41 @@ data: ${message}
|
|
|
1750
1814
|
timestamp,
|
|
1751
1815
|
data: { reason }
|
|
1752
1816
|
};
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1817
|
+
appendEventToFile(event, targetFile);
|
|
1818
|
+
if (isMultiWorktree()) {
|
|
1819
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
1820
|
+
res.json(updated?.issue || { ...issue, status: "closed", updatedAt: timestamp });
|
|
1821
|
+
} else {
|
|
1822
|
+
res.json(getIssue(issueId));
|
|
1823
|
+
}
|
|
1756
1824
|
} catch (error) {
|
|
1757
1825
|
res.status(500).json({ error: error.message });
|
|
1758
1826
|
}
|
|
1759
1827
|
});
|
|
1760
1828
|
app.post("/api/issues/:id/reopen", (req, res) => {
|
|
1761
1829
|
try {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
if (
|
|
1766
|
-
|
|
1767
|
-
|
|
1830
|
+
let issue;
|
|
1831
|
+
let issueId;
|
|
1832
|
+
let targetFile;
|
|
1833
|
+
if (isMultiWorktree()) {
|
|
1834
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
1835
|
+
if (!found) {
|
|
1836
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
issue = found.issue;
|
|
1840
|
+
issueId = issue.id;
|
|
1841
|
+
targetFile = found.targetFile;
|
|
1842
|
+
} else {
|
|
1843
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
1844
|
+
issueId = resolveId(req.params.id);
|
|
1845
|
+
const localIssue = getIssue(issueId);
|
|
1846
|
+
if (!localIssue) {
|
|
1847
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
issue = localIssue;
|
|
1851
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
1768
1852
|
}
|
|
1769
1853
|
if (issue.status !== "closed") {
|
|
1770
1854
|
res.status(400).json({ error: "Issue is not closed" });
|
|
@@ -1778,21 +1862,41 @@ data: ${message}
|
|
|
1778
1862
|
timestamp,
|
|
1779
1863
|
data: { reason }
|
|
1780
1864
|
};
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1865
|
+
appendEventToFile(event, targetFile);
|
|
1866
|
+
if (isMultiWorktree()) {
|
|
1867
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
1868
|
+
res.json(updated?.issue || { ...issue, status: "open", updatedAt: timestamp });
|
|
1869
|
+
} else {
|
|
1870
|
+
res.json(getIssue(issueId));
|
|
1871
|
+
}
|
|
1784
1872
|
} catch (error) {
|
|
1785
1873
|
res.status(500).json({ error: error.message });
|
|
1786
1874
|
}
|
|
1787
1875
|
});
|
|
1788
1876
|
app.post("/api/issues/:id/comments", (req, res) => {
|
|
1789
1877
|
try {
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
if (
|
|
1794
|
-
|
|
1795
|
-
|
|
1878
|
+
let issue;
|
|
1879
|
+
let issueId;
|
|
1880
|
+
let targetFile;
|
|
1881
|
+
if (isMultiWorktree()) {
|
|
1882
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
1883
|
+
if (!found) {
|
|
1884
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
issue = found.issue;
|
|
1888
|
+
issueId = issue.id;
|
|
1889
|
+
targetFile = found.targetFile;
|
|
1890
|
+
} else {
|
|
1891
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
1892
|
+
issueId = resolveId(req.params.id);
|
|
1893
|
+
const localIssue = getIssue(issueId);
|
|
1894
|
+
if (!localIssue) {
|
|
1895
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
issue = localIssue;
|
|
1899
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
1796
1900
|
}
|
|
1797
1901
|
const { text, author } = req.body;
|
|
1798
1902
|
if (!text || typeof text !== "string" || text.trim() === "") {
|
|
@@ -1810,38 +1914,68 @@ data: ${message}
|
|
|
1810
1914
|
author
|
|
1811
1915
|
}
|
|
1812
1916
|
};
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1917
|
+
appendEventToFile(event, targetFile);
|
|
1918
|
+
if (isMultiWorktree()) {
|
|
1919
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
1920
|
+
res.json(updated?.issue || issue);
|
|
1921
|
+
} else {
|
|
1922
|
+
res.json(getIssue(issueId));
|
|
1923
|
+
}
|
|
1816
1924
|
} catch (error) {
|
|
1817
1925
|
res.status(500).json({ error: error.message });
|
|
1818
1926
|
}
|
|
1819
1927
|
});
|
|
1820
1928
|
app.post("/api/issues/:id/deps", (req, res) => {
|
|
1821
1929
|
try {
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
if (
|
|
1826
|
-
|
|
1827
|
-
|
|
1930
|
+
let issue;
|
|
1931
|
+
let issueId;
|
|
1932
|
+
let targetFile;
|
|
1933
|
+
if (isMultiWorktree()) {
|
|
1934
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
1935
|
+
if (!found) {
|
|
1936
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
issue = found.issue;
|
|
1940
|
+
issueId = issue.id;
|
|
1941
|
+
targetFile = found.targetFile;
|
|
1942
|
+
} else {
|
|
1943
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
1944
|
+
issueId = resolveId(req.params.id);
|
|
1945
|
+
const localIssue = getIssue(issueId);
|
|
1946
|
+
if (!localIssue) {
|
|
1947
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
issue = localIssue;
|
|
1951
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
1828
1952
|
}
|
|
1829
1953
|
const { blockerId } = req.body;
|
|
1830
1954
|
if (!blockerId) {
|
|
1831
1955
|
res.status(400).json({ error: "blockerId is required" });
|
|
1832
1956
|
return;
|
|
1833
1957
|
}
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1958
|
+
let resolvedBlockerId;
|
|
1959
|
+
if (isMultiWorktree()) {
|
|
1960
|
+
const blockerFound = findIssueInSources(blockerId, issueFiles);
|
|
1961
|
+
if (!blockerFound) {
|
|
1962
|
+
res.status(404).json({ error: `Blocker issue not found: ${blockerId}` });
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
resolvedBlockerId = blockerFound.issue.id;
|
|
1966
|
+
} else {
|
|
1967
|
+
resolvedBlockerId = resolveId(blockerId);
|
|
1968
|
+
const blockerIssue = getIssue(resolvedBlockerId);
|
|
1969
|
+
if (!blockerIssue) {
|
|
1970
|
+
res.status(404).json({ error: `Blocker issue not found: ${blockerId}` });
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1839
1973
|
}
|
|
1840
1974
|
if (issue.blockedBy.includes(resolvedBlockerId)) {
|
|
1841
1975
|
res.status(400).json({ error: "Dependency already exists" });
|
|
1842
1976
|
return;
|
|
1843
1977
|
}
|
|
1844
|
-
if (detectCycle(issueId, resolvedBlockerId)) {
|
|
1978
|
+
if (!isMultiWorktree() && detectCycle(issueId, resolvedBlockerId)) {
|
|
1845
1979
|
res.status(400).json({ error: "Adding this dependency would create a cycle" });
|
|
1846
1980
|
return;
|
|
1847
1981
|
}
|
|
@@ -1854,39 +1988,74 @@ data: ${message}
|
|
|
1854
1988
|
blockedBy: [...issue.blockedBy, resolvedBlockerId]
|
|
1855
1989
|
}
|
|
1856
1990
|
};
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1991
|
+
appendEventToFile(event, targetFile);
|
|
1992
|
+
if (isMultiWorktree()) {
|
|
1993
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
1994
|
+
res.json(updated?.issue || { ...issue, blockedBy: [...issue.blockedBy, resolvedBlockerId], updatedAt: timestamp });
|
|
1995
|
+
} else {
|
|
1996
|
+
res.json(getIssue(issueId));
|
|
1997
|
+
}
|
|
1860
1998
|
} catch (error) {
|
|
1861
1999
|
res.status(500).json({ error: error.message });
|
|
1862
2000
|
}
|
|
1863
2001
|
});
|
|
1864
2002
|
app.delete("/api/issues/:id/deps/:blockerId", (req, res) => {
|
|
1865
2003
|
try {
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
if (
|
|
1870
|
-
|
|
1871
|
-
|
|
2004
|
+
let issue;
|
|
2005
|
+
let issueId;
|
|
2006
|
+
let targetFile;
|
|
2007
|
+
if (isMultiWorktree()) {
|
|
2008
|
+
const found = findIssueInSources(req.params.id, issueFiles);
|
|
2009
|
+
if (!found) {
|
|
2010
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
issue = found.issue;
|
|
2014
|
+
issueId = issue.id;
|
|
2015
|
+
targetFile = found.targetFile;
|
|
2016
|
+
} else {
|
|
2017
|
+
const pebbleDir = getOrCreatePebbleDir();
|
|
2018
|
+
issueId = resolveId(req.params.id);
|
|
2019
|
+
const localIssue = getIssue(issueId);
|
|
2020
|
+
if (!localIssue) {
|
|
2021
|
+
res.status(404).json({ error: `Issue not found: ${req.params.id}` });
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
issue = localIssue;
|
|
2025
|
+
targetFile = path2.join(pebbleDir, "issues.jsonl");
|
|
2026
|
+
}
|
|
2027
|
+
let resolvedBlockerId;
|
|
2028
|
+
if (isMultiWorktree()) {
|
|
2029
|
+
const blockerFound = findIssueInSources(req.params.blockerId, issueFiles);
|
|
2030
|
+
if (blockerFound) {
|
|
2031
|
+
resolvedBlockerId = blockerFound.issue.id;
|
|
2032
|
+
} else {
|
|
2033
|
+
resolvedBlockerId = req.params.blockerId;
|
|
2034
|
+
}
|
|
2035
|
+
} else {
|
|
2036
|
+
resolvedBlockerId = resolveId(req.params.blockerId);
|
|
1872
2037
|
}
|
|
1873
|
-
const resolvedBlockerId = resolveId(req.params.blockerId);
|
|
1874
2038
|
if (!issue.blockedBy.includes(resolvedBlockerId)) {
|
|
1875
2039
|
res.status(400).json({ error: "Dependency does not exist" });
|
|
1876
2040
|
return;
|
|
1877
2041
|
}
|
|
1878
2042
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2043
|
+
const newBlockedBy = issue.blockedBy.filter((id) => id !== resolvedBlockerId);
|
|
1879
2044
|
const event = {
|
|
1880
2045
|
type: "update",
|
|
1881
2046
|
issueId,
|
|
1882
2047
|
timestamp,
|
|
1883
2048
|
data: {
|
|
1884
|
-
blockedBy:
|
|
2049
|
+
blockedBy: newBlockedBy
|
|
1885
2050
|
}
|
|
1886
2051
|
};
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
2052
|
+
appendEventToFile(event, targetFile);
|
|
2053
|
+
if (isMultiWorktree()) {
|
|
2054
|
+
const updated = findIssueInSources(issueId, issueFiles);
|
|
2055
|
+
res.json(updated?.issue || { ...issue, blockedBy: newBlockedBy, updatedAt: timestamp });
|
|
2056
|
+
} else {
|
|
2057
|
+
res.json(getIssue(issueId));
|
|
2058
|
+
}
|
|
1890
2059
|
} catch (error) {
|
|
1891
2060
|
res.status(500).json({ error: error.message });
|
|
1892
2061
|
}
|