@slothmoney/agent-cli 0.19.0 → 0.20.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 +9 -0
- package/README.md +25 -6
- package/dist/args.js +26 -2
- package/dist/cli.js +47 -13
- package/dist/contracts.js +97 -42
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.20.0 - 2026-08-27
|
|
4
|
+
|
|
5
|
+
- Add `portfolio` views for personal, partner-shared, and combined household
|
|
6
|
+
savings and investments.
|
|
7
|
+
- Add account-level partner visibility updates for private, balance-only, and
|
|
8
|
+
balance-and-holdings sharing.
|
|
9
|
+
- Keep portfolio results strict, machine-readable, and explicit about refresh
|
|
10
|
+
status and excluded currencies.
|
|
11
|
+
|
|
3
12
|
## 0.19.0 - 2026-08-26
|
|
4
13
|
|
|
5
14
|
- Make every Goal use one explicit personal Goal-funding account and expose
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sloth Agent CLI
|
|
2
2
|
|
|
3
|
-
Use your own agent to inspect accounts, investments, and budgets, manage goals, move assigned budget money, update planned amounts, categorise transactions, and configure payment notifications through the
|
|
3
|
+
Use your own agent to inspect personal and household accounts, investments, and budgets, manage goals, move assigned budget money, update planned amounts, categorise transactions, and configure payment notifications through the
|
|
4
4
|
[Sloth Money Agent API](https://slothmoney.app/developers/).
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -24,7 +24,7 @@ Create a personal access token in Sloth Money under
|
|
|
24
24
|
**Settings > Developer access**, then choose the authentication method for
|
|
25
25
|
where the CLI runs.
|
|
26
26
|
|
|
27
|
-
New tokens are view-only. That is enough for `auth status`, `accounts`, `investments`,
|
|
27
|
+
New tokens are view-only. That is enough for `auth status`, `accounts`, `investments`, `portfolio`,
|
|
28
28
|
`budget`, `categories`, `transactions`, and `goals` list. Enable **Allow changes** when
|
|
29
29
|
creating the token only if the CLI must apply assignments, manage categories
|
|
30
30
|
or line items, move assigned budget money, update planned budgets, manage accounts, ask a partner for an explanation, or manage goals. Token
|
|
@@ -103,6 +103,7 @@ options, output, and examples. For example:
|
|
|
103
103
|
```bash
|
|
104
104
|
sloth-agent auth login --help
|
|
105
105
|
sloth-agent accounts --help
|
|
106
|
+
sloth-agent portfolio --help
|
|
106
107
|
sloth-agent budget --help
|
|
107
108
|
sloth-agent budget status --help
|
|
108
109
|
sloth-agent budget update --help
|
|
@@ -584,7 +585,8 @@ sloth-agent accounts
|
|
|
584
585
|
The command is read-only and cache-only: it does not refresh linked banks or
|
|
585
586
|
change account data. Each result contains an opaque `accountRef`, personal or
|
|
586
587
|
joint ownership, connected or manual source, native balance/currency when
|
|
587
|
-
known, `lastBalanceUpdatedAt`, `connectionState`,
|
|
588
|
+
known, `lastBalanceUpdatedAt`, `connectionState`, `isGoalFundingAccount`, and
|
|
589
|
+
`partnerVisibility`.
|
|
588
590
|
Missing values are JSON
|
|
589
591
|
`null`; currencies are never converted or combined. Partner personal accounts
|
|
590
592
|
are excluded, while enabled shared joint accounts follow Sloth's existing
|
|
@@ -604,7 +606,7 @@ Copy the value from `sloth-agent accounts`. Account references are the public
|
|
|
604
606
|
account identifier for transaction filtering.
|
|
605
607
|
|
|
606
608
|
Account changes are previews unless `--apply` is present. Connected accounts
|
|
607
|
-
support
|
|
609
|
+
support Goal-funding eligibility and partner visibility. Manual current accounts support their
|
|
608
610
|
institution, name, currency, and ownership. Manual balance accounts also
|
|
609
611
|
support balance, Savings/Investments type, and Goal-funding eligibility.
|
|
610
612
|
Partner-owned shared accounts return an explanatory error.
|
|
@@ -618,14 +620,31 @@ sloth-agent accounts update \
|
|
|
618
620
|
--ownership individual \
|
|
619
621
|
--balance-amount 12500.75 \
|
|
620
622
|
--account-type investments \
|
|
621
|
-
--goal-funding-account false
|
|
623
|
+
--goal-funding-account false \
|
|
624
|
+
--partner-visibility holdings
|
|
622
625
|
|
|
623
626
|
sloth-agent accounts update \
|
|
624
627
|
--account-ref sloth_account_v1_... \
|
|
625
|
-
--
|
|
628
|
+
--partner-visibility balance \
|
|
626
629
|
--apply
|
|
627
630
|
```
|
|
628
631
|
|
|
632
|
+
Read the same current position from your, your partner's, or the combined
|
|
633
|
+
household perspective:
|
|
634
|
+
|
|
635
|
+
```bash
|
|
636
|
+
sloth-agent portfolio
|
|
637
|
+
sloth-agent portfolio --view partner
|
|
638
|
+
sloth-agent portfolio --view household
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
The command waits up to 45 seconds for eligible linked balances to refresh,
|
|
642
|
+
then returns cached data if work continues. Partner accounts appear only when
|
|
643
|
+
their owner has shared the balance or linked holdings. Sharing is for household
|
|
644
|
+
planning only. It does not change account ownership, transaction access, Goal
|
|
645
|
+
funding, or who can move money. Totals use the viewer's budget currency and
|
|
646
|
+
exclude other native currencies without converting them.
|
|
647
|
+
|
|
629
648
|
Archive an owned manual account. The account disappears from active Sloth
|
|
630
649
|
surfaces, but its underlying records are retained. Repeating an applied removal
|
|
631
650
|
is safe and returns `changed: false`.
|
package/dist/args.js
CHANGED
|
@@ -390,6 +390,7 @@ function parseAccounts(args, baseUrl) {
|
|
|
390
390
|
'--balance-amount',
|
|
391
391
|
'--account-type',
|
|
392
392
|
'--goal-funding-account',
|
|
393
|
+
'--partner-visibility',
|
|
393
394
|
]));
|
|
394
395
|
const institutionName = values.get('--institution-name');
|
|
395
396
|
const accountName = values.get('--account-name');
|
|
@@ -398,6 +399,7 @@ function parseAccounts(args, baseUrl) {
|
|
|
398
399
|
const balanceValue = values.get('--balance-amount');
|
|
399
400
|
const accountTypeValue = values.get('--account-type');
|
|
400
401
|
const sourceValue = values.get('--goal-funding-account');
|
|
402
|
+
const partnerVisibility = values.get('--partner-visibility');
|
|
401
403
|
if (currencyValue !== undefined && !/^[A-Za-z]{3}$/.test(currencyValue)) {
|
|
402
404
|
throw new UsageError('--currency must be a three-letter currency code');
|
|
403
405
|
}
|
|
@@ -414,6 +416,12 @@ function parseAccounts(args, baseUrl) {
|
|
|
414
416
|
if (sourceValue !== undefined && sourceValue !== 'true' && sourceValue !== 'false') {
|
|
415
417
|
throw new UsageError('--goal-funding-account must be true or false');
|
|
416
418
|
}
|
|
419
|
+
if (partnerVisibility !== undefined
|
|
420
|
+
&& partnerVisibility !== 'private'
|
|
421
|
+
&& partnerVisibility !== 'balance'
|
|
422
|
+
&& partnerVisibility !== 'holdings') {
|
|
423
|
+
throw new UsageError('--partner-visibility must be private, balance, or holdings');
|
|
424
|
+
}
|
|
417
425
|
const update = {
|
|
418
426
|
...(institutionName === undefined
|
|
419
427
|
? {}
|
|
@@ -430,6 +438,9 @@ function parseAccounts(args, baseUrl) {
|
|
|
430
438
|
? {}
|
|
431
439
|
: { accountType: accountTypeValue }),
|
|
432
440
|
...(sourceValue === undefined ? {} : { isGoalFundingAccount: sourceValue === 'true' }),
|
|
441
|
+
...(partnerVisibility === undefined ? {} : {
|
|
442
|
+
partnerVisibility: partnerVisibility,
|
|
443
|
+
}),
|
|
433
444
|
};
|
|
434
445
|
if (Object.keys(update).length === 0) {
|
|
435
446
|
throw new UsageError('accounts update requires at least one field to update');
|
|
@@ -471,6 +482,16 @@ function parseInvestments(args, baseUrl) {
|
|
|
471
482
|
}
|
|
472
483
|
return withBaseUrl({ command: 'investments', ...(accountRef ? { accountRef } : {}) }, baseUrl);
|
|
473
484
|
}
|
|
485
|
+
function parsePortfolio(args, baseUrl) {
|
|
486
|
+
const { values, apply } = parseNamedOptions(args, 'portfolio', new Set(['--view']));
|
|
487
|
+
if (apply)
|
|
488
|
+
throw new UsageError('portfolio does not accept --apply');
|
|
489
|
+
const view = values.get('--view') ?? 'mine';
|
|
490
|
+
if (view !== 'mine' && view !== 'partner' && view !== 'household') {
|
|
491
|
+
throw new UsageError('--view must be mine, partner, or household');
|
|
492
|
+
}
|
|
493
|
+
return withBaseUrl({ command: 'portfolio', view }, baseUrl);
|
|
494
|
+
}
|
|
474
495
|
function parseBudget(args, baseUrl) {
|
|
475
496
|
const subcommand = args[0] === 'status' || args[0] === 'update' || args[0] === 'move'
|
|
476
497
|
? args.shift()
|
|
@@ -979,8 +1000,8 @@ function helpTopic(argv) {
|
|
|
979
1000
|
return 'accounts-remove';
|
|
980
1001
|
return command;
|
|
981
1002
|
}
|
|
982
|
-
if (command === 'investments')
|
|
983
|
-
return
|
|
1003
|
+
if (command === 'investments' || command === 'portfolio')
|
|
1004
|
+
return command;
|
|
984
1005
|
return undefined;
|
|
985
1006
|
}
|
|
986
1007
|
export function parseArgs(argv) {
|
|
@@ -1015,6 +1036,9 @@ export function parseArgs(argv) {
|
|
|
1015
1036
|
if (command === 'investments') {
|
|
1016
1037
|
return parseInvestments(args, baseUrl);
|
|
1017
1038
|
}
|
|
1039
|
+
if (command === 'portfolio') {
|
|
1040
|
+
return parsePortfolio(args, baseUrl);
|
|
1041
|
+
}
|
|
1018
1042
|
if (command === 'budget') {
|
|
1019
1043
|
return parseBudget(args, baseUrl);
|
|
1020
1044
|
}
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { ICON_KEYS } from './category-metadata.js';
|
|
|
6
6
|
import { parseApiResponse, parseAssignmentOperationResponse, toLegacyAssignmentResponse, validateAssignmentPayload, validateBudgetMovementResponse, validateBudgetUpdatePayload, validateNotificationRulePayload, validateReceiptConfirmation, } from './contracts.js';
|
|
7
7
|
import { createSystemCredentialStore, secureStorageUnavailableError, } from './credential-store.js';
|
|
8
8
|
import { ApiError, CliError, ConfigError, UsageError, } from './errors.js';
|
|
9
|
-
export const CLI_VERSION = '0.
|
|
9
|
+
export const CLI_VERSION = '0.20.0';
|
|
10
10
|
const REQUEST_TIMEOUT_MS = 60_000;
|
|
11
11
|
const MAX_CONTRACT_PDF_BYTES = 6_000_000;
|
|
12
12
|
const API_ORIGIN_HELP_LINES = [
|
|
@@ -34,6 +34,7 @@ export function usageText() {
|
|
|
34
34
|
' sloth-agent accounts update --account-ref REF [fields] [--apply]',
|
|
35
35
|
' sloth-agent accounts remove --account-ref REF [--apply]',
|
|
36
36
|
' sloth-agent investments [--account-ref REF] [--base-url URL]',
|
|
37
|
+
' sloth-agent portfolio [--view mine|partner|household] [--base-url URL]',
|
|
37
38
|
' sloth-agent budget --scope personal|joint [--period YYYY-MM] [--base-url URL]',
|
|
38
39
|
' sloth-agent budget status --scope personal|joint [--period YYYY-MM] [--base-url URL]',
|
|
39
40
|
' sloth-agent budget update --scope personal|joint [--period YYYY-MM]',
|
|
@@ -378,11 +379,14 @@ export function accountsUpdateHelpText() {
|
|
|
378
379
|
' --balance-amount AMOUNT Balance-only account balance.',
|
|
379
380
|
' --account-type savings|investments Balance-only account type.',
|
|
380
381
|
' --goal-funding-account true|false Whether Goals may use this account.',
|
|
382
|
+
' --partner-visibility private|balance|holdings',
|
|
383
|
+
' What this account shares with your partner.',
|
|
381
384
|
'',
|
|
382
385
|
'Write behavior:',
|
|
383
386
|
' Without --apply, returns a JSON preview without credentials or a network request.',
|
|
384
387
|
' With --apply, requires agent:write on a write-enabled token and updates saved Sloth metadata.',
|
|
385
|
-
' Connected accounts support
|
|
388
|
+
' Connected accounts support --goal-funding-account and --partner-visibility.',
|
|
389
|
+
' Sharing exposes planning data only. It does not change ownership or assign the account to Goals.',
|
|
386
390
|
' Manual current accounts cannot change type, balance, or Goal-funding membership.',
|
|
387
391
|
' Partner-owned shared accounts cannot be changed.',
|
|
388
392
|
' Unknown, disconnected, or inaccessible references return Account not found.',
|
|
@@ -442,6 +446,33 @@ export function investmentsHelpText() {
|
|
|
442
446
|
' provider-native and are not converted or guaranteed to reconcile to totals.',
|
|
443
447
|
].join('\n');
|
|
444
448
|
}
|
|
449
|
+
export function portfolioHelpText() {
|
|
450
|
+
return [
|
|
451
|
+
'Sloth Agent CLI — portfolio',
|
|
452
|
+
'',
|
|
453
|
+
'Read your savings and investments from one household planning perspective.',
|
|
454
|
+
'',
|
|
455
|
+
'Usage:',
|
|
456
|
+
' sloth-agent portfolio [--view mine|partner|household] [--base-url URL]',
|
|
457
|
+
'',
|
|
458
|
+
'Options:',
|
|
459
|
+
' --view mine|partner|household Optional. Defaults to mine.',
|
|
460
|
+
' --base-url URL Optional. Override the API origin.',
|
|
461
|
+
' -h, --help Show this help.',
|
|
462
|
+
...API_ORIGIN_HELP_LINES,
|
|
463
|
+
'',
|
|
464
|
+
'Access:',
|
|
465
|
+
' This read-only command waits up to 45 seconds for eligible linked balances to refresh.',
|
|
466
|
+
' Partner shows only balances or holdings your partner explicitly shared.',
|
|
467
|
+
' Household combines your accounts with those shared balances and deduplicates joint accounts.',
|
|
468
|
+
' Shared data supports planning only. It does not assign partner accounts to Goals or change ownership.',
|
|
469
|
+
'',
|
|
470
|
+
'Output:',
|
|
471
|
+
' totals gives savings, investments, and tracked amounts in the viewer currency.',
|
|
472
|
+
' accounts includes ownerRole, freshness, sharing level, and permitted holdings.',
|
|
473
|
+
' refresh reports whether eligible linked balances refreshed or cached data was returned.',
|
|
474
|
+
].join('\n');
|
|
475
|
+
}
|
|
445
476
|
export function budgetHelpText() {
|
|
446
477
|
return [
|
|
447
478
|
'Sloth Agent CLI — budget',
|
|
@@ -1173,6 +1204,7 @@ export function commandHelpText(topic) {
|
|
|
1173
1204
|
'accounts-update': accountsUpdateHelpText,
|
|
1174
1205
|
'accounts-remove': accountsRemoveHelpText,
|
|
1175
1206
|
investments: investmentsHelpText,
|
|
1207
|
+
portfolio: portfolioHelpText,
|
|
1176
1208
|
budget: budgetHelpText,
|
|
1177
1209
|
'budget-status': budgetStatusHelpText,
|
|
1178
1210
|
'budget-move': budgetMoveHelpText,
|
|
@@ -2063,19 +2095,21 @@ export async function runCli(argv = process.argv.slice(2), options = {}) {
|
|
|
2063
2095
|
}
|
|
2064
2096
|
const path = parsed.command === 'accounts'
|
|
2065
2097
|
? '/api/agent/v1/accounts'
|
|
2066
|
-
: parsed.command === '
|
|
2067
|
-
? `/api/agent/v1/
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
:
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2098
|
+
: parsed.command === 'portfolio'
|
|
2099
|
+
? `/api/agent/v1/portfolio?${new URLSearchParams({ view: parsed.view }).toString()}`
|
|
2100
|
+
: parsed.command === 'investments'
|
|
2101
|
+
? `/api/agent/v1/investments${parsed.accountRef
|
|
2102
|
+
? `?${new URLSearchParams({ accountRef: parsed.accountRef }).toString()}`
|
|
2103
|
+
: ''}`
|
|
2104
|
+
: parsed.command === 'categories'
|
|
2105
|
+
? '/api/agent/v1/categories'
|
|
2106
|
+
: `/api/agent/v1/transactions${(() => {
|
|
2107
|
+
const query = buildTransactionsQuery(parsed.filters);
|
|
2108
|
+
return query ? `?${query}` : '';
|
|
2109
|
+
})()}`;
|
|
2076
2110
|
const response = await fetchImplementation(`${baseUrl}${path}`, {
|
|
2077
2111
|
method: 'GET',
|
|
2078
|
-
headers: parsed.command === 'transactions'
|
|
2112
|
+
headers: parsed.command === 'transactions' || parsed.command === 'portfolio'
|
|
2079
2113
|
? { ...headers, Prefer: 'wait=45' }
|
|
2080
2114
|
: headers,
|
|
2081
2115
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
package/dist/contracts.js
CHANGED
|
@@ -861,6 +861,7 @@ function isAccount(value) {
|
|
|
861
861
|
'lastBalanceUpdatedAt',
|
|
862
862
|
'connectionState',
|
|
863
863
|
'isGoalFundingAccount',
|
|
864
|
+
'partnerVisibility',
|
|
864
865
|
])
|
|
865
866
|
&& isAccountRef(value.accountRef)
|
|
866
867
|
&& isNullableNonEmptyString(value.accountName)
|
|
@@ -879,7 +880,10 @@ function isAccount(value) {
|
|
|
879
880
|
|| value.connectionState === 'expired'
|
|
880
881
|
|| value.connectionState === 'manual'
|
|
881
882
|
|| value.connectionState === 'unknown')
|
|
882
|
-
&& typeof value.isGoalFundingAccount === 'boolean'
|
|
883
|
+
&& typeof value.isGoalFundingAccount === 'boolean'
|
|
884
|
+
&& (value.partnerVisibility === 'private'
|
|
885
|
+
|| value.partnerVisibility === 'balance'
|
|
886
|
+
|| value.partnerVisibility === 'holdings'));
|
|
883
887
|
}
|
|
884
888
|
function isAccountsResponse(value) {
|
|
885
889
|
return (isObject(value)
|
|
@@ -945,6 +949,55 @@ function isInvestmentsResponse(value) {
|
|
|
945
949
|
&& holdings.every(isInvestmentHolding));
|
|
946
950
|
}));
|
|
947
951
|
}
|
|
952
|
+
function isPortfolioAccount(value) {
|
|
953
|
+
return isObject(value)
|
|
954
|
+
&& hasOnlyFields(value, [
|
|
955
|
+
'accountRef', 'ownerRole', 'accountName', 'institutionName', 'accountType',
|
|
956
|
+
'ownership', 'balanceAmount', 'currency', 'source', 'lastBalanceUpdatedAt',
|
|
957
|
+
'connectionState', 'partnerVisibility', 'isGoalFundingAccount', 'holdings',
|
|
958
|
+
])
|
|
959
|
+
&& isAccountRef(value.accountRef)
|
|
960
|
+
&& (value.ownerRole === 'you' || value.ownerRole === 'partner')
|
|
961
|
+
&& isNullableNonEmptyString(value.accountName)
|
|
962
|
+
&& isNullableNonEmptyString(value.institutionName)
|
|
963
|
+
&& (value.accountType === 'savings' || value.accountType === 'investments')
|
|
964
|
+
&& (value.ownership === 'personal' || value.ownership === 'joint')
|
|
965
|
+
&& (value.balanceAmount === null || (typeof value.balanceAmount === 'number' && Number.isFinite(value.balanceAmount)))
|
|
966
|
+
&& isCurrency(value.currency)
|
|
967
|
+
&& (value.source === 'connected' || value.source === 'manual')
|
|
968
|
+
&& (value.lastBalanceUpdatedAt === null || isIsoDateTime(value.lastBalanceUpdatedAt))
|
|
969
|
+
&& ['active', 'expired', 'manual', 'unknown'].includes(String(value.connectionState))
|
|
970
|
+
&& ['private', 'balance', 'holdings'].includes(String(value.partnerVisibility))
|
|
971
|
+
&& (value.isGoalFundingAccount === null || typeof value.isGoalFundingAccount === 'boolean')
|
|
972
|
+
&& Array.isArray(value.holdings)
|
|
973
|
+
&& value.holdings.every(isInvestmentHolding);
|
|
974
|
+
}
|
|
975
|
+
function isPortfolioResponse(value) {
|
|
976
|
+
if (!isObject(value) || !hasOnlyFields(value, [
|
|
977
|
+
'asOf', 'currency', 'view', 'hasPartner', 'totals',
|
|
978
|
+
'excludedCurrencyAccountCount', 'accounts', 'refresh',
|
|
979
|
+
]))
|
|
980
|
+
return false;
|
|
981
|
+
const totals = value.totals;
|
|
982
|
+
const refresh = value.refresh;
|
|
983
|
+
return isIsoDateTime(value.asOf)
|
|
984
|
+
&& isCurrency(value.currency)
|
|
985
|
+
&& ['mine', 'partner', 'household'].includes(String(value.view))
|
|
986
|
+
&& typeof value.hasPartner === 'boolean'
|
|
987
|
+
&& isObject(totals)
|
|
988
|
+
&& hasOnlyFields(totals, ['savingsAmount', 'investmentsAmount', 'trackedAmount'])
|
|
989
|
+
&& ['savingsAmount', 'investmentsAmount', 'trackedAmount'].every(field => (typeof totals[field] === 'number' && Number.isFinite(totals[field])))
|
|
990
|
+
&& Number.isSafeInteger(value.excludedCurrencyAccountCount)
|
|
991
|
+
&& Number(value.excludedCurrencyAccountCount) >= 0
|
|
992
|
+
&& Array.isArray(value.accounts)
|
|
993
|
+
&& value.accounts.every(isPortfolioAccount)
|
|
994
|
+
&& isObject(refresh)
|
|
995
|
+
&& hasOnlyFields(refresh, ['status', 'reason', 'utcDate'])
|
|
996
|
+
&& ['skipped', 'completed', 'in_progress', 'partial', 'failed'].includes(String(refresh.status))
|
|
997
|
+
&& typeof refresh.reason === 'string'
|
|
998
|
+
&& refresh.reason.length > 0
|
|
999
|
+
&& isIsoDate(refresh.utcDate);
|
|
1000
|
+
}
|
|
948
1001
|
function isForecastBasis(value) {
|
|
949
1002
|
return isObject(value)
|
|
950
1003
|
&& hasOnlyFields(value, [
|
|
@@ -1059,47 +1112,49 @@ export function parseApiResponse(command, value) {
|
|
|
1059
1112
|
? isAccountRemovalResponse(value)
|
|
1060
1113
|
: command === 'investments'
|
|
1061
1114
|
? isInvestmentsResponse(value)
|
|
1062
|
-
: command === '
|
|
1063
|
-
?
|
|
1064
|
-
: command === 'budget-
|
|
1065
|
-
?
|
|
1066
|
-
: command === 'budget-
|
|
1067
|
-
?
|
|
1068
|
-
: command === '
|
|
1069
|
-
?
|
|
1070
|
-
: command === 'categories
|
|
1071
|
-
?
|
|
1072
|
-
: command === '
|
|
1073
|
-
?
|
|
1074
|
-
: command === '
|
|
1075
|
-
?
|
|
1076
|
-
: command === '
|
|
1077
|
-
?
|
|
1078
|
-
: command === 'rules-
|
|
1079
|
-
?
|
|
1080
|
-
: command === 'rules-
|
|
1081
|
-
?
|
|
1082
|
-
: command === 'rules-
|
|
1083
|
-
?
|
|
1084
|
-
: command === '
|
|
1085
|
-
?
|
|
1086
|
-
: command === 'receipts-
|
|
1087
|
-
?
|
|
1088
|
-
: command === 'receipts-
|
|
1089
|
-
?
|
|
1090
|
-
: command === 'receipts-
|
|
1091
|
-
?
|
|
1092
|
-
: command === '
|
|
1093
|
-
?
|
|
1094
|
-
: command === '
|
|
1095
|
-
?
|
|
1096
|
-
: command === '
|
|
1097
|
-
?
|
|
1098
|
-
: command === 'goals-
|
|
1099
|
-
?
|
|
1100
|
-
: command === 'goals-
|
|
1101
|
-
?
|
|
1102
|
-
:
|
|
1115
|
+
: command === 'portfolio'
|
|
1116
|
+
? isPortfolioResponse(value)
|
|
1117
|
+
: command === 'budget' || command === 'budget-update'
|
|
1118
|
+
? isBudgetResponse(value)
|
|
1119
|
+
: command === 'budget-status'
|
|
1120
|
+
? isBudgetActivityStatusResponse(value)
|
|
1121
|
+
: command === 'budget-move'
|
|
1122
|
+
? isBudgetMovementResponse(value)
|
|
1123
|
+
: command === 'categories'
|
|
1124
|
+
? isCategoryResponse(value)
|
|
1125
|
+
: command === 'categories-create' || command === 'categories-rename'
|
|
1126
|
+
? isCategoryMutationResponse(value)
|
|
1127
|
+
: command === 'line-items-create' || command === 'line-items-rename'
|
|
1128
|
+
? isLineItemMutationResponse(value)
|
|
1129
|
+
: command === 'transactions'
|
|
1130
|
+
? isTransactionsResponse(value)
|
|
1131
|
+
: command === 'rules-list'
|
|
1132
|
+
? isNotificationRuleListResponse(value)
|
|
1133
|
+
: command === 'rules-get' || command === 'rules-set'
|
|
1134
|
+
? isNotificationRuleResponse(value)
|
|
1135
|
+
: command === 'rules-delete'
|
|
1136
|
+
? isNotificationRuleDeleteResponse(value)
|
|
1137
|
+
: command === 'rules-scan-contract'
|
|
1138
|
+
? isRenewalExtractionResponse(value)
|
|
1139
|
+
: command === 'receipts-extract'
|
|
1140
|
+
? isReceiptExtractResponse(value)
|
|
1141
|
+
: command === 'receipts-get'
|
|
1142
|
+
? isReceiptLookupResponse(value)
|
|
1143
|
+
: command === 'receipts-attach'
|
|
1144
|
+
? isReceiptMutationResponse(value)
|
|
1145
|
+
: command === 'receipts-remove'
|
|
1146
|
+
? isReceiptDeleteResponse(value)
|
|
1147
|
+
: command === 'assign'
|
|
1148
|
+
? isAssignmentResponse(value)
|
|
1149
|
+
: command === 'ask-partner'
|
|
1150
|
+
? isPartnerResponse(value)
|
|
1151
|
+
: command === 'goals-list'
|
|
1152
|
+
? isGoalsResponse(value)
|
|
1153
|
+
: command === 'goals-preview'
|
|
1154
|
+
? isGoalPreviewResponse(value)
|
|
1155
|
+
: command === 'goals-delete'
|
|
1156
|
+
? isGoalDeleteResponse(value)
|
|
1157
|
+
: isGoalMutationResponse(value);
|
|
1103
1158
|
if (!valid) {
|
|
1104
1159
|
const label = command === 'assign' ? 'assignment' : command;
|
|
1105
1160
|
throw new ApiError(`Invalid ${label} response from the Agent API`);
|