@slothmoney/agent-cli 0.7.0 → 0.8.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.8.0 - 2026-08-12
6
+
7
+ - Read each goal's one-based priority and move one goal to a new position with
8
+ automatic shifting of the intervening goals.
9
+
10
+ ## 0.7.0 - 2026-08-09
11
+
5
12
  - Read personal or joint budget periods with categories, line items, funding,
6
13
  and planned amounts.
7
14
  - Preview or apply planned line-item updates that overwrite the selected period
package/README.md CHANGED
@@ -15,7 +15,7 @@ sloth-agent --version
15
15
  For a one-off pinned run:
16
16
 
17
17
  ```bash
18
- npm exec --yes --package=@slothmoney/agent-cli@0.7.0 -- sloth-agent --help
18
+ npm exec --yes --package=@slothmoney/agent-cli@0.8.0 -- sloth-agent --help
19
19
  ```
20
20
 
21
21
  ## Authenticate
@@ -355,7 +355,7 @@ sloth-agent goals create \
355
355
  --apply
356
356
  ```
357
357
 
358
- Use the `id` from list or create output to update or delete a goal:
358
+ Use the `id` from list or create output to update or delete goals:
359
359
 
360
360
  ```bash
361
361
  sloth-agent goals update \
@@ -365,6 +365,11 @@ sloth-agent goals update \
365
365
  --achieved=false \
366
366
  --apply
367
367
 
368
+ sloth-agent goals update \
369
+ --goal-id house-goal-id \
370
+ --priority 2 \
371
+ --apply
372
+
368
373
  sloth-agent goals delete --goal-id goal-id --apply
