projectionlab-mcp 1.0.1 → 1.2.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/HOW-IT-WORKS.md +2 -2
- package/MANUAL-SETUP.md +64 -0
- package/README.md +34 -271
- package/REFERENCE.md +221 -0
- package/SETUP-FOR-AGENTS.md +37 -0
- package/dist/bootstrap.js +20 -3
- package/dist/bootstrap.js.map +1 -1
- package/dist/bridge.d.ts +2 -0
- package/dist/clonePlan.d.ts +9 -0
- package/dist/clonePlan.js +15 -14
- package/dist/clonePlan.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +41 -6
- package/dist/config.js.map +1 -1
- package/dist/currentFinances.d.ts +12 -1
- package/dist/currentFinances.js +60 -0
- package/dist/currentFinances.js.map +1 -1
- package/dist/dataModel.d.ts +58 -0
- package/dist/dataModel.js +1429 -0
- package/dist/dataModel.js.map +1 -0
- package/dist/deletePlan.d.ts +17 -0
- package/dist/deletePlan.js +72 -0
- package/dist/deletePlan.js.map +1 -0
- package/dist/diff.d.ts +288 -0
- package/dist/diff.js +744 -0
- package/dist/diff.js.map +1 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +14 -1
- package/dist/errors.js.map +1 -1
- package/dist/extensionBridge.d.ts +16 -2
- package/dist/extensionBridge.js +104 -23
- package/dist/extensionBridge.js.map +1 -1
- package/dist/index.js +27 -1
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +3 -2
- package/dist/instructions.js.map +1 -1
- package/dist/largeOutput.js +25 -0
- package/dist/largeOutput.js.map +1 -1
- package/dist/logger.js +11 -4
- package/dist/logger.js.map +1 -1
- package/dist/pathPatch.d.ts +5 -2
- package/dist/pathPatch.js +16 -2
- package/dist/pathPatch.js.map +1 -1
- package/dist/planSettings.d.ts +1 -1
- package/dist/planSettings.js +3 -3
- package/dist/planSettings.js.map +1 -1
- package/dist/plans.d.ts +73 -10
- package/dist/plans.js +206 -42
- package/dist/plans.js.map +1 -1
- package/dist/prompts/index.js +7 -4
- package/dist/prompts/index.js.map +1 -1
- package/dist/realEstate.d.ts +22 -0
- package/dist/realEstate.js +118 -0
- package/dist/realEstate.js.map +1 -0
- package/dist/redact.d.ts +26 -0
- package/dist/redact.js +93 -1
- package/dist/redact.js.map +1 -1
- package/dist/resources/dataModel.d.ts +3 -0
- package/dist/resources/dataModel.js +66 -0
- package/dist/resources/dataModel.js.map +1 -0
- package/dist/resources/knowledge.js +189 -47
- package/dist/resources/knowledge.js.map +1 -1
- package/dist/resources/planData.js +3 -1
- package/dist/resources/planData.js.map +1 -1
- package/dist/resources/summary.js +4 -1
- package/dist/resources/summary.js.map +1 -1
- package/dist/snapshot.d.ts +21 -0
- package/dist/snapshot.js +116 -12
- package/dist/snapshot.js.map +1 -1
- package/dist/summary.js +19 -6
- package/dist/summary.js.map +1 -1
- package/dist/tools/clonePlan.js +17 -8
- package/dist/tools/clonePlan.js.map +1 -1
- package/dist/tools/connection.js +29 -4
- package/dist/tools/connection.js.map +1 -1
- package/dist/tools/deletePlan.d.ts +4 -0
- package/dist/tools/deletePlan.js +103 -0
- package/dist/tools/deletePlan.js.map +1 -0
- package/dist/tools/diff.d.ts +4 -0
- package/dist/tools/diff.js +417 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/getCurrentFinances.js +27 -4
- package/dist/tools/getCurrentFinances.js.map +1 -1
- package/dist/tools/getPlan.js +4 -4
- package/dist/tools/getPlan.js.map +1 -1
- package/dist/tools/getPlanSection.js +7 -6
- package/dist/tools/getPlanSection.js.map +1 -1
- package/dist/tools/getPlanSettings.js +10 -6
- package/dist/tools/getPlanSettings.js.map +1 -1
- package/dist/tools/restore.js +18 -1
- package/dist/tools/restore.js.map +1 -1
- package/dist/tools/schema.js +28 -4
- package/dist/tools/schema.js.map +1 -1
- package/dist/tools/snapshots.d.ts +1 -1
- package/dist/tools/snapshots.js +53 -6
- package/dist/tools/snapshots.js.map +1 -1
- package/dist/tools/summary.js +3 -2
- package/dist/tools/summary.js.map +1 -1
- package/dist/tools/updateAccount.js +9 -7
- package/dist/tools/updateAccount.js.map +1 -1
- package/dist/tools/updatePlanEvent.js +71 -33
- package/dist/tools/updatePlanEvent.js.map +1 -1
- package/dist/tools/updatePlanSection.js +17 -32
- package/dist/tools/updatePlanSection.js.map +1 -1
- package/dist/tools/updatePlanSettings.js +11 -7
- package/dist/tools/updatePlanSettings.js.map +1 -1
- package/dist/types/projectionlab.d.ts +3 -1
- package/dist/types/wire.d.ts +27 -2
- package/dist/types/wire.js +6 -2
- package/dist/types/wire.js.map +1 -1
- package/dist/updateCheck.d.ts +22 -0
- package/dist/updateCheck.js +58 -0
- package/dist/updateCheck.js.map +1 -0
- package/dist/versionCompare.d.ts +5 -0
- package/dist/versionCompare.js +33 -0
- package/dist/versionCompare.js.map +1 -0
- package/dist/versionNotices.d.ts +9 -0
- package/dist/versionNotices.js +42 -0
- package/dist/versionNotices.js.map +1 -0
- package/package.json +6 -3
- package/skills/projectionlab/SKILL.md +329 -29
|
@@ -1,30 +1,61 @@
|
|
|
1
1
|
const KNOWLEDGE = `# ProjectionLab & FIRE Reference
|
|
2
2
|
|
|
3
3
|
Curated concepts for analyzing retirement plans through this MCP server.
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
ProjectionLab v5 is in early access; this reference and the tool descriptions
|
|
6
|
+
describe the current release, 4.6.0
|
|
7
|
+
(https://projectionlab.com/help/projectionlab-v5-early-access-guide).
|
|
8
|
+
|
|
9
|
+
## How to use this reference
|
|
10
|
+
|
|
11
|
+
- **Explain, do not recommend.** Say what a term means, what ProjectionLab does
|
|
12
|
+
with it, and what the user can look at in the app to decide. Do not tell the
|
|
13
|
+
user what to do with their money and do not predict a personal outcome. This
|
|
14
|
+
is information and education, not personalized financial advice; the decision
|
|
15
|
+
belongs to the user and a licensed professional.
|
|
16
|
+
- **Concepts only; ProjectionLab owns the yearly figures.** The app applies the
|
|
17
|
+
current tax brackets, standard deduction, IRMAA tiers, RMD ages, contribution
|
|
18
|
+
limits and ACA subsidies, and the user sees those numbers in the app (Tax
|
|
19
|
+
Analytics). Never state a yearly figure from memory: they change every year.
|
|
20
|
+
Ask the user to read the current one in ProjectionLab.
|
|
6
21
|
|
|
7
22
|
## ProjectionLab data model (quick map)
|
|
8
23
|
|
|
9
24
|
- **plans[]**: each plan is a milestone-driven simulation.
|
|
10
25
|
- **milestones[]**: lifecycle events (retirement, Medicare, death) keyed by
|
|
11
26
|
date/year/milestone-relative criteria. Other events reference milestone IDs.
|
|
27
|
+
Retirement and Life Expectancy always exist in the app and its delete
|
|
28
|
+
control is disabled for them, so never remove either one
|
|
29
|
+
(https://projectionlab.com/help/manage-milestones).
|
|
12
30
|
- **income.events[]**: salary, Social Security, pension, inheritance; start/end
|
|
13
31
|
reference milestone IDs.
|
|
14
32
|
- **expenses.events[]**: living, travel, healthcare, LTC; carry a
|
|
15
33
|
\`spendingType\` (essential vs discretionary).
|
|
16
34
|
- **accounts.events[]**: investment accounts with \`rothConversions\`
|
|
17
|
-
schedules, withdrawal rules, and bond/equity allocation glidepaths.
|
|
35
|
+
schedules, withdrawal rules, and bond/equity allocation glidepaths. A custom
|
|
36
|
+
growth or dividend rate on one account covers its stock portion only; the
|
|
37
|
+
bonds there follow the plan-level bond settings unless that account's bond
|
|
38
|
+
allocation is 0%
|
|
39
|
+
(https://projectionlab.com/help/growth-dividend-settings-chance-of-success).
|
|
18
40
|
- **assets.events[]**: real estate, vehicles with appreciation/depreciation.
|
|
19
41
|
- **variables**: tax settings, inflation, returns, drawdown order, IRMAA,
|
|
20
42
|
estate config.
|
|
21
|
-
- **withdrawalStrategy**:
|
|
22
|
-
|
|
23
|
-
|
|
43
|
+
- **withdrawalStrategy**: a separate mode, not the plan's normal drawdown
|
|
44
|
+
policy. From the year or milestone it starts, its rule replaces most other
|
|
45
|
+
plan events, such as expenses and asset purchases, so most plans leave it
|
|
46
|
+
off (https://projectionlab.com/help/withdrawal-strategy-mode).
|
|
47
|
+
- **montecarlo**: Chance of Success settings (review only; cannot be run
|
|
48
|
+
remotely). Chance of Success runs many trials over historical market periods
|
|
49
|
+
by default, with randomized (Monte Carlo) sampling as an option
|
|
50
|
+
(https://projectionlab.com/help/plan-vs-chance-of-success).
|
|
51
|
+
- **priorities.events[]**: savings contribution ordering. An "Always Fund"
|
|
52
|
+
flow is paid even when income falls short: ProjectionLab sells from other
|
|
53
|
+
accounts to cover it (https://projectionlab.com/help/mandatory-goals).
|
|
24
54
|
- **today / currentFinances**: actual account balances; \`accountId\` links these
|
|
25
55
|
to plan \`accounts.events[]\`.
|
|
26
|
-
-
|
|
27
|
-
server reads/writes the plan definition; it does not compute
|
|
56
|
+
- Chance of Success trials and projection *math* run only in the ProjectionLab
|
|
57
|
+
UI. This server reads/writes the plan definition; it does not compute
|
|
58
|
+
projections.
|
|
28
59
|
|
|
29
60
|
## Plan-change outcome metrics
|
|
30
61
|
|
|
@@ -35,57 +66,168 @@ the requested input changed; they do not measure its financial impact. The
|
|
|
35
66
|
Plugin API currently does not expose a supported calculation/result method, so
|
|
36
67
|
recalculate both outcomes in the UI after applying a change.
|
|
37
68
|
|
|
69
|
+
## Account tax vocabulary
|
|
70
|
+
|
|
71
|
+
Use three words for every account, and use them consistently:
|
|
72
|
+
|
|
73
|
+
- **taxable**: funded with after-tax money; interest, dividends and gains are
|
|
74
|
+
taxed in the year they are received.
|
|
75
|
+
- **tax-deferred**: traditional 401(k) and IRA. Contributions lower taxable
|
|
76
|
+
income now; withdrawals are taxed as ordinary income later.
|
|
77
|
+
- **tax-free**: Roth accounts, and an HSA spent on healthcare. Qualified
|
|
78
|
+
withdrawals are not taxed.
|
|
79
|
+
|
|
80
|
+
Do not use "pre-tax" or "post-tax" as account names; they blur the line between
|
|
81
|
+
tax-deferred and taxable.
|
|
82
|
+
|
|
38
83
|
## Core FIRE / decumulation concepts
|
|
39
84
|
|
|
40
|
-
- **Safe Withdrawal Rate (SWR)**: the
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- **
|
|
69
|
-
|
|
70
|
-
|
|
85
|
+
- **Safe Withdrawal Rate (SWR)**: the share of the portfolio taken out in the
|
|
86
|
+
first year of drawdown. The classic "4% rule" (Trinity study) is a starting
|
|
87
|
+
heuristic for a 30-year horizon, not a guarantee; a longer horizon argues for
|
|
88
|
+
a lower start. The portfolio withdrawal a plan needs falls as guaranteed
|
|
89
|
+
income (Social Security, pension) switches on.
|
|
90
|
+
- **Sequence-of-returns risk**: poor returns in the first years of drawdown do
|
|
91
|
+
far more damage than the same returns later. Common mitigations: a cash/bond
|
|
92
|
+
bridge, and a **rising-equity glidepath** ("bond tent" - most bonds at
|
|
93
|
+
retirement, equity rising after).
|
|
94
|
+
- **Asset location**: which account holds which asset. A common convention
|
|
95
|
+
places bonds in tax-deferred accounts, high-growth equity in tax-free (Roth,
|
|
96
|
+
HSA) accounts, and tax-efficient equity and cash in taxable. Location changes
|
|
97
|
+
after-tax return without changing the overall allocation.
|
|
98
|
+
- **Roth conversion**: moving money from a tax-deferred account into a tax-free
|
|
99
|
+
one. The converted amount is taxed as ordinary income in the year of the
|
|
100
|
+
conversion. A "Roth conversion ladder" converts in low-income years (often
|
|
101
|
+
the window after work ends and before Social Security or RMDs start) to fill
|
|
102
|
+
a low bracket, lower later RMDs, and shrink the taxable estate. Paying that
|
|
103
|
+
year's tax from a taxable account rather than from withholding keeps more
|
|
104
|
+
money inside the tax-free account.
|
|
105
|
+
|
|
106
|
+
## Tax concepts that gate conversions
|
|
107
|
+
|
|
108
|
+
Only the shape of each rule is here. ProjectionLab computes with the
|
|
109
|
+
current-year figures, and the user reads them in Tax Analytics. MAGI means
|
|
110
|
+
modified adjusted gross income; each program (ACA, IRMAA, NIIT) defines it
|
|
111
|
+
slightly differently.
|
|
112
|
+
|
|
113
|
+
- **Federal income tax brackets**: ordinary income is taxed in bands. Income
|
|
114
|
+
that fills an unused low band is cheap; income pushed into the next band
|
|
115
|
+
costs more. What a conversion costs depends on where it lands.
|
|
116
|
+
- **ACA premium subsidies**: marketplace health coverage is income-tested. In
|
|
117
|
+
some income ranges extra income can cut a subsidy faster than tax does, so
|
|
118
|
+
the effective marginal rate in those pre-Medicare years is higher than the
|
|
119
|
+
bracket alone suggests. Not a factor with employer, retiree or other
|
|
120
|
+
non-marketplace coverage.
|
|
121
|
+
- **IRMAA**: an extra charge on Medicare Part B and Part D premiums. It is set
|
|
122
|
+
by the person's MAGI from two years earlier and comes in tiers, so income
|
|
123
|
+
just over a tier boundary pays the whole higher charge. A conversion in one
|
|
124
|
+
year can raise premiums two years later. If the user is already on Medicare
|
|
125
|
+
when the plan starts, ProjectionLab estimates that lookback income in the
|
|
126
|
+
first two plan years, and the actual rule applies from year 3
|
|
127
|
+
(https://projectionlab.com/help/modeling-irmaa-surcharges).
|
|
128
|
+
- **NIIT (net investment income tax)**: a surtax on investment income (gains,
|
|
129
|
+
dividends, interest, rent) once MAGI is above an income threshold. It raises
|
|
130
|
+
the cost of a year that mixes a conversion with investment income.
|
|
131
|
+
- **Long-term capital gains rate**: while taxable income stays under a
|
|
132
|
+
threshold, long-term gains are taxed at 0%. A low-income year can realize
|
|
133
|
+
some gains at no tax cost before that room is gone.
|
|
134
|
+
- **RMDs (Required Minimum Distributions)**: once a person reaches the RMD age,
|
|
135
|
+
tax-deferred accounts require a withdrawal every year, whether or not the
|
|
136
|
+
cash is needed. A large tax-deferred balance can push those forced
|
|
137
|
+
withdrawals into higher brackets and IRMAA tiers, which is the usual reason
|
|
138
|
+
people convert while their income is still low.
|
|
71
139
|
|
|
72
140
|
## Analysis checklist
|
|
73
141
|
|
|
74
142
|
1. Build a lifecycle timeline (phase, date range, milestone trigger).
|
|
75
|
-
2. Cash flow by phase; flag pure-drawdown years and the
|
|
143
|
+
2. Cash flow by phase; flag pure-drawdown years and the gap before Social
|
|
144
|
+
Security starts.
|
|
76
145
|
3. Withdrawal rate now and after guaranteed income begins.
|
|
77
|
-
4. Sequence risk:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
146
|
+
4. Sequence risk: what a poor-return start does to the plan. Only a run in the
|
|
147
|
+
ProjectionLab UI can show it.
|
|
148
|
+
5. Roth conversion efficiency: bracket headroom versus the ACA, IRMAA and NIIT
|
|
149
|
+
ceilings; compare lifetime taxes and net legacy, not just the tax now.
|
|
150
|
+
6. Longevity: does the plan last well past life expectancy?
|
|
151
|
+
7. Inflation: healthcare and long-term care costs rise with inflation and are
|
|
152
|
+
often decades out; check how the plan assumes them.
|
|
153
|
+
|
|
154
|
+
## ProjectionLab help articles
|
|
155
|
+
|
|
156
|
+
ProjectionLab's own pages, linked for the user and summarized here for a model
|
|
157
|
+
with no web access. The bracketed tag is the plan section or area this reference
|
|
158
|
+
uses for it. The summaries are ours, not ProjectionLab's wording. Glossary of
|
|
159
|
+
financial terms: https://projectionlab.com/financial-terms
|
|
160
|
+
|
|
161
|
+
- **Withdrawal Strategy mode** [withdrawalStrategy]
|
|
162
|
+
https://projectionlab.com/help/withdrawal-strategy-mode - a comparison mode
|
|
163
|
+
for classic rules (initial percentage, variable percentage withdrawal,
|
|
164
|
+
Guyton-Klinger) that starts at a chosen year or milestone. While it is on,
|
|
165
|
+
its rule replaces most other plan events, so most plans leave it off.
|
|
166
|
+
- **Flows, the cash flow priorities** [priorities]
|
|
167
|
+
https://projectionlab.com/help/cash-flow-priorities - Flows (the
|
|
168
|
+
\`priorities\` section in the data) send income to savings goals,
|
|
169
|
+
contributions, extra debt payments and transfers, earliest-added first.
|
|
170
|
+
- **Mandatory goals ("Always Fund")** [priorities]
|
|
171
|
+
https://projectionlab.com/help/mandatory-goals - an Always Fund flow is paid
|
|
172
|
+
ahead of the other flows, selling from other accounts when income falls short.
|
|
173
|
+
- **Milestones** [milestones]
|
|
174
|
+
https://projectionlab.com/help/manage-milestones - lifecycle markers
|
|
175
|
+
triggered by age, date, balance, or a combination of criteria; other events
|
|
176
|
+
anchor their start and end to them. Retirement and Life Expectancy cannot be
|
|
177
|
+
deleted.
|
|
178
|
+
- **Drawdown order** [variables; the chart is app only]
|
|
179
|
+
https://projectionlab.com/help/drawdown-order-visualization - the order
|
|
180
|
+
accounts are liquidated in to cover a yearly shortfall. The graph and its red
|
|
181
|
+
early-withdrawal penalty line are a UI view of that order.
|
|
182
|
+
- **Roth conversions** [accounts; the optimizer is app only]
|
|
183
|
+
https://projectionlab.com/help/roth-conversion - Optimize searches conversion
|
|
184
|
+
strategies against brackets, IRMAA and legacy goals with a beam search, then
|
|
185
|
+
writes the chosen schedule into the plan's accounts. This server can read and
|
|
186
|
+
edit such a schedule; it cannot run the search.
|
|
187
|
+
- **Bond allocation and location** [accounts, variables]
|
|
188
|
+
https://projectionlab.com/help/bond-allocation-and-overrides - the bond
|
|
189
|
+
percentage is set plan-wide and can be overridden per account, and the other
|
|
190
|
+
accounts adjust to keep the plan-wide target, with a warning when it cannot
|
|
191
|
+
balance. Bond location chooses which accounts hold bonds first.
|
|
192
|
+
- **Custom growth and dividend rates** [accounts]
|
|
193
|
+
https://projectionlab.com/help/growth-dividend-settings-chance-of-success - an
|
|
194
|
+
account's custom growth or dividend rate covers its stock portion; the bond
|
|
195
|
+
portion follows the plan's bond settings unless the account's bond allocation
|
|
196
|
+
is overridden to 0%. In Chance of Success such a rate is either held fixed or
|
|
197
|
+
sampled like the rest of the simulation.
|
|
198
|
+
- **IRMAA surcharges** [variables; the optimizer is app only]
|
|
199
|
+
https://projectionlab.com/help/modeling-irmaa-surcharges - tiered Medicare
|
|
200
|
+
Part B and Part D surcharges set by MAGI two years earlier, where crossing a
|
|
201
|
+
tier by any amount costs the whole surcharge. When the user is already on
|
|
202
|
+
Medicare at plan start, ProjectionLab estimates the lookback income for the
|
|
203
|
+
first two plan years.
|
|
204
|
+
- **Plan vs Chance of Success** [montecarlo; results are app only]
|
|
205
|
+
https://projectionlab.com/help/plan-vs-chance-of-success - the Plan tab is one
|
|
206
|
+
fixed path at fixed growth; Chance of Success runs many trials over historical
|
|
207
|
+
or randomized market data. All other tabs follow the Plan tab, not the trial
|
|
208
|
+
outcomes.
|
|
209
|
+
- **Simulation engine** [app only]
|
|
210
|
+
https://projectionlab.com/help/simulation-engine - the app simulates a full
|
|
211
|
+
year at a time (income, withholding, expenses, debt, dividends, prior-year
|
|
212
|
+
taxes, RMDs) and turns a surplus into savings and a shortfall into
|
|
213
|
+
withdrawals.
|
|
214
|
+
- **Flexible spending** [expenses; the feature is app only]
|
|
215
|
+
https://projectionlab.com/help/flex-spending - an optional rule that raises
|
|
216
|
+
or cuts spending with portfolio performance against earlier all-time highs,
|
|
217
|
+
scoped either to all spending or to discretionary expenses only.
|
|
218
|
+
- **Plugins and external accounts** [Current Finances; app only]
|
|
219
|
+
https://projectionlab.com/help/plugins - ProjectionLab does not link to banks;
|
|
220
|
+
plugins (Lunch Money, YNAB, Monarch, or your own code) write balances into
|
|
221
|
+
Current Finances through the Plugin API, which has to be enabled in account
|
|
222
|
+
settings. This server uses that same API.
|
|
83
223
|
`;
|
|
84
224
|
export function registerKnowledgeResource(server) {
|
|
85
225
|
server.registerResource("knowledge", "projectionlab://knowledge", {
|
|
86
226
|
title: "ProjectionLab & FIRE Knowledge",
|
|
87
227
|
description: "Curated reference: ProjectionLab data model, FIRE/decumulation concepts, " +
|
|
88
|
-
"tax
|
|
228
|
+
"retirement tax concepts without yearly figures, an analysis checklist, and an " +
|
|
229
|
+
"index of ProjectionLab help articles. Static; information and education, not " +
|
|
230
|
+
"personalized financial advice.",
|
|
89
231
|
mimeType: "text/markdown",
|
|
90
232
|
}, async (uri) => ({
|
|
91
233
|
contents: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../src/resources/knowledge.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG
|
|
1
|
+
{"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../src/resources/knowledge.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8NjB,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,gBAAgB,CACrB,WAAW,EACX,2BAA2B,EAC3B;QACE,KAAK,EAAE,gCAAgC;QACvC,WAAW,EACT,2EAA2E;YAC3E,gFAAgF;YAChF,+EAA+E;YAC/E,gCAAgC;QAClC,QAAQ,EAAE,eAAe;KAC1B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,IAAI;gBACb,IAAI,EAAE,SAAS;gBACf,QAAQ,EAAE,eAAe;aAC1B;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -27,7 +27,9 @@ export function registerPlanDataResource(server, bridge) {
|
|
|
27
27
|
uri: uri.href,
|
|
28
28
|
text: JSON.stringify({
|
|
29
29
|
error: "Failed to export data",
|
|
30
|
-
|
|
30
|
+
// The message can echo request data, so scrub the Plugin API
|
|
31
|
+
// key from it the way errorResult does.
|
|
32
|
+
details: redactSecrets(err instanceof Error ? err.message : String(err)),
|
|
31
33
|
}),
|
|
32
34
|
mimeType: "application/json",
|
|
33
35
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planData.js","sourceRoot":"","sources":["../../src/resources/planData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,MAAc;IAEd,MAAM,CAAC,gBAAgB,CACrB,WAAW,EACX,2BAA2B,EAC3B;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,wGAAwG;QAC1G,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,MAAM,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;wBAClB,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,uBAAuB;4BAC9B,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"planData.js","sourceRoot":"","sources":["../../src/resources/planData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,MAAc;IAEd,MAAM,CAAC,gBAAgB,CACrB,WAAW,EACX,2BAA2B,EAC3B;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,wGAAwG;QAC1G,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,MAAM,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;wBAClB,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,uBAAuB;4BAC9B,6DAA6D;4BAC7D,wCAAwC;4BACxC,OAAO,EAAE,aAAa,CACpB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACjD;yBACF,CAAC;wBACF,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toJson } from "../json.js";
|
|
2
2
|
import { log } from "../logger.js";
|
|
3
|
+
import { redactSecrets } from "../redact.js";
|
|
3
4
|
import { buildSummary } from "../summary.js";
|
|
4
5
|
export function registerSummaryResource(server, bridge) {
|
|
5
6
|
server.registerResource("summary", "projectionlab://summary", {
|
|
@@ -28,7 +29,9 @@ export function registerSummaryResource(server, bridge) {
|
|
|
28
29
|
uri: uri.href,
|
|
29
30
|
text: JSON.stringify({
|
|
30
31
|
error: "Failed to build summary",
|
|
31
|
-
|
|
32
|
+
// The message can echo request data, so scrub the Plugin API
|
|
33
|
+
// key from it the way errorResult does.
|
|
34
|
+
details: redactSecrets(err instanceof Error ? err.message : String(err)),
|
|
32
35
|
}),
|
|
33
36
|
mimeType: "application/json",
|
|
34
37
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/resources/summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAAc;IAEd,MAAM,CAAC,gBAAgB,CACrB,SAAS,EACT,yBAAyB,EACzB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,4HAA4H;QAC9H,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACnC,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC;wBACrB,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,yBAAyB;4BAChC,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/resources/summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAAc;IAEd,MAAM,CAAC,gBAAgB,CACrB,SAAS,EACT,yBAAyB,EACzB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,4HAA4H;QAC9H,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACnC,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC;wBACrB,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,yBAAyB;4BAChC,6DAA6D;4BAC7D,wCAAwC;4BACxC,OAAO,EAAE,aAAa,CACpB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACjD;yBACF,CAAC;wBACF,QAAQ,EAAE,kBAAkB;qBAC7B;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/snapshot.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { Snapshot } from "./types/projectionlab.js";
|
|
2
|
+
/** The three mutually exclusive ways a caller can name one snapshot. */
|
|
3
|
+
export interface SnapshotSelectorArgs {
|
|
4
|
+
snapshotId?: string | null;
|
|
5
|
+
nBack?: number | null;
|
|
6
|
+
beforeTime?: string | null;
|
|
7
|
+
}
|
|
2
8
|
export declare class SnapshotManager {
|
|
3
9
|
private dir;
|
|
4
10
|
private initialized;
|
|
@@ -8,3 +14,18 @@ export declare class SnapshotManager {
|
|
|
8
14
|
list(): Promise<Omit<Snapshot, "data">[]>;
|
|
9
15
|
get(snapshotId: string): Promise<Snapshot>;
|
|
10
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a snapshot selector to one snapshot. Shared by
|
|
19
|
+
* projectionlab_rollback and projectionlab_diff so both pick the same
|
|
20
|
+
* snapshot for the same selector.
|
|
21
|
+
*
|
|
22
|
+
* nBack and beforeTime rank snapshots newest first, the order
|
|
23
|
+
* projectionlab_list_snapshots shows, and count every saved snapshot including
|
|
24
|
+
* the rollback_pre_* snapshot a confirmed rollback itself writes. nBack: 1 is
|
|
25
|
+
* therefore always the top of that list, which is the state saved just before
|
|
26
|
+
* a confirmed rollback, so a rollback is undone by rolling back once more.
|
|
27
|
+
*
|
|
28
|
+
* `subject` names the selector in the errors, for example "rollback snapshot"
|
|
29
|
+
* or "from snapshot".
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveSnapshot(snapshots: SnapshotManager, args: SnapshotSelectorArgs, subject?: string): Promise<Snapshot>;
|
package/dist/snapshot.js
CHANGED
|
@@ -1,13 +1,56 @@
|
|
|
1
|
-
import { readdir, readFile, unlink } from "node:fs/promises";
|
|
1
|
+
import { readdir, readFile, stat, unlink } from "node:fs/promises";
|
|
2
2
|
import { join, resolve, sep } from "node:path";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { config } from "./config.js";
|
|
5
5
|
import { ProjectionLabError } from "./errors.js";
|
|
6
|
-
import {
|
|
6
|
+
import { redactApiKeyToPlaceholder, restoreApiKeyFromPlaceholder } from "./redact.js";
|
|
7
7
|
import { secureMkdir, secureWriteFile } from "./secureFs.js";
|
|
8
8
|
import { log } from "./logger.js";
|
|
9
9
|
const RETENTION_DAYS = 30;
|
|
10
10
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11
|
+
const SELECTOR_KEYS = ["snapshotId", "nBack", "beforeTime"];
|
|
12
|
+
const SELECTOR_HELP = "Supply exactly one of snapshotId (an exact ID from projectionlab_list_snapshots), " +
|
|
13
|
+
"nBack (how many snapshots back, 1 being the most recent) or " +
|
|
14
|
+
"beforeTime (an ISO 8601 time with an explicit Z or ±HH:MM offset)";
|
|
15
|
+
// Snapshot timestamps are UTC instants. Date.parse reads an offset-less
|
|
16
|
+
// date-time in the host's zone and accepts loose text such as "12345" or
|
|
17
|
+
// "November 8 2026", so beforeTime has to carry its own offset to name one
|
|
18
|
+
// unambiguous instant. A bare date is refused for the same reason: it states
|
|
19
|
+
// no time of day.
|
|
20
|
+
const ISO_TIME_WITH_OFFSET = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|[+-]\d{2}:\d{2})$/i;
|
|
21
|
+
/** The instant a beforeTime names, or NaN when it is not a usable one. */
|
|
22
|
+
function parseBeforeTime(value) {
|
|
23
|
+
const parts = ISO_TIME_WITH_OFFSET.exec(value);
|
|
24
|
+
if (!parts)
|
|
25
|
+
return NaN;
|
|
26
|
+
const ms = Date.parse(value);
|
|
27
|
+
if (Number.isNaN(ms))
|
|
28
|
+
return NaN;
|
|
29
|
+
const offset = parts[8].toUpperCase();
|
|
30
|
+
const offsetMinutes = offset === "Z"
|
|
31
|
+
? 0
|
|
32
|
+
: (offset[0] === "-" ? -1 : 1) *
|
|
33
|
+
(Number(offset.slice(1, 3)) * 60 + Number(offset.slice(4, 6)));
|
|
34
|
+
// Date.parse rolls 31 February over instead of rejecting it, so the wall
|
|
35
|
+
// clock the caller wrote has to survive the round trip.
|
|
36
|
+
const wall = new Date(ms + offsetMinutes * 60_000);
|
|
37
|
+
const matches = wall.getUTCFullYear() === Number(parts[1]) &&
|
|
38
|
+
wall.getUTCMonth() === Number(parts[2]) - 1 &&
|
|
39
|
+
wall.getUTCDate() === Number(parts[3]) &&
|
|
40
|
+
wall.getUTCHours() === Number(parts[4]) &&
|
|
41
|
+
wall.getUTCMinutes() === Number(parts[5]);
|
|
42
|
+
return matches ? ms : NaN;
|
|
43
|
+
}
|
|
44
|
+
function pickSelector(args, subject) {
|
|
45
|
+
const supplied = SELECTOR_KEYS.filter((key) => args[key] !== undefined && args[key] !== null);
|
|
46
|
+
if (supplied.length !== 1) {
|
|
47
|
+
throw new ProjectionLabError("INVALID_INPUT", supplied.length === 0
|
|
48
|
+
? `No ${subject} selector supplied`
|
|
49
|
+
: `Supply exactly one ${subject} selector, received ${supplied.join(" and ")}`, SELECTOR_HELP);
|
|
50
|
+
}
|
|
51
|
+
// Exactly one key is present and is neither undefined nor null.
|
|
52
|
+
return { kind: supplied[0], value: args[supplied[0]] };
|
|
53
|
+
}
|
|
11
54
|
export class SnapshotManager {
|
|
12
55
|
dir = config.snapshotDir;
|
|
13
56
|
initialized = false;
|
|
@@ -24,11 +67,12 @@ export class SnapshotManager {
|
|
|
24
67
|
if (!file.endsWith(".json"))
|
|
25
68
|
continue;
|
|
26
69
|
try {
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
70
|
+
// mtime is the write time; snapshot files are never rewritten.
|
|
71
|
+
const filePath = join(this.dir, file);
|
|
72
|
+
const { mtimeMs } = await stat(filePath);
|
|
73
|
+
if (mtimeMs < cutoff) {
|
|
74
|
+
await unlink(filePath);
|
|
75
|
+
log.info("snapshot", `Pruned expired snapshot ${file}`);
|
|
32
76
|
}
|
|
33
77
|
}
|
|
34
78
|
catch {
|
|
@@ -43,9 +87,11 @@ export class SnapshotManager {
|
|
|
43
87
|
timestamp: new Date().toISOString(),
|
|
44
88
|
operation,
|
|
45
89
|
sections,
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
90
|
+
// The Plugin API key is stored as SNAPSHOT_KEY_PLACEHOLDER, so the file
|
|
91
|
+
// on disk never holds it; SnapshotManager.get puts the current
|
|
92
|
+
// config.apiKey back on every read, which keeps a rollback exact while
|
|
93
|
+
// the key itself stays out of the snapshot files.
|
|
94
|
+
data: redactApiKeyToPlaceholder(data),
|
|
49
95
|
};
|
|
50
96
|
const filePath = join(this.dir, `${snapshot.id}.json`);
|
|
51
97
|
await secureWriteFile(filePath, JSON.stringify(snapshot, null, 2));
|
|
@@ -75,7 +121,10 @@ export class SnapshotManager {
|
|
|
75
121
|
log.warn("snapshot", `Failed to read snapshot file: ${file}`);
|
|
76
122
|
}
|
|
77
123
|
}
|
|
78
|
-
|
|
124
|
+
// Newest first, with equal millisecond timestamps ordered by id so a
|
|
125
|
+
// recency-based rollback selector picks the same snapshot every time.
|
|
126
|
+
return snapshots.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() ||
|
|
127
|
+
(a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
79
128
|
}
|
|
80
129
|
async get(snapshotId) {
|
|
81
130
|
await this.ensureDir();
|
|
@@ -92,11 +141,66 @@ export class SnapshotManager {
|
|
|
92
141
|
}
|
|
93
142
|
try {
|
|
94
143
|
const raw = await readFile(filePath, "utf-8");
|
|
95
|
-
|
|
144
|
+
const snapshot = JSON.parse(raw);
|
|
145
|
+
// Undo the on-disk key placeholder (see create) so every reader sees
|
|
146
|
+
// the real key wherever the exported state carried it.
|
|
147
|
+
snapshot.data = restoreApiKeyFromPlaceholder(snapshot.data);
|
|
148
|
+
return snapshot;
|
|
96
149
|
}
|
|
97
150
|
catch {
|
|
98
151
|
throw new ProjectionLabError("SNAPSHOT_NOT_FOUND", `Snapshot ${snapshotId} not found`, "Use projectionlab_list_snapshots to see available snapshots");
|
|
99
152
|
}
|
|
100
153
|
}
|
|
101
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Resolve a snapshot selector to one snapshot. Shared by
|
|
157
|
+
* projectionlab_rollback and projectionlab_diff so both pick the same
|
|
158
|
+
* snapshot for the same selector.
|
|
159
|
+
*
|
|
160
|
+
* nBack and beforeTime rank snapshots newest first, the order
|
|
161
|
+
* projectionlab_list_snapshots shows, and count every saved snapshot including
|
|
162
|
+
* the rollback_pre_* snapshot a confirmed rollback itself writes. nBack: 1 is
|
|
163
|
+
* therefore always the top of that list, which is the state saved just before
|
|
164
|
+
* a confirmed rollback, so a rollback is undone by rolling back once more.
|
|
165
|
+
*
|
|
166
|
+
* `subject` names the selector in the errors, for example "rollback snapshot"
|
|
167
|
+
* or "from snapshot".
|
|
168
|
+
*/
|
|
169
|
+
export async function resolveSnapshot(snapshots, args, subject = "rollback snapshot") {
|
|
170
|
+
const selector = pickSelector(args, subject);
|
|
171
|
+
switch (selector.kind) {
|
|
172
|
+
case "snapshotId":
|
|
173
|
+
return snapshots.get(selector.value);
|
|
174
|
+
case "nBack": {
|
|
175
|
+
const nBack = selector.value;
|
|
176
|
+
if (!Number.isInteger(nBack) || nBack < 1) {
|
|
177
|
+
throw new ProjectionLabError("INVALID_INPUT", `nBack must be a positive integer with 1 as the most recent snapshot, received ${String(nBack)}`, SELECTOR_HELP);
|
|
178
|
+
}
|
|
179
|
+
const list = await snapshots.list();
|
|
180
|
+
if (nBack > list.length) {
|
|
181
|
+
const existence = list.length === 0
|
|
182
|
+
? "no snapshots exist"
|
|
183
|
+
: `only ${list.length} snapshot${list.length === 1 ? "" : "s"} exist${list.length === 1 ? "s" : ""}`;
|
|
184
|
+
throw new ProjectionLabError("SNAPSHOT_NOT_FOUND", `nBack ${nBack} is out of range; ${existence}`, "Use projectionlab_list_snapshots to see them, or a smaller nBack. " +
|
|
185
|
+
"Snapshots are saved automatically before confirmed writes");
|
|
186
|
+
}
|
|
187
|
+
return snapshots.get(list[nBack - 1].id);
|
|
188
|
+
}
|
|
189
|
+
case "beforeTime": {
|
|
190
|
+
const cutoff = parseBeforeTime(selector.value);
|
|
191
|
+
if (Number.isNaN(cutoff)) {
|
|
192
|
+
throw new ProjectionLabError("INVALID_INPUT", `beforeTime "${selector.value}" is not an ISO 8601 time with an explicit Z or ±HH:MM offset`, "Use a time such as 2026-11-08T15:30:00Z or 2026-11-08T15:30:00+02:00. " +
|
|
193
|
+
"projectionlab_list_snapshots shows snapshot times in that form");
|
|
194
|
+
}
|
|
195
|
+
const list = await snapshots.list();
|
|
196
|
+
const match = list.find((entry) => Date.parse(entry.timestamp) < cutoff);
|
|
197
|
+
if (!match) {
|
|
198
|
+
throw new ProjectionLabError("SNAPSHOT_NOT_FOUND", list.length === 0
|
|
199
|
+
? "No snapshots exist, so nothing predates that beforeTime"
|
|
200
|
+
: `No snapshot predates ${selector.value}; the oldest is ${list[list.length - 1].timestamp}`, "Use projectionlab_list_snapshots to see the saved snapshot times, or a later beforeTime");
|
|
201
|
+
}
|
|
202
|
+
return snapshots.get(match.id);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
102
206
|
//# sourceMappingURL=snapshot.js.map
|
package/dist/snapshot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/summary.js
CHANGED
|
@@ -23,15 +23,28 @@ export function buildSummary(data) {
|
|
|
23
23
|
for (const item of items) {
|
|
24
24
|
if (item && typeof item === "object") {
|
|
25
25
|
const obj = item;
|
|
26
|
-
const balance = Number(obj.balance ?? obj.value ?? 0);
|
|
27
26
|
group.count++;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
if (section === "assets") {
|
|
28
|
+
// In today.assets, amount is market value and balance is the loan balance.
|
|
29
|
+
const marketValue = Number(obj.amount ?? obj.value ?? 0);
|
|
30
|
+
group.total += marketValue;
|
|
31
|
+
totalNetWorth += marketValue;
|
|
32
|
+
// An outstanding loan balance on an asset is subtracted from net worth
|
|
33
|
+
// as a liability. Paid-in-full assets carry balance: 0.
|
|
34
|
+
const loanBalance = Number(obj.balance ?? 0);
|
|
35
|
+
if (loanBalance > 0) {
|
|
36
|
+
totalNetWorth -= loanBalance;
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
else {
|
|
34
|
-
|
|
40
|
+
const balance = Number(obj.balance ?? obj.value ?? 0);
|
|
41
|
+
group.total += balance;
|
|
42
|
+
if (section === "debts") {
|
|
43
|
+
totalNetWorth -= Math.abs(balance);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
totalNetWorth += balance;
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
50
|
}
|
package/dist/summary.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO7C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAkB;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAA4C,CAAC;IACnE,MAAM,cAAc,GAAqD,EAAE,CAAC;IAC5E,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG;YACf,oBAAoB;YACpB,iBAAiB;YACjB,OAAO;YACP,QAAQ;SACT,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAI,QAAoC,CAAC,OAAO,CAAC,CAAC;YAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,SAAS;YAEpC,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrC,MAAM,GAAG,GAAG,IAA+B,CAAC;oBAC5C,
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"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"}
|