@fuzzle/opencode-accountant 0.1.3-next.1 → 0.1.3

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
@@ -199,15 +199,13 @@ The `import-pipeline` tool provides an atomic, safe import workflow using git wo
199
199
  2. Run `import-pipeline` tool with optional provider/currency filters
200
200
  3. The tool automatically:
201
201
  - Creates an isolated git worktree
202
- - Syncs CSV files from main repo to worktree
203
202
  - Classifies CSV files by provider/currency
204
203
  - Validates all transactions have matching rules
205
204
  - Imports transactions to the appropriate year journal
206
205
  - Reconciles closing balance (if available in CSV metadata)
207
206
  - Merges changes back to main branch with `--no-ff`
208
- - Deletes processed CSV files from main repo's import/incoming
209
207
  - Cleans up the worktree
210
- 4. If any step fails, the worktree is discarded and main branch remains untouched (CSV files are preserved for retry)
208
+ 4. If any step fails, the worktree is discarded and main branch remains untouched
211
209
 
212
210
  ### Statement Import
213
211
 
@@ -56,10 +56,10 @@ When working with accounting tasks:
56
56
 
57
57
  You have access to specialized MCP tools that MUST be used for their designated tasks. Do NOT attempt to replicate their functionality with bash commands, direct hledger CLI calls, or manual file edits.
58
58
 
59
- | Tool | Use For | NEVER Do Instead |
60
- | ----------------------- | ---------------------------------------------------- | --------------------------------------------------------- |
61
- | `import-pipeline` | Full import workflow (classify → import → reconcile) | Manual file moves, `hledger import`, manual journal edits |
62
- | `fetch-currency-prices` | Fetching exchange rates | `curl` to price APIs, manual price entries |
59
+ | Tool | Use For | NEVER Do Instead |
60
+ | ----------------- | ---------------------------------------------------- | --------------------------------------------------------- |
61
+ | `import-pipeline` | Full import workflow (classify → import → reconcile) | Manual file moves, `hledger import`, manual journal edits |
62
+ | `fetch-currency-prices` | Fetching exchange rates | `curl` to price APIs, manual price entries |
63
63
 
64
64
  These tools handle validation, deduplication, error checking, and file organization automatically. Bypassing them risks data corruption, duplicate transactions, and inconsistent state.
65
65
 
@@ -87,13 +87,11 @@ The `import-pipeline` tool provides an **atomic, safe workflow** using git workt
87
87
  1. **Prepare**: Drop CSV files into `{paths.import}` (configured in `config/import/providers.yaml`, default: `import/incoming`)
88
88
  2. **Run Pipeline**: Execute `import-pipeline` (optionally filter by `provider` and `currency`)
89
89
  3. **Automatic Processing**: The tool creates an isolated git worktree and:
90
- - Syncs CSV files from main repo to worktree
91
90
  - Classifies CSV files by provider/currency
92
91
  - Validates all transactions have matching rules
93
92
  - Imports transactions to the appropriate year journal
94
93
  - Reconciles closing balance (if available in CSV metadata)
95
94
  - Merges changes back to main branch with `--no-ff`
96
- - Deletes processed CSV files from main repo's import/incoming
97
95
  - Cleans up the worktree
98
96
  4. **Handle Failures**: If any step fails (e.g., unknown postings found):
99
97
  - Worktree is discarded, main branch remains untouched
@@ -136,14 +134,12 @@ The following are MCP tools available to you. Always call these tools directly -
136
134
  **Behavior:**
137
135
 
138
136
  1. Creates isolated git worktree
139
- 2. Syncs CSV files from main repo to worktree
140
- 3. Classifies CSV files (unless `skipClassify: true`)
141
- 4. Validates all transactions have matching rules (dry run)
142
- 5. Imports transactions to year journal
143
- 6. Reconciles closing balance against CSV metadata or manual value
144
- 7. Merges to main with `--no-ff` commit
145
- 8. Deletes processed CSV files from main repo's import/incoming
146
- 9. Cleans up worktree
137
+ 2. Classifies CSV files (unless `skipClassify: true`)
138
+ 3. Validates all transactions have matching rules (dry run)
139
+ 4. Imports transactions to year journal
140
+ 5. Reconciles closing balance against CSV metadata or manual value
141
+ 6. Merges to main with `--no-ff` commit
142
+ 7. Cleans up worktree
147
143
 
148
144
  **Output:** Returns step-by-step results with success/failure for each phase
149
145
 
package/dist/index.js CHANGED
@@ -17731,53 +17731,6 @@ function ensureDirectory(dirPath) {
17731
17731
  fs5.mkdirSync(dirPath, { recursive: true });
17732
17732
  }
17733
17733
  }
17734
- function syncCSVFilesToWorktree(mainRepoPath, worktreePath, importDir) {
17735
- const result = {
17736
- synced: [],
17737
- errors: []
17738
- };
17739
- const mainImportDir = path6.join(mainRepoPath, importDir);
17740
- const worktreeImportDir = path6.join(worktreePath, importDir);
17741
- const csvFiles = findCSVFiles(mainImportDir);
17742
- if (csvFiles.length === 0) {
17743
- return result;
17744
- }
17745
- ensureDirectory(worktreeImportDir);
17746
- for (const file2 of csvFiles) {
17747
- try {
17748
- const sourcePath = path6.join(mainImportDir, file2);
17749
- const destPath = path6.join(worktreeImportDir, file2);
17750
- fs5.copyFileSync(sourcePath, destPath);
17751
- result.synced.push(file2);
17752
- } catch (error45) {
17753
- const errorMsg = error45 instanceof Error ? error45.message : String(error45);
17754
- result.errors.push({ file: file2, error: errorMsg });
17755
- }
17756
- }
17757
- return result;
17758
- }
17759
- function cleanupProcessedCSVFiles(mainRepoPath, importDir) {
17760
- const result = {
17761
- deleted: [],
17762
- errors: []
17763
- };
17764
- const mainImportDir = path6.join(mainRepoPath, importDir);
17765
- const csvFiles = findCSVFiles(mainImportDir);
17766
- if (csvFiles.length === 0) {
17767
- return result;
17768
- }
17769
- for (const file2 of csvFiles) {
17770
- try {
17771
- const filePath = path6.join(mainImportDir, file2);
17772
- fs5.unlinkSync(filePath);
17773
- result.deleted.push(file2);
17774
- } catch (error45) {
17775
- const errorMsg = error45 instanceof Error ? error45.message : String(error45);
17776
- result.errors.push({ file: file2, error: errorMsg });
17777
- }
17778
- }
17779
- return result;
17780
- }
17781
17734
 