369
374
  ```
370
375
 
@@ -373,7 +378,13 @@ remove an optional value. Marking a goal achieved removes its forecast
373
378
  assignment. Deleting a goal also removes its forecast assignments and drift
374
379
  history. Goal sharing remains app-managed. Change an active shared goal's
375
380
  pot-tracked target amount in the Sloth Budget app, where account balances can
376
- be reallocated across goals in priority order.
381
+ be reallocated across goals in priority order. Goal list output includes a
382
+ one-based `priority`; `1` is highest. Moving one goal automatically shifts the
383
+ goals between its old and new positions. The
384
+ priority option must be used on its own, and the write persists immediately.
385
+ Forecast assignments and shared pot
386
+ progress are browser-owned derived state and refresh when the owner next opens
387
+ the Forecast screen.
377
388
 
378
389
  Read uncategorised contributions to the joint budget:
379
390
 
package/dist/args.js CHANGED
@@ -64,6 +64,16 @@ function parseGoalMonthKey(value, name) {
64
64
  }
65
65
  return value;
66
66
  }
67
+ function parseGoalPriority(value) {
68
+ if (!/^[1-9]\d*$/.test(value)) {
69
+ throw new UsageError('--priority must be a positive whole-number position');
70
+ }
71
+ const priority = Number(value);
72
+ if (!Number.isSafeInteger(priority)) {
73
+ throw new UsageError('--priority must be a positive whole-number position');
74
+ }
75
+ return priority;
76
+ }
67
77
  function parseExplicitBoolean(value, name) {
68
78
  if (value !== 'true' && value !== 'false') {
69
79
  throw new UsageError(`${name} must be true or false`);
@@ -467,6 +477,7 @@ function parseGoals(args, baseUrl) {
467
477
  let targetAmount;
468
478
  let targetMonthKey;
469
479
  let isAchieved;
480
+ let priority;
470
481
  let apply = false;
471
482
  for (let index = 0; index < args.length; index += 1) {
472
483
  const argument = args[index];
@@ -497,7 +508,8 @@ function parseGoals(args, baseUrl) {
497
508
  && option !== '--name'
498
509
  && option !== '--target-amount'
499
510
  && option !== '--target-month'
500
- && option !== '--achieved') {
511
+ && option !== '--achieved'
512
+ && option !== '--priority') {
501
513
  throw new UsageError(`Unknown goals update option: ${argument}`);
502
514
  }
503
515
  const value = requireNonEmpty(inlineValue ?? readOptionValue(args, index, option), option);
@@ -521,6 +533,9 @@ function parseGoals(args, baseUrl) {
521
533
  }
522
534
  targetMonthKey = parseGoalMonthKey(value, option);
523
535
  }
536
+ else if (option === '--priority') {
537
+ priority = setOnce(priority, parseGoalPriority(value), option);
538
+ }
524
539
  else {
525
540
  isAchieved = setOnce(isAchieved, parseExplicitBoolean(value, option), option);
526
541
  }
@@ -530,9 +545,17 @@ function parseGoals(args, baseUrl) {
530
545
  if (name === undefined
531
546
  && targetAmount === undefined
532
547
  && targetMonthKey === undefined
533
- && isAchieved === undefined) {
548
+ && isAchieved === undefined
549
+ && priority === undefined) {
534
550
  throw new UsageError('goals update requires at least one field to update');
535
551
  }
552
+ if (priority !== undefined
553
+ && (name !== undefined
554
+ || targetAmount !== undefined
555
+ || targetMonthKey !== undefined
556
+ || isAchieved !== undefined)) {
557
+ throw new UsageError('--priority must be used on its own');
558
+ }
536
559
  return withBaseUrl({
537
560
  command: 'goals-update',
538
561
  goalId,
@@ -540,6 +563,7 @@ function parseGoals(args, baseUrl) {
540
563
  ...(targetAmount === undefined ? {} : { targetAmount }),
541
564
  ...(targetMonthKey === undefined ? {} : { targetMonthKey }),
542
565
  ...(isAchieved === undefined ? {} : { isAchieved }),
566
+ ...(priority === undefined ? {} : { priority }),
543
567
  apply,
544
568
  }, baseUrl);
545
569
  }
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { ICON_KEYS } from './category-metadata.js';
4
4
  import { parseApiResponse, validateAssignmentPayload, validateBudgetUpdatePayload, } from './contracts.js';
5
5
  import { createSystemCredentialStore, secureStorageUnavailableError, } from './credential-store.js';
6
6
  import { ApiError, CliError, ConfigError, UsageError, } from './errors.js';
7
- export const CLI_VERSION = '0.7.0';
7
+ export const CLI_VERSION = '0.8.0';
8
8
  const REQUEST_TIMEOUT_MS = 60_000;
9
9
  const API_ORIGIN_HELP_LINES = [
10
10
  '',
@@ -562,7 +562,7 @@ export function goalsListHelpText() {
562
562
  ' This command is read-only.',
563
563
  '',
564
564
  'Output:',
565
- ' JSON containing currency and goals. Each goal contains id, name,',
565
+ ' JSON containing currency and goals. Each goal contains id, name, priority,',
566
566
  ' targetAmount, targetMonthKey, isAchieved, and sharedWithPartner.',
567
567
  ].join('\n');
568
568
  }
@@ -615,6 +615,7 @@ export function goalsUpdateHelpText() {
615
615
  ' --target-month YYYY-MM Optional. Replace the target month.',
616
616
  ' --clear-target-month Optional. Remove the target month.',
617
617
  ' --achieved=true|false Optional. Mark the goal achieved or active.',
618
+ ' --priority POSITION Optional. Positive whole-number position; 1 is highest.',
618
619
  ' --apply Optional. Write the partial update.',
619
620
  ' --base-url URL Optional. Override the API origin.',
620
621
  ' -h, --help Show this help.',
@@ -622,6 +623,11 @@ export function goalsUpdateHelpText() {
622
623
  '',
623
624
  'Constraints:',
624
625
  ' Provide at least one field to update.',
626
+ ' Priority must be updated on its own.',
627
+ ' Priority 1 is highest. The position cannot exceed the current goal count.',
628
+ ' Moving a goal shifts the intervening goals automatically.',
629
+ ' Forecast assignments and shared progress refresh when the owner next opens',
630
+ ' the Forecast screen.',
625
631
  ' Set and clear options for the same field are mutually exclusive.',
626
632
  ' Marking a goal achieved removes its forecast assignment.',
627
633
  ' Marking it active again does not restore the previous assignment.',
@@ -634,6 +640,9 @@ export function goalsUpdateHelpText() {
634
640
  ' Without --apply, the command returns a dry-run preview and does not write.',
635
641
  ' Applying requires a write-enabled token created with Allow changes.',
636
642
  '',
643
+ 'Example:',
644
+ ' sloth-agent goals update --goal-id goal-3 --priority 2 --apply',
645
+ '',
637
646
  'Output:',
638
647
  ' Preview mode returns dryRun, method, endpoint, and payload.',
639
648
  ' Apply mode returns the complete persisted goal and currency.',
@@ -724,6 +733,23 @@ export function commandHelpText(topic) {
724
733
  function writeJson(write, data) {
725
734
  write(`${JSON.stringify(data, null, 2)}\n`);
726
735
  }
736
+ function withListedGoalPriorities(value) {
737
+ const response = value;
738
+ return {
739
+ ...response,
740
+ goals: response.goals.map((goal, index) => ({
741
+ ...goal,
742
+ priority: index + 1,
743
+ })),
744
+ };
745
+ }
746
+ function withUpdatedGoalPriority(value, priority) {
747
+ const response = value;
748
+ return {
749
+ ...response,
750
+ goal: { ...response.goal, priority },
751
+ };
752
+ }
727
753
  function redact(value, token) {
728
754
  return token ? value.split(token).join('[REDACTED]') : value;
729
755
  }
@@ -1104,6 +1130,9 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
1104
1130
  ...(parsed.isAchieved === undefined
1105
1131
  ? {}
1106
1132
  : { isAchieved: parsed.isAchieved }),
1133
+ ...(parsed.priority === undefined
1134
+ ? {}
1135
+ : { priority: parsed.priority }),
1107
1136
  };
1108
1137
  if (!parsed.apply) {
1109
1138
  writeJson(writeStdout, {
@@ -1124,7 +1153,9 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
1124
1153
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
1125
1154
  });
1126
1155
  const data = parseApiResponse('goals-update', await parseHttpResponse(response, token));
1127
- writeJson(writeStdout, data);
1156
+ writeJson(writeStdout, parsed.priority === undefined
1157
+ ? data
1158
+ : withUpdatedGoalPriority(data, parsed.priority));
1128
1159
  return 0;
1129
1160
  }
1130
1161
  if (parsed.command === 'goals-delete') {
@@ -1187,7 +1218,7 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
1187
1218
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
1188
1219
  });
1189
1220
  const data = parseApiResponse('goals-list', await parseHttpResponse(response, token));
1190
- writeJson(writeStdout, data);
1221
+ writeJson(writeStdout, withListedGoalPriorities(data));
1191
1222
  return 0;
1192
1223
  }
1193
1224
  if (parsed.command === 'budget') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slothmoney/agent-cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Command-line access to the Sloth Money Agent API.",
5
5
  "type": "module",
6
6
  "bin": {