driggsby 0.9.0 → 0.9.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.
@@ -117,7 +117,8 @@ async function runStart(session, options, io) {
117
117
  }
118
118
  return renderStatus(view, {
119
119
  compact: options.wait && startedIn === "categorizing",
120
- repeated: target.kind === "file" && !created && given === null,
120
+ // Found already this far: a wait that watched it land shows it in full.
121
+ repeated: target.kind === "file" && !created && given === null && view.state === startedIn,
121
122
  unchanged: outcome.note !== null,
122
123
  rerun: { file: typedFile, account: options.account, create: options.create },
123
124
  }, context(io));
@@ -60,7 +60,9 @@ function statusBody(view, options, context) {
60
60
  case "waiting":
61
61
  return ok(renderQuestion(view));
62
62
  case "categorizing":
63
- return ok(options.compact ? categorizingLine(view) : landed(view, "Imported"));
63
+ if (options.compact)
64
+ return ok(categorizingLine(view));
65
+ return ok(options.repeated ? alreadyImported(view) : landed(view, "Imported"));
64
66
  case "done":
65
67
  return ok(done(view, options, context));
66
68
  case "stopped":
@@ -136,10 +138,15 @@ export function renderQuestion(view) {
136
138
  export function choiceLines(choices, command) {
137
139
  return `${choices.map((choice) => ` ${name(choice.label)}\n ${command(choice)}`).join("\n")}\n`;
138
140
  }
141
+ // One transaction "is", any other count "are".
142
+ function be(count) {
143
+ return count === 1 ? "is" : "are";
144
+ }
139
145
  // The transactions are in: what landed, then what's left to do.
140
146
  function landed(view, headline) {
141
- const where = view.account === null ? " landed" : ` are in ${name(view.account)}`;
142
- const top = `${headline}: ${plural(view.counts?.new ?? 0, "transaction")} from ${name(view.file)}${where}.`;
147
+ const count = view.counts?.new ?? 0;
148
+ const where = view.account === null ? " landed" : ` ${be(count)} in ${name(view.account)}`;
149
+ const top = `${headline}: ${plural(count, "transaction")} from ${name(view.file)}${where}.`;
143
150
  const undoCommand = ` ${CLI} import undo ${view.ref}\n`;
144
151
  // A new account is the person's to name by its ID from here on.
145
152
  const again = view.newAccount && view.accountRef !== null ? `Next time, for this account:\n ${CLI} import <FILE> --account ${view.accountRef}\n\n` : "";
@@ -182,6 +189,14 @@ function progressText(view) {
182
189
  const left = progress.secondsLeft === null ? "" : `, ${timeLeft(progress.secondsLeft)}`;
183
190
  return `${progress.categorized.toLocaleString("en-US")} of ${progress.total.toLocaleString("en-US")} so far${left}`;
184
191
  }
192
+ // The same file sent again while categories fill in: it's already in, and
193
+ // this run imported nothing, so it never reads as a second import.
194
+ function alreadyImported(view) {
195
+ const count = view.counts?.new ?? 0;
196
+ const into = view.account === null ? " landed" : ` ${be(count)} in ${name(view.account)}`;
197
+ return (`Already imported: this file's ${plural(count, "transaction")}${into} (${view.ref}). Categories: ${progressText(view)}.\n\n` +
198
+ `${wrapProse("Nothing else to do unless you need the categories. To wait for them:")}\n ${waitCommand(view.ref)}\n`);
199
+ }
185
200
  function categorizingLine(view) {
186
201
  const progress = view.progress;
187
202
  const where = progress === null || progress.categorized === 0
@@ -194,14 +209,15 @@ function done(view, options, context) {
194
209
  const why = NOTHING_NEW[view.nothingNew] ?? "none of its transactions were new";
195
210
  return `Done: nothing new in ${name(view.file)}: ${why}.\n\nNothing else to do.\n`;
196
211
  }
212
+ const count = view.counts?.new ?? 0;
197
213
  // A wait that followed categorizing ends on how it went, even for a file
198
214
  // sent again.
199
215
  if (options.compact && view.categorized === false) {
200
- return (`Done: ${plural(view.counts?.new ?? 0, "transaction")} from ${name(view.file)} are in, but some couldn't be categorized.\n\n` +
216
+ return (`Done: ${plural(count, "transaction")} from ${name(view.file)} ${be(count)} in, but some couldn't be categorized.\n\n` +
201
217
  `${wrapProse("Those show as uncategorized. Nothing else to do: the import is finished.")}\n`);
202
218
  }
203
219
  if (options.compact) {
204
- return `Done: all ${plural(view.counts?.new ?? 0, "transaction")} from ${name(view.file)} are categorized.\n\nNothing else to do: the import is finished.\n`;
220
+ return `Done: ${count === 1 ? "the" : "all"} ${plural(count, "transaction")} from ${name(view.file)} ${be(count)} categorized.\n\nNothing else to do: the import is finished.\n`;
205
221
  }
206
222
  if (options.repeated) {
207
223
  const on = view.finishedAt === null ? "" : ` on ${shortDate(view.finishedAt, context)}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "driggsby",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Set up and build on Driggsby, the MCP server for personal finance.",
5
5
  "license": "Apache-2.0 AND OFL-1.1",
6
6
  "repository": {
@@ -30,7 +30,7 @@
30
30
  "node": ">=18"
31
31
  },
32
32
  "dependencies": {
33
- "@driggsby/deploy": "0.9.0",
34
- "@driggsby/sdk": "0.9.0"
33
+ "@driggsby/deploy": "0.9.1",
34
+ "@driggsby/sdk": "0.9.1"
35
35
  }
36
36
  }