17782
17735
  // src/tools/classify-statements.ts
17783
17736
  function buildSuccessResult2(classified, unrecognized, message) {
@@ -19107,67 +19060,19 @@ async function importPipeline(directory, agent, options, configLoader = loadImpo
19107
19060
  path: worktree.path,
19108
19061
  branch: worktree.branch
19109
19062
  });
19110
- try {
19111
- const config2 = configLoader(directory);
19112
- const syncResult = syncCSVFilesToWorktree(directory, worktree.path, config2.paths.import);
19113
- if (syncResult.synced.length === 0 && syncResult.errors.length === 0) {
19114
- result.steps.sync = buildStepResult(true, "No CSV files to sync", {
19115
- synced: []
19116
- });
19117
- } else if (syncResult.errors.length > 0) {
19118
- result.steps.sync = buildStepResult(true, `Synced ${syncResult.synced.length} file(s) with ${syncResult.errors.length} error(s)`, { synced: syncResult.synced, errors: syncResult.errors });
19119
- } else {
19120
- result.steps.sync = buildStepResult(true, `Synced ${syncResult.synced.length} CSV file(s) to worktree`, { synced: syncResult.synced });
19121
- }
19122
- } catch (error45) {
19123
- const errorMsg = error45 instanceof Error ? error45.message : String(error45);
19124
- result.steps.sync = buildStepResult(false, `Failed to sync CSV files: ${errorMsg}`, { synced: [], errors: [{ file: "unknown", error: errorMsg }] });
19125
- }
19126
19063
  try {
19127
19064
  await executeClassifyStep(context, worktree);
19128
19065
  await executeDryRunStep(context, worktree);
19129
19066
  await executeImportStep(context, worktree);
19130
19067
  await executeReconcileStep(context, worktree);
19131
- try {
19132
- const config2 = configLoader(directory);
19133
- const cleanupResult = cleanupProcessedCSVFiles(directory, config2.paths.import);
19134
- if (cleanupResult.deleted.length === 0 && cleanupResult.errors.length === 0) {
19135
- result.steps.cleanup = buildStepResult(true, "No CSV files to cleanup", { csvCleanup: { deleted: [] } });
19136
- } else if (cleanupResult.errors.length > 0) {
19137
- result.steps.cleanup = buildStepResult(true, `Deleted ${cleanupResult.deleted.length} CSV file(s) with ${cleanupResult.errors.length} error(s)`, {
19138
- csvCleanup: {
19139
- deleted: cleanupResult.deleted,
19140
- errors: cleanupResult.errors
19141
- }
19142
- });
19143
- } else {
19144
- result.steps.cleanup = buildStepResult(true, `Deleted ${cleanupResult.deleted.length} CSV file(s) from main repo`, { csvCleanup: { deleted: cleanupResult.deleted } });
19145
- }
19146
- } catch (error45) {
19147
- const errorMsg = error45 instanceof Error ? error45.message : String(error45);
19148
- result.steps.cleanup = buildStepResult(false, `Failed to cleanup CSV files: ${errorMsg}`, {
19149
- csvCleanup: {
19150
- deleted: [],
19151
- errors: [{ file: "unknown", error: errorMsg }]
19152
- }
19153
- });
19154
- }
19155
19068
  await executeMergeStep(context, worktree);
19156
- const existingCleanup = result.steps.cleanup;
19157
- if (existingCleanup) {
19158
- existingCleanup.message += ", worktree cleaned up";
19159
- existingCleanup.details = {
19160
- ...existingCleanup.details,
19161
- cleanedAfterSuccess: true
19162
- };
19163
- }
19069
+ result.steps.cleanup = buildStepResult(true, "Worktree cleaned up", {
19070
+ cleanedAfterSuccess: true
19071
+ });
19164
19072
  const transactionCount = context.result.steps.import?.details?.summary?.totalTransactions || 0;
19165
19073
  return buildSuccessResult5(result, `Successfully imported ${transactionCount} transaction(s)`);
19166
19074
  } catch (error45) {
19167
- result.steps.cleanup = buildStepResult(true, "Worktree cleaned up after failure (CSV files preserved for retry)", {
19168
- cleanedAfterFailure: true,
19169
- csvCleanup: { deleted: [] }
19170
- });
19075
+ result.steps.cleanup = buildStepResult(true, "Worktree cleaned up after failure", { cleanedAfterFailure: true });
19171
19076
  if (error45 instanceof NoTransactionsError) {
19172
19077
  return handleNoTransactions(result);
19173
19078
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzzle/opencode-accountant",
3
- "version": "0.1.3-next.1",
3
+ "version": "0.1.3",
4
4
  "description": "An OpenCode accounting agent, specialized in double-entry-bookkepping with hledger",
5
5
  "author": {
6
6
  "name": "ali bengali",