@fuzzle/opencode-accountant 0.7.1-next.1 → 0.7.2-next.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.
@@ -118,8 +118,7 @@ The `import-pipeline` tool operates directly on the working directory:
118
118
  3. **Automatic Processing**: The tool:
119
119
  - Classifies CSV files by provider/currency (creates import contexts in `.memory/`)
120
120
  - Extracts required accounts from rules files and updates year journal
121
- - Validates all transactions have matching rules (dry run)
122
- - Imports transactions to the appropriate year journal
121
+ - Validates and imports transactions to the appropriate year journal
123
122
  - Reconciles closing balance (auto-detected from CSV metadata or data, or manual override)
124
123
  - CSV files move: `incoming/` → `pending/` → `done/`
125
124
  4. **After Pipeline**: All changes remain uncommitted in your working directory for inspection
@@ -193,8 +192,7 @@ The following are MCP tools available to you. Always call these tools directly -
193
192
  1. Classifies CSV files and creates import contexts (unless `skipClassify: true`)
194
193
  2. For each context (sequentially, fail-fast):
195
194
  - Extracts accounts from matched rules and updates year journal with declarations
196
- - Validates all transactions have matching rules (dry run)
197
- - Imports transactions to year journal, moves CSV from `pending/` to `done/`
195
+ - Validates and imports transactions to year journal, moves CSV from `pending/` to `done/`
198
196
  - Reconciles closing balance (auto-detected from CSV metadata/data or manual override)
199
197
  3. All changes remain uncommitted in the working directory
200
198
 
package/dist/index.js CHANGED
@@ -23667,28 +23667,6 @@ async function importStatements(directory, agent, options, configLoader = loadIm
23667
23667
  }
23668
23668
  const hasUnknowns = totalUnknown > 0;
23669
23669
  const hasErrors = filesWithErrors > 0 || filesWithoutRules > 0;
23670
- if (options.checkOnly !== false) {
23671
- const result = {
23672
- success: !hasUnknowns && !hasErrors,
23673
- files: fileResults,
23674
- summary: {
23675
- filesProcessed: fileResults.length,
23676
- filesWithErrors,
23677
- filesWithoutRules,
23678
- totalTransactions,
23679
- matched: totalMatched,
23680
- unknown: totalUnknown
23681
- }
23682
- };
23683
- if (hasUnknowns) {
23684
- result.message = `Found ${totalUnknown} transaction(s) with unknown accounts. Add rules to categorize them.`;
23685
- } else if (hasErrors) {
23686
- result.message = `Some files had errors. Check the file results for details.`;
23687
- } else {
23688
- result.message = "All transactions matched. Ready to import with checkOnly: false";
23689
- }
23690
- return JSON.stringify(result);
23691
- }
23692
23670
  if (hasUnknowns || hasErrors) {
23693
23671
  return buildErrorResultWithDetails("Cannot import: some transactions have unknown accounts or files have errors", fileResults, {
23694
23672
  filesProcessed: fileResults.length,
@@ -23697,7 +23675,7 @@ async function importStatements(directory, agent, options, configLoader = loadIm
23697
23675
  totalTransactions,
23698
23676
  matched: totalMatched,
23699
23677
  unknown: totalUnknown
23700
- }, "Run with checkOnly: true to see details, then add missing rules");
23678
+ }, "Add missing rules to categorize unknown transactions, then retry");
23701
23679
  }
23702
23680
  const importResult = await executeImports(fileResults, directory, pendingDir, doneDir, hledgerExecutor);
