@velvetmonkey/flywheel-crank 0.8.1 → 0.9.2
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/index.js +133 -45
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -14,6 +14,10 @@ import matter from "gray-matter";
|
|
|
14
14
|
|
|
15
15
|
// src/core/constants.ts
|
|
16
16
|
var HEADING_REGEX = /^(#{1,6})\s+(.+)$/;
|
|
17
|
+
function estimateTokens(content) {
|
|
18
|
+
const str = typeof content === "string" ? content : JSON.stringify(content);
|
|
19
|
+
return Math.ceil(str.length / 4);
|
|
20
|
+
}
|
|
17
21
|
|
|
18
22
|
// src/core/writer.ts
|
|
19
23
|
var SENSITIVE_PATH_PATTERNS = [
|
|
@@ -158,8 +162,8 @@ function formatContent(content, format) {
|
|
|
158
162
|
return trimmed;
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
|
-
function
|
|
162
|
-
for (let i =
|
|
165
|
+
function detectSectionBaseIndentation(lines, sectionStartLine, sectionEndLine) {
|
|
166
|
+
for (let i = sectionStartLine; i <= sectionEndLine; i++) {
|
|
163
167
|
const line = lines[i];
|
|
164
168
|
const trimmed = line.trim();
|
|
165
169
|
if (trimmed === "")
|
|
@@ -169,7 +173,7 @@ function detectListIndentation(lines, insertLineIndex, sectionStartLine) {
|
|
|
169
173
|
const indent = listMatch[1] || listMatch[2] || listMatch[3] || "";
|
|
170
174
|
return indent;
|
|
171
175
|
}
|
|
172
|
-
if (trimmed.match(/^#+\s/)) {
|
|
176
|
+
if (i > sectionStartLine && trimmed.match(/^#+\s/)) {
|
|
173
177
|
break;
|
|
174
178
|
}
|
|
175
179
|
}
|
|
@@ -212,7 +216,7 @@ function insertInSection(content, section, newContent, position, options) {
|
|
|
212
216
|
}
|
|
213
217
|
if (lastContentLineIdx >= section.contentStartLine && isEmptyPlaceholder(lines[lastContentLineIdx])) {
|
|
214
218
|
if (options?.preserveListNesting) {
|
|
215
|
-
const indent =
|
|
219
|
+
const indent = detectSectionBaseIndentation(lines, section.contentStartLine, section.endLine);
|
|
216
220
|
const indentedContent = formattedContent.split("\n").map((line) => indent + line).join("\n");
|
|
217
221
|
lines[lastContentLineIdx] = indentedContent;
|
|
218
222
|
} else {
|
|
@@ -231,7 +235,7 @@ function insertInSection(content, section, newContent, position, options) {
|
|
|
231
235
|
insertLine = section.contentStartLine;
|
|
232
236
|
}
|
|
233
237
|
if (options?.preserveListNesting) {
|
|
234
|
-
const indent =
|
|
238
|
+
const indent = detectSectionBaseIndentation(lines, section.contentStartLine, section.endLine);
|
|
235
239
|
const indentedContent = formattedContent.split("\n").map((line) => indent + line).join("\n");
|
|
236
240
|
lines.splice(insertLine, 0, indentedContent);
|
|
237
241
|
} else {
|
|
@@ -510,9 +514,12 @@ async function undoLastCommit(vaultPath2) {
|
|
|
510
514
|
import {
|
|
511
515
|
scanVaultEntities,
|
|
512
516
|
getAllEntities,
|
|
517
|
+
getEntityName,
|
|
518
|
+
getEntityAliases,
|
|
513
519
|
applyWikilinks,
|
|
514
520
|
loadEntityCache,
|
|
515
|
-
saveEntityCache
|
|
521
|
+
saveEntityCache,
|
|
522
|
+
ENTITY_CACHE_VERSION
|
|
516
523
|
} from "@velvetmonkey/vault-core";
|
|
517
524
|
import path4 from "path";
|
|
518
525
|
|
|
@@ -1411,6 +1418,12 @@ async function initializeEntityIndex(vaultPath2) {
|
|
|
1411
1418
|
try {
|
|
1412
1419
|
const cached = await loadEntityCache(cacheFile);
|
|
1413
1420
|
if (cached) {
|
|
1421
|
+
const cacheVersion = cached._metadata.version ?? 1;
|
|
1422
|
+
if (cacheVersion < ENTITY_CACHE_VERSION) {
|
|
1423
|
+
console.error(`[Crank] Cache version ${cacheVersion} < ${ENTITY_CACHE_VERSION}, rebuilding...`);
|
|
1424
|
+
await rebuildIndex(vaultPath2, cacheFile);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1414
1427
|
entityIndex = cached;
|
|
1415
1428
|
indexReady = true;
|
|
1416
1429
|
console.error(`[Crank] Loaded ${cached._metadata.total_entities} entities from cache`);
|
|
@@ -1569,33 +1582,59 @@ var STRICTNESS_CONFIGS = {
|
|
|
1569
1582
|
var DEFAULT_STRICTNESS = "conservative";
|
|
1570
1583
|
var MIN_SUGGESTION_SCORE = STRICTNESS_CONFIGS.balanced.minSuggestionScore;
|
|
1571
1584
|
var MIN_MATCH_RATIO = STRICTNESS_CONFIGS.balanced.minMatchRatio;
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1585
|
+
var FULL_ALIAS_MATCH_BONUS = 8;
|
|
1586
|
+
function scoreNameAgainstContent(name, contentTokens, contentStems, config) {
|
|
1587
|
+
const nameTokens = tokenize(name);
|
|
1588
|
+
if (nameTokens.length === 0) {
|
|
1589
|
+
return { score: 0, matchedWords: 0, exactMatches: 0, totalTokens: 0 };
|
|
1590
|
+
}
|
|
1591
|
+
const nameStems = nameTokens.map((t) => stem(t));
|
|
1577
1592
|
let score = 0;
|
|
1578
1593
|
let matchedWords = 0;
|
|
1579
1594
|
let exactMatches = 0;
|
|
1580
|
-
for (let i = 0; i <
|
|
1581
|
-
const token =
|
|
1582
|
-
const
|
|
1595
|
+
for (let i = 0; i < nameTokens.length; i++) {
|
|
1596
|
+
const token = nameTokens[i];
|
|
1597
|
+
const nameStem = nameStems[i];
|
|
1583
1598
|
if (contentTokens.has(token)) {
|
|
1584
1599
|
score += config.exactMatchBonus;
|
|
1585
1600
|
matchedWords++;
|
|
1586
1601
|
exactMatches++;
|
|
1587
|
-
} else if (contentStems.has(
|
|
1602
|
+
} else if (contentStems.has(nameStem)) {
|
|
1588
1603
|
score += config.stemMatchBonus;
|
|
1589
1604
|
matchedWords++;
|
|
1590
1605
|
}
|
|
1591
1606
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1607
|
+
return { score, matchedWords, exactMatches, totalTokens: nameTokens.length };
|
|
1608
|
+
}
|
|
1609
|
+
function scoreEntity(entity, contentTokens, contentStems, config) {
|
|
1610
|
+
const entityName = getEntityName(entity);
|
|
1611
|
+
const aliases = getEntityAliases(entity);
|
|
1612
|
+
const nameResult = scoreNameAgainstContent(entityName, contentTokens, contentStems, config);
|
|
1613
|
+
let bestAliasResult = { score: 0, matchedWords: 0, exactMatches: 0, totalTokens: 0 };
|
|
1614
|
+
for (const alias of aliases) {
|
|
1615
|
+
const aliasResult = scoreNameAgainstContent(alias, contentTokens, contentStems, config);
|
|
1616
|
+
if (aliasResult.score > bestAliasResult.score) {
|
|
1617
|
+
bestAliasResult = aliasResult;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
const bestResult = nameResult.score >= bestAliasResult.score ? nameResult : bestAliasResult;
|
|
1621
|
+
let { score, matchedWords, exactMatches, totalTokens } = bestResult;
|
|
1622
|
+
if (totalTokens === 0)
|
|
1623
|
+
return 0;
|
|
1624
|
+
for (const alias of aliases) {
|
|
1625
|
+
const aliasLower = alias.toLowerCase();
|
|
1626
|
+
if (aliasLower.length >= 4 && !/\s/.test(aliasLower) && contentTokens.has(aliasLower)) {
|
|
1627
|
+
score += FULL_ALIAS_MATCH_BONUS;
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
if (totalTokens > 1) {
|
|
1632
|
+
const matchRatio = matchedWords / totalTokens;
|
|
1594
1633
|
if (matchRatio < config.minMatchRatio) {
|
|
1595
1634
|
return 0;
|
|
1596
1635
|
}
|
|
1597
1636
|
}
|
|
1598
|
-
if (config.requireMultipleMatches &&
|
|
1637
|
+
if (config.requireMultipleMatches && totalTokens === 1) {
|
|
1599
1638
|
if (exactMatches === 0) {
|
|
1600
1639
|
return 0;
|
|
1601
1640
|
}
|
|
@@ -1628,7 +1667,7 @@ function suggestRelatedLinks(content, options = {}) {
|
|
|
1628
1667
|
const scoredEntities = [];
|
|
1629
1668
|
const directlyMatchedEntities = /* @__PURE__ */ new Set();
|
|
1630
1669
|
for (const entity of entities) {
|
|
1631
|
-
const entityName =
|
|
1670
|
+
const entityName = getEntityName(entity);
|
|
1632
1671
|
if (!entityName)
|
|
1633
1672
|
continue;
|
|
1634
1673
|
if (entityName.length > MAX_ENTITY_LENGTH) {
|
|
@@ -1640,7 +1679,7 @@ function suggestRelatedLinks(content, options = {}) {
|
|
|
1640
1679
|
if (linkedEntities.has(entityName.toLowerCase())) {
|
|
1641
1680
|
continue;
|
|
1642
1681
|
}
|
|
1643
|
-
const score = scoreEntity(
|
|
1682
|
+
const score = scoreEntity(entity, contentTokens, contentStems, config);
|
|
1644
1683
|
if (score > 0) {
|
|
1645
1684
|
directlyMatchedEntities.add(entityName);
|
|
1646
1685
|
}
|
|
@@ -1650,7 +1689,7 @@ function suggestRelatedLinks(content, options = {}) {
|
|
|
1650
1689
|
}
|
|
1651
1690
|
if (cooccurrenceIndex && directlyMatchedEntities.size > 0) {
|
|
1652
1691
|
for (const entity of entities) {
|
|
1653
|
-
const entityName =
|
|
1692
|
+
const entityName = getEntityName(entity);
|
|
1654
1693
|
if (!entityName)
|
|
1655
1694
|
continue;
|
|
1656
1695
|
if (entityName.length > MAX_ENTITY_LENGTH)
|
|
@@ -1710,8 +1749,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1710
1749
|
const result2 = {
|
|
1711
1750
|
success: false,
|
|
1712
1751
|
message: `File not found: ${notePath}`,
|
|
1713
|
-
path: notePath
|
|
1752
|
+
path: notePath,
|
|
1753
|
+
tokensEstimate: 0
|
|
1714
1754
|
};
|
|
1755
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1715
1756
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1716
1757
|
}
|
|
1717
1758
|
const { content: fileContent, frontmatter } = await readVaultFile(vaultPath2, notePath);
|
|
@@ -1720,8 +1761,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1720
1761
|
const result2 = {
|
|
1721
1762
|
success: false,
|
|
1722
1763
|
message: `Section not found: ${section}`,
|
|
1723
|
-
path: notePath
|
|
1764
|
+
path: notePath,
|
|
1765
|
+
tokensEstimate: 0
|
|
1724
1766
|
};
|
|
1767
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1725
1768
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1726
1769
|
}
|
|
1727
1770
|
let { content: processedContent, wikilinkInfo } = maybeApplyWikilinks(content, skipWikilinks);
|
|
@@ -1761,15 +1804,20 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1761
1804
|
path: notePath,
|
|
1762
1805
|
preview,
|
|
1763
1806
|
gitCommit,
|
|
1764
|
-
gitError
|
|
1807
|
+
gitError,
|
|
1808
|
+
tokensEstimate: 0
|
|
1809
|
+
// Will be set below
|
|
1765
1810
|
};
|
|
1811
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1766
1812
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1767
1813
|
} catch (error) {
|
|
1768
1814
|
const result = {
|
|
1769
1815
|
success: false,
|
|
1770
1816
|
message: `Failed to add content: ${error instanceof Error ? error.message : String(error)}`,
|
|
1771
|
-
path: notePath
|
|
1817
|
+
path: notePath,
|
|
1818
|
+
tokensEstimate: 0
|
|
1772
1819
|
};
|
|
1820
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1773
1821
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1774
1822
|
}
|
|
1775
1823
|
}
|
|
@@ -1794,8 +1842,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1794
1842
|
const result2 = {
|
|
1795
1843
|
success: false,
|
|
1796
1844
|
message: `File not found: ${notePath}`,
|
|
1797
|
-
path: notePath
|
|
1845
|
+
path: notePath,
|
|
1846
|
+
tokensEstimate: 0
|
|
1798
1847
|
};
|
|
1848
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1799
1849
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1800
1850
|
}
|
|
1801
1851
|
const { content: fileContent, frontmatter } = await readVaultFile(vaultPath2, notePath);
|
|
@@ -1804,8 +1854,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1804
1854
|
const result2 = {
|
|
1805
1855
|
success: false,
|
|
1806
1856
|
message: `Section not found: ${section}`,
|
|
1807
|
-
path: notePath
|
|
1857
|
+
path: notePath,
|
|
1858
|
+
tokensEstimate: 0
|
|
1808
1859
|
};
|
|
1860
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1809
1861
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1810
1862
|
}
|
|
1811
1863
|
const removeResult = removeFromSection(
|
|
@@ -1819,8 +1871,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1819
1871
|
const result2 = {
|
|
1820
1872
|
success: false,
|
|
1821
1873
|
message: `No content matching "${pattern}" found in section "${sectionBoundary.name}"`,
|
|
1822
|
-
path: notePath
|
|
1874
|
+
path: notePath,
|
|
1875
|
+
tokensEstimate: 0
|
|
1823
1876
|
};
|
|
1877
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1824
1878
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1825
1879
|
}
|
|
1826
1880
|
await writeVaultFile(vaultPath2, notePath, removeResult.content, frontmatter);
|
|
@@ -1840,15 +1894,19 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1840
1894
|
path: notePath,
|
|
1841
1895
|
preview: removeResult.removedLines.join("\n"),
|
|
1842
1896
|
gitCommit,
|
|
1843
|
-
gitError
|
|
1897
|
+
gitError,
|
|
1898
|
+
tokensEstimate: 0
|
|
1844
1899
|
};
|
|
1900
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1845
1901
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1846
1902
|
} catch (error) {
|
|
1847
1903
|
const result = {
|
|
1848
1904
|
success: false,
|
|
1849
1905
|
message: `Failed to remove content: ${error instanceof Error ? error.message : String(error)}`,
|
|
1850
|
-
path: notePath
|
|
1906
|
+
path: notePath,
|
|
1907
|
+
tokensEstimate: 0
|
|
1851
1908
|
};
|
|
1909
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1852
1910
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1853
1911
|
}
|
|
1854
1912
|
}
|
|
@@ -1877,8 +1935,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1877
1935
|
const result2 = {
|
|
1878
1936
|
success: false,
|
|
1879
1937
|
message: `File not found: ${notePath}`,
|
|
1880
|
-
path: notePath
|
|
1938
|
+
path: notePath,
|
|
1939
|
+
tokensEstimate: 0
|
|
1881
1940
|
};
|
|
1941
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1882
1942
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1883
1943
|
}
|
|
1884
1944
|
const { content: fileContent, frontmatter } = await readVaultFile(vaultPath2, notePath);
|
|
@@ -1887,8 +1947,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1887
1947
|
const result2 = {
|
|
1888
1948
|
success: false,
|
|
1889
1949
|
message: `Section not found: ${section}`,
|
|
1890
|
-
path: notePath
|
|
1950
|
+
path: notePath,
|
|
1951
|
+
tokensEstimate: 0
|
|
1891
1952
|
};
|
|
1953
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1892
1954
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1893
1955
|
}
|
|
1894
1956
|
let { content: processedReplacement, wikilinkInfo } = maybeApplyWikilinks(replacement, skipWikilinks);
|
|
@@ -1912,8 +1974,10 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1912
1974
|
const result2 = {
|
|
1913
1975
|
success: false,
|
|
1914
1976
|
message: `No content matching "${search}" found in section "${sectionBoundary.name}"`,
|
|
1915
|
-
path: notePath
|
|
1977
|
+
path: notePath,
|
|
1978
|
+
tokensEstimate: 0
|
|
1916
1979
|
};
|
|
1980
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
1917
1981
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
1918
1982
|
}
|
|
1919
1983
|
await writeVaultFile(vaultPath2, notePath, replaceResult.content, frontmatter);
|
|
@@ -1937,15 +2001,19 @@ function registerMutationTools(server2, vaultPath2) {
|
|
|
1937
2001
|
path: notePath,
|
|
1938
2002
|
preview: previewLines.join("\n"),
|
|
1939
2003
|
gitCommit,
|
|
1940
|
-
gitError
|
|
2004
|
+
gitError,
|
|
2005
|
+
tokensEstimate: 0
|
|
1941
2006
|
};
|
|
2007
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1942
2008
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1943
2009
|
} catch (error) {
|
|
1944
2010
|
const result = {
|
|
1945
2011
|
success: false,
|
|
1946
2012
|
message: `Failed to replace content: ${error instanceof Error ? error.message : String(error)}`,
|
|
1947
|
-
path: notePath
|
|
2013
|
+
path: notePath,
|
|
2014
|
+
tokensEstimate: 0
|
|
1948
2015
|
};
|
|
2016
|
+
result.tokensEstimate = estimateTokens(result);
|
|
1949
2017
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1950
2018
|
}
|
|
1951
2019
|
}
|
|
@@ -2019,8 +2087,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2019
2087
|
const result2 = {
|
|
2020
2088
|
success: false,
|
|
2021
2089
|
message: `File not found: ${notePath}`,
|
|
2022
|
-
path: notePath
|
|
2090
|
+
path: notePath,
|
|
2091
|
+
tokensEstimate: 0
|
|
2023
2092
|
};
|
|
2093
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2024
2094
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2025
2095
|
}
|
|
2026
2096
|
const { content: fileContent, frontmatter } = await readVaultFile(vaultPath2, notePath);
|
|
@@ -2031,8 +2101,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2031
2101
|
const result2 = {
|
|
2032
2102
|
success: false,
|
|
2033
2103
|
message: `Section not found: ${section}`,
|
|
2034
|
-
path: notePath
|
|
2104
|
+
path: notePath,
|
|
2105
|
+
tokensEstimate: 0
|
|
2035
2106
|
};
|
|
2107
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2036
2108
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2037
2109
|
}
|
|
2038
2110
|
sectionBoundary = found;
|
|
@@ -2046,8 +2118,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2046
2118
|
const result2 = {
|
|
2047
2119
|
success: false,
|
|
2048
2120
|
message: `No task found matching "${task}"${section ? ` in section "${section}"` : ""}`,
|
|
2049
|
-
path: notePath
|
|
2121
|
+
path: notePath,
|
|
2122
|
+
tokensEstimate: 0
|
|
2050
2123
|
};
|
|
2124
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2051
2125
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2052
2126
|
}
|
|
2053
2127
|
const toggleResult = toggleTask(fileContent, matchingTask.line);
|
|
@@ -2055,8 +2129,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2055
2129
|
const result2 = {
|
|
2056
2130
|
success: false,
|
|
2057
2131
|
message: "Failed to toggle task",
|
|
2058
|
-
path: notePath
|
|
2132
|
+
path: notePath,
|
|
2133
|
+
tokensEstimate: 0
|
|
2059
2134
|
};
|
|
2135
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2060
2136
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2061
2137
|
}
|
|
2062
2138
|
await writeVaultFile(vaultPath2, notePath, toggleResult.content, frontmatter);
|
|
@@ -2078,15 +2154,19 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2078
2154
|
path: notePath,
|
|
2079
2155
|
preview: `${checkbox} ${matchingTask.text}`,
|
|
2080
2156
|
gitCommit,
|
|
2081
|
-
gitError
|
|
2157
|
+
gitError,
|
|
2158
|
+
tokensEstimate: 0
|
|
2082
2159
|
};
|
|
2160
|
+
result.tokensEstimate = estimateTokens(result);
|
|
2083
2161
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
2084
2162
|
} catch (error) {
|
|
2085
2163
|
const result = {
|
|
2086
2164
|
success: false,
|
|
2087
2165
|
message: `Failed to toggle task: ${error instanceof Error ? error.message : String(error)}`,
|
|
2088
|
-
path: notePath
|
|
2166
|
+
path: notePath,
|
|
2167
|
+
tokensEstimate: 0
|
|
2089
2168
|
};
|
|
2169
|
+
result.tokensEstimate = estimateTokens(result);
|
|
2090
2170
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
2091
2171
|
}
|
|
2092
2172
|
}
|
|
@@ -2115,8 +2195,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2115
2195
|
const result2 = {
|
|
2116
2196
|
success: false,
|
|
2117
2197
|
message: `File not found: ${notePath}`,
|
|
2118
|
-
path: notePath
|
|
2198
|
+
path: notePath,
|
|
2199
|
+
tokensEstimate: 0
|
|
2119
2200
|
};
|
|
2201
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2120
2202
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2121
2203
|
}
|
|
2122
2204
|
const { content: fileContent, frontmatter } = await readVaultFile(vaultPath2, notePath);
|
|
@@ -2125,8 +2207,10 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2125
2207
|
const result2 = {
|
|
2126
2208
|
success: false,
|
|
2127
2209
|
message: `Section not found: ${section}`,
|
|
2128
|
-
path: notePath
|
|
2210
|
+
path: notePath,
|
|
2211
|
+
tokensEstimate: 0
|
|
2129
2212
|
};
|
|
2213
|
+
result2.tokensEstimate = estimateTokens(result2);
|
|
2130
2214
|
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
2131
2215
|
}
|
|
2132
2216
|
let { content: processedTask, wikilinkInfo } = maybeApplyWikilinks(task.trim(), skipWikilinks);
|
|
@@ -2166,15 +2250,19 @@ function registerTaskTools(server2, vaultPath2) {
|
|
|
2166
2250
|
preview: taskLine + (infoLines.length > 0 ? `
|
|
2167
2251
|
(${infoLines.join("; ")})` : ""),
|
|
2168
2252
|
gitCommit,
|
|
2169
|
-
gitError
|
|
2253
|
+
gitError,
|
|
2254
|
+
tokensEstimate: 0
|
|
2170
2255
|
};
|
|
2256
|
+
result.tokensEstimate = estimateTokens(result);
|
|
2171
2257
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
2172
2258
|
} catch (error) {
|
|
2173
2259
|
const result = {
|
|
2174
2260
|
success: false,
|
|
2175
2261
|
message: `Failed to add task: ${error instanceof Error ? error.message : String(error)}`,
|
|
2176
|
-
path: notePath
|
|
2262
|
+
path: notePath,
|
|
2263
|
+
tokensEstimate: 0
|
|
2177
2264
|
};
|
|
2265
|
+
result.tokensEstimate = estimateTokens(result);
|
|
2178
2266
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
2179
2267
|
}
|
|
2180
2268
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/flywheel-crank",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Deterministic vault mutations for Obsidian via MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
44
|
-
"@velvetmonkey/vault-core": "^0.
|
|
44
|
+
"@velvetmonkey/vault-core": "^0.2.0",
|
|
45
45
|
"gray-matter": "^4.0.3",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
46
|
+
"simple-git": "^3.22.0",
|
|
47
|
+
"zod": "^3.22.4"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/node": "^20.10.0",
|