actual-mcp-server 0.22.19 → 0.22.20

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 CHANGED
@@ -835,7 +835,7 @@ The software is provided **as-is**, without warranty of any kind. The author acc
835
835
 
836
836
  ---
837
837
 
838
- **Version:** 0.22.19 | **Tool Count:** 83 (verified LibreChat-compatible)
838
+ **Version:** 0.22.20 | **Tool Count:** 83 (verified LibreChat-compatible)
839
839
 
840
840
  ## Sponsor
841
841
 
@@ -1868,6 +1868,28 @@ export async function setBudgetAmount(month, categoryId, amount) {
1868
1868
  return result;
1869
1869
  }, { preservesListings: ['accounts', 'categories', 'categoryGroups', 'payees'] });
1870
1870
  }
1871
+ /**
1872
+ * Budget transfer between two categories within a single month.
1873
+ *
1874
+ * Reads the current budget amounts, validates source-side sufficient funds,
1875
+ * and writes both adjustments inside ONE `queueWriteOperation` cycle. This
1876
+ * is the structural fix for issue #141: the previous tool body did three
1877
+ * separate lock cycles (read + write + write) which could hang for the
1878
+ * full Playwright timeout when the upstream server's mutator queue stalled
1879
+ * between cycles. The month read and the funds check run before either write.
1880
+ *
1881
+ * NOT atomic and no rollback (#518). Both writes run inside
1882
+ * `rawBatchBudgetUpdates`, upstream's `batch-budget-start` /
1883
+ * `batch-budget-end` bracket around `batchMessages`, which batches sync
1884
+ * messages; it is not a database transaction. If the second write fails, the
1885
+ * first stays applied, so a partial transfer is possible. A returned result
1886
+ * means both writes were queued, not that both landed: `batch-budget-start`
1887
+ * runs `batchMessages` un-awaited and `batch-budget-end` returns before the
1888
+ * queued messages are applied, so a later apply failure is a detached
1889
+ * rejection that is never returned to the caller (#539). The upstream trace is the
1890
+ * `actual_budget_updates_batch` row of `docs/audit/write-effect-audit.md`,
1891
+ * which shares this bracket (#516).
1892
+ */
1871
1893
  export async function transferBudgetAmount(month, fromCategoryId, toCategoryId, amount) {
1872
1894
  observability.incrementToolCall('actual.budgets.transfer').catch(() => { });
1873
1895
  return queueWriteOperation(async () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "actual-mcp-server",
3
3
  "displayName": "Actual MCP Server",
4
- "version": "0.22.19",
4
+ "version": "0.22.20",
5
5
  "engines": {
6
6
  "node": ">=22.0.0",
7
7
  "npm": ">=10.0.0"