23703
23681
  if (!importResult.success) {
@@ -23737,32 +23715,19 @@ var import_statements_default = tool({
23737
23715
 
23738
23716
  This tool processes CSV files in the pending import directory and uses hledger's CSV import capabilities with matching rules files.
23739
23717
 
23740
- **Check Mode (checkOnly: true, default):**
23741
- - Runs hledger print to preview transactions
23742
- - Identifies transactions with 'income:unknown' or 'expenses:unknown' accounts
23743
- - These indicate missing rules that need to be added
23744
-
23745
- **Import Mode (checkOnly: false):**
23746
- - First validates all transactions have known accounts
23747
- - If any unknowns exist, aborts and reports them
23718
+ **Behavior:**
23719
+ - First validates all transactions have known accounts (runs hledger print)
23720
+ - If any 'income:unknown' or 'expenses:unknown' accounts found, aborts and reports them
23748
23721
  - If all clean, imports transactions and moves CSVs to done directory
23749
23722
 
23750
- **Workflow:**
23751
- 1. Run with checkOnly: true (or no args)
23752
- 2. If unknowns found, add rules to the appropriate .rules file
23753
- 3. Repeat until no unknowns
23754
- 4. Run with checkOnly: false to import
23755
-
23756
23723
  Note: This tool is typically called via import-pipeline for the full workflow.`,
23757
23724
  args: {
23758
- contextId: tool.schema.string().describe("Context ID from classify step. Used to locate the specific CSV file to process."),
23759
- checkOnly: tool.schema.boolean().optional().describe("If true (default), only check for unknown accounts without importing. Set to false to perform actual import.")
23725
+ contextId: tool.schema.string().describe("Context ID from classify step. Used to locate the specific CSV file to process.")
23760
23726
  },
23761
23727
  async execute(params, context) {
23762
23728
  const { directory, agent } = context;
23763
23729
  return importStatements(directory, agent, {
23764
- contextId: params.contextId,
23765
- checkOnly: params.checkOnly
23730
+ contextId: params.contextId
23766
23731
  });
23767
23732
  }
23768
23733
  });
@@ -25020,61 +24985,6 @@ async function buildSuggestionContext(context, contextId, logger) {
25020
24985
  logger
25021
24986
  };
25022
24987
  }
25023
- async function executeDryRunStep(context, contextId, logger) {
25024
- logger?.startSection("Step 3: Dry Run Import");
25025
- logger?.logStep("Dry Run", "start");
25026
- const dryRunResult = await importStatements(context.directory, context.agent, {
25027
- contextId,
25028
- checkOnly: true
25029
- }, context.configLoader, context.hledgerExecutor);
25030
- const dryRunParsed = JSON.parse(dryRunResult);
25031
- const message = dryRunParsed.success ? `Dry run passed: ${dryRunParsed.summary?.totalTransactions || 0} transactions ready` : `Dry run failed: ${dryRunParsed.summary?.unknown || 0} unknown account(s)`;
25032
- logger?.logStep("Dry Run", dryRunParsed.success ? "success" : "error", message);
25033
- if (dryRunParsed.summary?.totalTransactions) {
25034
- logger?.info(`Found ${dryRunParsed.summary.totalTransactions} transactions`);
25035
- }
25036
- let postingsWithSuggestions = [];
25037
- if (!dryRunParsed.success) {
25038
- const allUnknownPostings = [];
25039
- for (const file2 of dryRunParsed.files ?? []) {
25040
- if (file2.unknownPostings && file2.unknownPostings.length > 0) {
25041
- allUnknownPostings.push(...file2.unknownPostings);
25042
- }
25043
- }
25044
- if (allUnknownPostings.length > 0) {
25045
- try {
25046
- const { suggestAccountsForPostingsBatch: suggestAccountsForPostingsBatch2 } = await Promise.resolve().then(() => (init_accountSuggester(), exports_accountSuggester));
25047
- const suggestionContext = await buildSuggestionContext(context, contextId, logger);
25048
- postingsWithSuggestions = await suggestAccountsForPostingsBatch2(allUnknownPostings, suggestionContext);
25049
- } catch (error45) {
25050
- logger?.error(`[ERROR] Failed to generate account suggestions: ${error45 instanceof Error ? error45.message : String(error45)}`);
25051
- postingsWithSuggestions = allUnknownPostings;
25052
- }
25053
- }
25054
- }
25055
- const detailsLog = postingsWithSuggestions.length > 0 ? formatUnknownPostingsLog(postingsWithSuggestions) : undefined;
25056
- context.result.steps.dryRun = buildStepResult(dryRunParsed.success, message, {
25057
- success: dryRunParsed.success,
25058
- summary: dryRunParsed.summary,
25059
- unknownPostings: postingsWithSuggestions.length > 0 ? postingsWithSuggestions : undefined,
25060
- detailsLog
25061
- });
25062
- if (!dryRunParsed.success) {
25063
- if (detailsLog) {
25064
- logger?.error("Dry run found unknown accounts or errors");
25065
- logger?.info(detailsLog);
25066
- }
25067
- logger?.endSection();
25068
- context.result.error = "Dry run found unknown accounts or errors";
25069
- context.result.hint = "Add rules to categorize unknown transactions, then retry. See details above for suggestions.";
25070
- throw new Error("Dry run failed");
25071
- }
25072
- if (dryRunParsed.summary?.totalTransactions === 0) {
25073
- logger?.endSection();
25074
- throw new NoTransactionsError;
25075
- }
25076
- logger?.endSection();
25077
- }
25078
24988
  function formatUnknownPostingsLog(postings) {
25079
24989
  if (postings.length === 0)
25080
24990
  return "";
@@ -25111,18 +25021,40 @@ function formatUnknownPostingsLog(postings) {
25111
25021
  }
25112
25022
  async function executeImportStep(context, contextId, logger) {
25113
25023
  const importContext = loadContext(context.directory, contextId);
25114
- logger?.startSection(`Step 4: Import Transactions (${importContext.accountNumber || contextId})`);
25024
+ logger?.startSection(`Step 3: Import Transactions (${importContext.accountNumber || contextId})`);
25115
25025
  logger?.logStep("Import", "start");
25116
25026
  const importResult = await importStatements(context.directory, context.agent, {
25117
- contextId,
25118
- checkOnly: false
25027
+ contextId
25119
25028
  }, context.configLoader, context.hledgerExecutor);
25120
25029
  const importParsed = JSON.parse(importResult);
25121
25030
  const message = importParsed.success ? `Imported ${importParsed.summary?.totalTransactions || 0} transactions` : `Import failed: ${importParsed.error || "Unknown error"}`;
25122
25031
  logger?.logStep("Import", importParsed.success ? "success" : "error", message);
25032
+ let postingsWithSuggestions;
25033
+ let detailsLog;
25034
+ if (!importParsed.success) {
25035
+ const allUnknownPostings = [];
25036
+ for (const file2 of importParsed.files ?? []) {
25037
+ if (file2.unknownPostings && file2.unknownPostings.length > 0) {
25038
+ allUnknownPostings.push(...file2.unknownPostings);
25039
+ }
25040
+ }
25041
+ if (allUnknownPostings.length > 0) {
25042
+ try {
25043
+ const { suggestAccountsForPostingsBatch: suggestAccountsForPostingsBatch2 } = await Promise.resolve().then(() => (init_accountSuggester(), exports_accountSuggester));
25044
+ const suggestionContext = await buildSuggestionContext(context, contextId, logger);
25045
+ postingsWithSuggestions = await suggestAccountsForPostingsBatch2(allUnknownPostings, suggestionContext);
25046
+ } catch (error45) {
25047
+ logger?.error(`[ERROR] Failed to generate account suggestions: ${error45 instanceof Error ? error45.message : String(error45)}`);
25048
+ postingsWithSuggestions = allUnknownPostings;
25049
+ }
25050
+ detailsLog = postingsWithSuggestions && postingsWithSuggestions.length > 0 ? formatUnknownPostingsLog(postingsWithSuggestions) : undefined;
25051
+ }
25052
+ }
25123
25053
  context.result.steps.import = buildStepResult(importParsed.success, message, {
25124
25054
  success: importParsed.success,
25125
25055
  summary: importParsed.summary,
25056
+ unknownPostings: postingsWithSuggestions,
25057
+ detailsLog,
25126
25058
  error: importParsed.error
25127
25059
  });
25128
25060
  if (importParsed.success) {
@@ -25133,16 +25065,26 @@ async function executeImportStep(context, contextId, logger) {
25133
25065
  });
25134
25066
  }
25135
25067
  if (!importParsed.success) {
25136
- logger?.error("Import failed", new Error(importParsed.error || "Unknown error"));
25068
+ if (detailsLog) {
25069
+ logger?.error("Import found unknown accounts or errors");
25070
+ logger?.info(detailsLog);
25071
+ } else {
25072
+ logger?.error("Import failed", new Error(importParsed.error || "Unknown error"));
25073
+ }
25137
25074
  logger?.endSection();
25138
- context.result.error = `Import failed: ${importParsed.error || "Unknown error"}`;
25075
+ context.result.error = detailsLog ? "Import found unknown accounts or errors" : `Import failed: ${importParsed.error || "Unknown error"}`;
25076
+ context.result.hint = detailsLog ? "Add rules to categorize unknown transactions, then retry. See details above for suggestions." : undefined;
25139
25077
  throw new Error("Import failed");
25140
25078
  }
25079
+ if (importParsed.summary?.totalTransactions === 0) {
25080
+ logger?.endSection();
25081
+ throw new NoTransactionsError;
25082
+ }
25141
25083
  logger?.endSection();
25142
25084
  }
25143
25085
  async function executeReconcileStep(context, contextId, logger) {
25144
25086
  const importContext = loadContext(context.directory, contextId);
25145
- logger?.startSection(`Step 5: Reconcile Balance (${importContext.accountNumber || contextId})`);
25087
+ logger?.startSection(`Step 4: Reconcile Balance (${importContext.accountNumber || contextId})`);
25146
25088
  logger?.logStep("Reconcile", "start");
25147
25089
  const reconcileResult = await reconcileStatement(context.directory, context.agent, {
25148
25090
  contextId,
@@ -25221,7 +25163,6 @@ async function importPipeline(directory, agent, options, configLoader = loadImpo
25221
25163
  const importContext = loadContext(context.directory, contextId);
25222
25164
  logger.info(`Processing: ${importContext.filename} (${importContext.accountNumber || "unknown account"})`);
25223
25165
  await executeAccountDeclarationsStep(context, contextId, logger);
25224
- await executeDryRunStep(context, contextId, logger);
25225
25166
  await executeImportStep(context, contextId, logger);
25226
25167
  await executeReconcileStep(context, contextId, logger);
25227
25168
  totalTransactions += context.result.steps.import?.details?.summary?.totalTransactions || 0;
@@ -25259,9 +25200,8 @@ This tool orchestrates the full import workflow:
25259
25200
  **Pipeline Steps:**
25260
25201
  1. **Classify**: Moves CSVs from import/incoming to import/pending (optional, skip with skipClassify)
25261
25202
  2. **Account Declarations**: Ensures all required accounts are declared in year journal
25262
- 3. **Dry Run**: Validates all transactions have known accounts
25263
- 4. **Import**: Imports transactions to the journal (moves CSVs to import/done)
25264
- 5. **Reconcile**: Validates closing balance matches CSV metadata
25203
+ 3. **Import**: Validates all transactions have known accounts, imports to journal (moves CSVs to import/done)
25204
+ 4. **Reconcile**: Validates closing balance matches CSV metadata
25265
25205
 
25266
25206
  **Important:**
25267
25207
  - All changes remain uncommitted in your working directory
@@ -12,9 +12,8 @@ The pipeline automates these sequential steps:
12
12
  1a. **Preprocess BTC CSV** _(Revolut only)_ - Add computed columns (fees in BTC, total, clean price) for hledger rules
13
13
  1b. **Generate BTC Purchases** _(Revolut only)_ - Cross-reference fiat + BTC CSVs for equity conversion entries
14
14
  2. **Account Declarations** - Ensure all accounts exist in year journals
15
- 3. **Dry Run** - Validate transactions, check for unknown accounts
16
- 4. **Import** - Add transactions to journals, move files to done
17
- 5. **Reconcile** - Verify balances match expectations
15
+ 3. **Import** - Validate transactions, add to journals, move files to done
16
+ 4. **Reconcile** - Verify balances match expectations
18
17
 
19
18
  Steps 1a and 1b are Revolut-specific and are automatically skipped when no Revolut BTC CSV is present.
20
19
 
@@ -49,10 +48,6 @@ When all steps complete successfully:
49
48
  "success": true,
50
49
  "message": "Account declarations complete"
51
50
  },
52
- "dryRun": {
53
- "success": true,
54
- "message": "Dry run complete - all transactions validated"
55
- },
56
51
  "import": {
57
52
  "success": true,
58
53
  "message": "Imported 42 transactions"
@@ -86,9 +81,9 @@ When the incoming directory is empty:
86
81
  }
87
82
  ```
88
83
 
89
- ### Failure - Unknown Accounts in Dry Run
84
+ ### Failure - Unknown Accounts in Import
90
85
 
91
- When dry run detects unknown accounts:
86
+ When import detects unknown accounts:
92
87
 
93
88
  ```json
94
89
  {
@@ -103,13 +98,13 @@ When dry run detects unknown accounts:
103
98
  "success": true,
104
99
  "message": "Account declarations complete"
105
100
  },
106
- "dryRun": {
101
+ "import": {
107
102
  "success": false,
108
- "message": "Dry run failed: 3 transactions with unknown accounts"
103
+ "message": "Import failed: 3 transactions with unknown accounts"
109
104
  }
110
105
  },
111
- "error": "Dry run validation failed: 3 transactions with unknown accounts",
112
- "hint": "Update rules file to categorize unknown transactions"
106
+ "error": "Import found unknown accounts or errors",
107
+ "hint": "Add rules to categorize unknown transactions, then retry. See details above for suggestions."
113
108
  }
114
109
  ```
115
110
 
@@ -124,7 +119,6 @@ When reconciliation fails:
124
119
  "steps": {
125
120
  "classify": { "success": true },
126
121
  "accountDeclarations": { "success": true },
127
- "dryRun": { "success": true },
128
122
  "import": { "success": true, "message": "Imported 42 transactions" },
129
123
  "reconcile": {
130
124
  "success": false,
@@ -206,34 +200,17 @@ See [classify-statements](classify-statements.md) for details.
206
200
  - Multiple years in single CSV
207
201
  - Cannot create year journal file
208
202
 
209
- ### Step 3: Dry Run
210
-
211
- **Purpose**: Validate all transactions can be categorized before importing
212
-
213
- **What happens** (per context):
214
-
215
- 1. Loads context to find CSV file
216
- 2. Runs `hledger print` with rules file
217
- 3. Checks for `income:unknown` or `expenses:unknown` accounts
218
- 4. Reports unknown postings if found
219
-
220
- **Failure scenarios**:
221
-
222
- - Unknown accounts detected → **Pipeline stops here**
223
- - CSV parsing errors
224
- - Rules file syntax errors
203
+ ### Step 3: Import
225
204
 
226
- **User action required**: Update rules file to categorize unknown transactions, then re-run pipeline.
227
-
228
- ### Step 4: Import
229
-
230
- **Purpose**: Add transactions to journal and mark files as processed
205
+ **Purpose**: Validate and add transactions to journal, mark files as processed
231
206
 
232
207
  **What happens** (per context):
233
208
 
234
209
  1. Loads context to find CSV file
235
- 2. Imports transactions using `hledger import`
236
- 3. Moves CSV from `pending/` to `done/`
210
+ 2. Validates all transactions have known accounts (checks for `income:unknown`/`expenses:unknown`)
211
+ 3. If unknown accounts found, generates account suggestions and **stops pipeline**
212
+ 4. Imports transactions using `hledger import`
213
+ 5. Moves CSV from `pending/` to `done/`
237
214
  4. Updates context with:
238
215
  - `rulesFile` path
239
216
  - `yearJournal` path
@@ -242,13 +219,14 @@ See [classify-statements](classify-statements.md) for details.
242
219
 
243
220
  **Failure scenarios**:
244
221
 
222
+ - Unknown accounts detected → **Pipeline stops here** with account suggestions
245
223
  - Duplicate transactions detected
246
224
  - Journal file write error
247
225
  - File move operation fails
248
226
 
249
227
  See [import-statements](import-statements.md) for details.
250
228
 
251
- ### Step 5: Reconcile
229
+ ### Step 4: Reconcile
252
230
 
253
231
  **Purpose**: Verify imported transactions result in correct closing balance
254
232
 
@@ -320,7 +298,7 @@ See [reconcile-statement](reconcile-statement.md) for details.
320
298
  │ │
321
299
  ▼ │
322
300
  ┌────────────────────────────────────────┐ │
323
- │ STEPS 2-5 (for uuid-1): │ │
301
+ │ STEPS 2-4 (for uuid-1): │ │
324
302
  │ • Account Declarations │ │
325
303
  │ • Dry Run │ │
326
304
  │ • Import │ │
@@ -331,10 +309,9 @@ See [reconcile-statement](reconcile-statement.md) for details.
331
309
  │ │
332
310
  │ ▼
333
311
  │ ┌────────────────────────────────────────┐
334
- │ │ STEPS 2-5 (for uuid-2): │
312
+ │ │ STEPS 2-4 (for uuid-2): │
335
313
  │ │ • Account Declarations │
336
- │ │ • Dry Run
337
- │ │ • Import │
314
+ │ • Import
338
315
  │ │ • Reconcile │
339
316
  │ │ • UPDATE: .memory/uuid-2.json │
340
317
  │ └────────────────────────────────────────┘
@@ -353,7 +330,7 @@ The pipeline processes contexts **one at a time**:
353
330
  ```
354
331
  for each contextId:
355
332
  1. Load context
356
- 2. Run steps 2-5 for this context
333
+ 2. Run steps 2-4 for this context
357
334
  3. If ANY step fails → STOP PIPELINE
358
335
  4. Update context with results
359
336
  5. Move to next context
@@ -417,8 +394,8 @@ classify-statements
417
394
  # Output: { "contexts": ["uuid-1", "uuid-2"] }
418
395
 
419
396
  # Import each manually
420
- import-statements --contextId "uuid-1" --checkOnly false
421
- import-statements --contextId "uuid-2" --checkOnly false
397
+ import-statements --contextId "uuid-1"
398
+ import-statements --contextId "uuid-2"
422
399
 
423
400
  # Reconcile with different balances
424
401
  reconcile-statement --contextId "uuid-1" --closingBalance "EUR 1000.00"
@@ -438,12 +415,12 @@ import-pipeline --skipClassify
438
415
  ### Scenario 5: Handling Unknown Accounts
439
416
 
440
417
  ```bash
441
- # First run: dry run fails
418
+ # First run: import fails with unknown accounts
442
419
  import-pipeline
443
- # Output: "Dry run failed: 3 transactions with unknown accounts"
420
+ # Output: "Import found unknown accounts or errors"
444
421
 
445
- # Check which transactions are unknown
446
- import-statements --contextId {from-output} --checkOnly true
422
+ # Check which transactions are unknown (details in pipeline output)
423
+ import-statements --contextId {from-output}
447
424
  # Shows unknown postings with suggestions
448
425
 
449
426
  # Update rules file
@@ -462,7 +439,7 @@ import-pipeline --skipClassify
462
439
  | ----------------------- | ------------------- | ----------------------------- | --------------------------------------------------- |
463
440
  | File collision | Classify | Target file already exists | Move existing file to done or delete |
464
441
  | Unrecognized CSV | Classify | Unknown provider | Add provider config or move to pending manually |
465
- | Unknown accounts | Dry Run | Transactions without rules | Update rules file to categorize |
442
+ | Unknown accounts | Import | Transactions without rules | Update rules file to categorize |
466
443
  | Balance mismatch | Reconcile | Missing transactions | Check skip rules, verify all transactions imported |
467
444
  | Context not found | Import/Reconcile | Invalid context ID | Re-run classify-statements |
468
445
  | Multi-year CSV | Account Declaration | CSV spans multiple years | Split CSV by year or import to single year manually |
@@ -481,9 +458,9 @@ The output shows which step failed:
481
458
  "steps": {
482
459
  "classify": { "success": true },
483
460
  "accountDeclarations": { "success": true },
484
- "dryRun": { "success": false } // ← Failed here
461
+ "import": { "success": false } // ← Failed here
485
462
  },
486
- "error": "Dry run validation failed..."
463
+ "error": "Import found unknown accounts or errors..."
487
464
  }
488
465
  ```
489
466
 
@@ -494,7 +471,7 @@ The output shows which step failed:
494
471
  # contexts: ["abc123-..."]
495
472
 
496
473
  # Run the failed step individually
497
- import-statements --contextId "abc123-..." --checkOnly true
474
+ import-statements --contextId "abc123-..."
498
475
  ```
499
476
 
500
477
  **Step 3: Fix issue and resume**
@@ -586,7 +563,7 @@ Context 3: classify → import → reconcile ✓
586
563
  The pipeline invokes these tools internally:
587
564
 
588
565
  1. `classify-statements` → Returns context IDs
589
- 2. `import-statements` (per context) → Updates contexts
566
+ 2. `import-statements` (per context) → Validates and imports, updates contexts
590
567
  3. `reconcile-statement` (per context) → Updates contexts
591
568
 
592
569
  ### Manual Tool Usage
@@ -598,11 +575,8 @@ You can run tools independently for more control:
598
575
  classify-statements
599
576
  # → Get contextIds
600
577
 
601
- import-statements --contextId {uuid} --checkOnly true
602
- # → Validate first
603
-
604
- import-statements --contextId {uuid} --checkOnly false
605
- # → Import
578
+ import-statements --contextId {uuid}
579
+ # → Validate and import
606
580
 
607
581
  reconcile-statement --contextId {uuid}
608
582
  # → Reconcile
@@ -631,11 +605,10 @@ For typical import (1-2 CSVs, 50-100 transactions each):
631
605
 
632
606
  - **Classify**: <1 second
633
607
  - **Account Declarations**: <1 second
634
- - **Dry Run**: 1-2 seconds (hledger processing)
635
- - **Import**: 1-2 seconds (hledger processing)
608
+ - **Import**: 1-2 seconds (hledger validation + import)
636
609
  - **Reconcile**: 1-2 seconds (hledger queries)
637
610
 
638
- **Total**: ~5-10 seconds per context
611
+ **Total**: ~3-6 seconds per context
639
612
 
640
613
  ### Scalability
641
614
 
@@ -652,5 +625,5 @@ If you regularly import 50+ CSVs, consider:
652
625
 
653
626
  - [Import Context Architecture](../architecture/import-context.md) - Deep dive into context system
654
627
  - [classify-statements Tool](classify-statements.md) - Step 1: Classification
655
- - [import-statements Tool](import-statements.md) - Step 4: Import
656
- - [reconcile-statement Tool](reconcile-statement.md) - Step 5: Reconciliation
628
+ - [import-statements Tool](import-statements.md) - Step 3: Import
629
+ - [reconcile-statement Tool](reconcile-statement.md) - Step 4: Reconciliation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzzle/opencode-accountant",
3
- "version": "0.7.1-next.1",
3
+ "version": "0.7.2-next.1",
4
4
  "description": "An OpenCode accounting agent, specialized in double-entry-bookkepping with hledger",
5
5
  "author": {
6
6
  "name": "ali bengali",