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
|
@@ -4,19 +4,10 @@ import { ProjectionLabError, errorResult } from "../errors.js";
|
|
|
4
4
|
import { assertPlansUnchanged } from "../planVersion.js";
|
|
5
5
|
import { toJson } from "../json.js";
|
|
6
6
|
import { log } from "../logger.js";
|
|
7
|
-
import { applyExistingPathChanges, pathChangesApplied, } from "../pathPatch.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
// projectionlab_update_plan_settings.
|
|
12
|
-
const EVENT_SECTIONS = [
|
|
13
|
-
"income",
|
|
14
|
-
"expenses",
|
|
15
|
-
"accounts",
|
|
16
|
-
"assets",
|
|
17
|
-
"milestones",
|
|
18
|
-
"priorities",
|
|
19
|
-
];
|
|
7
|
+
import { applyExistingPathChanges, listAddressableValues, pathChangesApplied, } from "../pathPatch.js";
|
|
8
|
+
import { enumRefusalError } from "../dataModel.js";
|
|
9
|
+
import { isSecretFieldName, redactSecrets } from "../redact.js";
|
|
10
|
+
import { eventLabel, resolveEventIndex, resolvePlanIndex, getEvents, planNotFoundError, requirePlans, EVENT_SECTIONS, } from "../plans.js";
|
|
20
11
|
const EVENT_FIELD_CONTEXT = {
|
|
21
12
|
label: "event field",
|
|
22
13
|
discoveryTool: "projectionlab_get_plan_section with listPaths=true",
|
|
@@ -27,6 +18,56 @@ function assertMutableEventPath(path) {
|
|
|
27
18
|
throw new ProjectionLabError("INVALID_INPUT", "The event ID is immutable", "Use the ID only to select the event");
|
|
28
19
|
}
|
|
29
20
|
}
|
|
21
|
+
const UNSAFE_NEW_FIELDS = new Set([
|
|
22
|
+
"__proto__",
|
|
23
|
+
"prototype",
|
|
24
|
+
"constructor",
|
|
25
|
+
"id",
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* The legacy shallow top-level patch, validated like pathChanges. Existing
|
|
29
|
+
* fields go through applyExistingPathChanges (same existence, JSON-type,
|
|
30
|
+
* unsafe-key and secret-name checks); values replacing a whole nested object
|
|
31
|
+
* are still checked leaf by leaf against the observed enums. New fields stay
|
|
32
|
+
* allowed only as plain, non-secret names.
|
|
33
|
+
*/
|
|
34
|
+
function applyEventPatch(event, patch, section) {
|
|
35
|
+
for (const key of Object.keys(patch)) {
|
|
36
|
+
assertMutableEventPath(key);
|
|
37
|
+
}
|
|
38
|
+
for (const { path, value } of listAddressableValues(patch)) {
|
|
39
|
+
const refusal = enumRefusalError(section, path, value);
|
|
40
|
+
if (refusal)
|
|
41
|
+
throw refusal;
|
|
42
|
+
}
|
|
43
|
+
const existing = {};
|
|
44
|
+
const additions = {};
|
|
45
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
46
|
+
if (Object.prototype.hasOwnProperty.call(event, key)) {
|
|
47
|
+
existing[key] = value;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (key.length === 0 ||
|
|
51
|
+
key.includes(".") ||
|
|
52
|
+
UNSAFE_NEW_FIELDS.has(key) ||
|
|
53
|
+
isSecretFieldName(key)) {
|
|
54
|
+
throw new ProjectionLabError("INVALID_INPUT", `Invalid new event field "${key}"`, "New top-level fields must be plain, non-secret names; use pathChanges to change existing nested values");
|
|
55
|
+
}
|
|
56
|
+
additions[key] = value;
|
|
57
|
+
}
|
|
58
|
+
let updated = event;
|
|
59
|
+
let changes = {};
|
|
60
|
+
if (Object.keys(existing).length > 0) {
|
|
61
|
+
const result = applyExistingPathChanges(event, existing, EVENT_FIELD_CONTEXT, section);
|
|
62
|
+
updated = result.updated;
|
|
63
|
+
changes = result.changes;
|
|
64
|
+
}
|
|
65
|
+
for (const [key, value] of Object.entries(additions)) {
|
|
66
|
+
updated = { ...updated, [key]: value };
|
|
67
|
+
changes[key] = { before: "[ABSENT]", after: value };
|
|
68
|
+
}
|
|
69
|
+
return { updated, changes };
|
|
70
|
+
}
|
|
30
71
|
/** Rebuild a section with one event replaced, preserving its container shape. */
|
|
31
72
|
function replaceEvent(sectionData, eventIndex, newEvent) {
|
|
32
73
|
if (Array.isArray(sectionData)) {
|
|
@@ -45,8 +86,10 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
45
86
|
description: "Patches ONE event (income source, expense, account, asset, milestone, or priority) " +
|
|
46
87
|
"within ONE plan. Use pathChanges for nested fields so nested siblings are preserved; " +
|
|
47
88
|
"get valid paths from projectionlab_get_plan_section with eventIdentifier and listPaths=true. " +
|
|
89
|
+
"See projectionlab://data-model for field units and allowed values. " +
|
|
48
90
|
"The legacy patch input shallowly merges top-level fields and replaces any nested object " +
|
|
49
|
-
"supplied there
|
|
91
|
+
"supplied there; existing fields keep their JSON type and new fields must be plain, " +
|
|
92
|
+
"non-secret names. Supply exactly one of patch or pathChanges. All sibling events are preserved. " +
|
|
50
93
|
"This is the PREFERRED write tool for single-event changes: much smaller and " +
|
|
51
94
|
"safer than regenerating a whole section. " +
|
|
52
95
|
"When confirm is false (default), returns a dry-run field-level diff. " +
|
|
@@ -56,7 +99,7 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
56
99
|
.string()
|
|
57
100
|
.trim()
|
|
58
101
|
.min(1)
|
|
59
|
-
.describe("Plan name (case-insensitive
|
|
102
|
+
.describe("Plan name (case-insensitive; a partial match must identify exactly one plan) or exact plan ID"),
|
|
60
103
|
section: z
|
|
61
104
|
.enum(EVENT_SECTIONS)
|
|
62
105
|
.describe("Which event-based section of the plan the event lives in"),
|
|
@@ -64,11 +107,11 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
64
107
|
.string()
|
|
65
108
|
.trim()
|
|
66
109
|
.min(1)
|
|
67
|
-
.describe("Event name (case-insensitive
|
|
110
|
+
.describe("Event name (case-insensitive; exact name preferred, a partial match must identify exactly one event) or exact event ID"),
|
|
68
111
|
patch: z
|
|
69
112
|
.record(z.string(), z.unknown())
|
|
70
113
|
.optional()
|
|
71
|
-
.describe("Top-level fields to change, e.g. { amount: 5000 }.
|
|
114
|
+
.describe("Top-level fields to change, e.g. { amount: 5000 }. Existing fields keep their JSON type and are validated like pathChanges; a nested object supplied here replaces that complete nested object. New fields must be plain, non-secret names. Use pathChanges for nested fields."),
|
|
72
115
|
pathChanges: z
|
|
73
116
|
.record(z.string(), z.unknown())
|
|
74
117
|
.optional()
|
|
@@ -94,7 +137,7 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
94
137
|
}
|
|
95
138
|
const data = await bridge.exportData({ fresh: true });
|
|
96
139
|
const plans = requirePlans(data);
|
|
97
|
-
const planIndex =
|
|
140
|
+
const planIndex = resolvePlanIndex(plans, planIdentifier);
|
|
98
141
|
if (planIndex === -1)
|
|
99
142
|
throw planNotFoundError(plans, planIdentifier);
|
|
100
143
|
const plan = plans[planIndex];
|
|
@@ -103,29 +146,25 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
103
146
|
if (events.length === 0) {
|
|
104
147
|
throw new ProjectionLabError("INVALID_INPUT", `Section "${section}" of plan "${plan.name}" has no events`, "Check the section name with projectionlab_get_plan_section");
|
|
105
148
|
}
|
|
106
|
-
const eventIndex =
|
|
149
|
+
const eventIndex = resolveEventIndex(events, eventIdentifier);
|
|
107
150
|
if (eventIndex === -1) {
|
|
108
151
|
throw new ProjectionLabError("INVALID_INPUT", `No event matching "${eventIdentifier}" in section "${section}" of plan "${plan.name}"`, `Available events: ${events.map(eventLabel).sort().join(", ")}`);
|
|
109
152
|
}
|
|
110
153
|
const event = events[eventIndex];
|
|
111
154
|
let patched;
|
|
112
155
|
let changes;
|
|
113
|
-
let pathDiff;
|
|
114
156
|
if (pathChanges !== undefined) {
|
|
115
157
|
for (const path of Object.keys(pathChanges)) {
|
|
116
158
|
assertMutableEventPath(path);
|
|
117
159
|
}
|
|
118
|
-
const result = applyExistingPathChanges(event, pathChanges, EVENT_FIELD_CONTEXT);
|
|
160
|
+
const result = applyExistingPathChanges(event, pathChanges, EVENT_FIELD_CONTEXT, section);
|
|
119
161
|
patched = result.updated;
|
|
120
162
|
changes = result.changes;
|
|
121
|
-
pathDiff = result.changes;
|
|
122
163
|
}
|
|
123
164
|
else {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
patched = { ...event, ...patch };
|
|
128
|
-
changes = diffFields(event, patched);
|
|
165
|
+
const result = applyEventPatch(event, patch ?? {}, section);
|
|
166
|
+
patched = result.updated;
|
|
167
|
+
changes = result.changes;
|
|
129
168
|
}
|
|
130
169
|
const renderedChanges = redactSecrets(changes, { byName: true });
|
|
131
170
|
if (!confirm) {
|
|
@@ -167,7 +206,9 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
167
206
|
],
|
|
168
207
|
};
|
|
169
208
|
}
|
|
170
|
-
await snapshots.create("updatePlanEvent", ["plans"], {
|
|
209
|
+
const snapshot = await snapshots.create("updatePlanEvent", ["plans"], {
|
|
210
|
+
plans,
|
|
211
|
+
});
|
|
171
212
|
const updatedPlan = {
|
|
172
213
|
...plan,
|
|
173
214
|
[section]: replaceEvent(sectionData, eventIndex, patched),
|
|
@@ -189,11 +230,7 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
189
230
|
e.id === event.id) ||
|
|
190
231
|
eventLabel(e) === eventLabel(patched)));
|
|
191
232
|
if (verifiedEvent) {
|
|
192
|
-
verified =
|
|
193
|
-
pathDiff !== undefined
|
|
194
|
-
? pathChangesApplied(verifiedEvent, pathDiff, EVENT_FIELD_CONTEXT)
|
|
195
|
-
: Object.entries(patch ?? {}).every(([key, expected]) => JSON.stringify(verifiedEvent[key]) ===
|
|
196
|
-
JSON.stringify(expected));
|
|
233
|
+
verified = pathChangesApplied(verifiedEvent, changes, EVENT_FIELD_CONTEXT);
|
|
197
234
|
}
|
|
198
235
|
}
|
|
199
236
|
return {
|
|
@@ -207,6 +244,7 @@ export function registerUpdatePlanEventTool(server, bridge, snapshots) {
|
|
|
207
244
|
event: eventLabel(patched),
|
|
208
245
|
changes: renderedChanges,
|
|
209
246
|
verified,
|
|
247
|
+
snapshotId: snapshot.id,
|
|
210
248
|
message: verified
|
|
211
249
|
? "Event patched and verified. Snapshot saved automatically."
|
|
212
250
|
: "Patch sent but verification did not confirm all fields - check with projectionlab_get_plan_section.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updatePlanEvent.js","sourceRoot":"","sources":["../../src/tools/updatePlanEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GAEnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"updatePlanEvent.js","sourceRoot":"","sources":["../../src/tools/updatePlanEvent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { config } from "../config.js";
|
|
3
|
-
import { ProjectionLabError, errorResult } from "../errors.js";
|
|
3
|
+
import { ProjectionLabError, errorResult, redactedSecretsError, } from "../errors.js";
|
|
4
4
|
import { assertPlanVersion, assertPlansUnchanged, planVersion, } from "../planVersion.js";
|
|
5
5
|
import { toJson } from "../json.js";
|
|
6
6
|
import { log } from "../logger.js";
|
|
7
|
-
import {
|
|
7
|
+
import { redactSecrets, findRedactedSecretPaths } from "../redact.js";
|
|
8
|
+
import { PLAN_SECTIONS, assertSectionShape, diffFields, resolvePlanIndex, getEvents, keyEvents, planNotFoundError, requirePlans, verifySectionApplied, } from "../plans.js";
|
|
8
9
|
function isEventish(sectionData) {
|
|
9
10
|
if (Array.isArray(sectionData))
|
|
10
11
|
return true;
|
|
@@ -12,30 +13,6 @@ function isEventish(sectionData) {
|
|
|
12
13
|
typeof sectionData === "object" &&
|
|
13
14
|
Array.isArray(sectionData.events));
|
|
14
15
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Key events for diffing by label plus occurrence number, so events sharing a
|
|
17
|
-
* name each keep their own entry. Ids are not used because a replacement
|
|
18
|
-
* section may omit them. The display name shows the occurrence only when the
|
|
19
|
-
* label repeats.
|
|
20
|
-
*/
|
|
21
|
-
function keyEvents(events) {
|
|
22
|
-
const labelCounts = new Map();
|
|
23
|
-
for (const e of events) {
|
|
24
|
-
const label = eventLabel(e);
|
|
25
|
-
labelCounts.set(label, (labelCounts.get(label) ?? 0) + 1);
|
|
26
|
-
}
|
|
27
|
-
const seen = new Map();
|
|
28
|
-
const keyed = new Map();
|
|
29
|
-
for (const e of events) {
|
|
30
|
-
const label = eventLabel(e);
|
|
31
|
-
const n = (seen.get(label) ?? 0) + 1;
|
|
32
|
-
seen.set(label, n);
|
|
33
|
-
const key = `${label}#${n}`;
|
|
34
|
-
const name = (labelCounts.get(label) ?? 0) > 1 ? `${label} #${n}` : label;
|
|
35
|
-
keyed.set(key, { name, event: e });
|
|
36
|
-
}
|
|
37
|
-
return keyed;
|
|
38
|
-
}
|
|
39
16
|
function diffSection(current, incoming) {
|
|
40
17
|
const currentEvents = getEvents(current);
|
|
41
18
|
const newEvents = getEvents(incoming);
|
|
@@ -78,15 +55,17 @@ function diffSection(current, incoming) {
|
|
|
78
55
|
: {}),
|
|
79
56
|
};
|
|
80
57
|
}
|
|
58
|
+
/** The preview of a section change, with secret-named fields and the Plugin
|
|
59
|
+
* API key scrubbed like every other plan read. */
|
|
81
60
|
function renderDiff(diff) {
|
|
82
|
-
return {
|
|
61
|
+
return redactSecrets({
|
|
83
62
|
itemCount: `${diff.currentCount} → ${diff.newCount}`,
|
|
84
63
|
added: diff.added.length > 0 ? diff.added : undefined,
|
|
85
64
|
removed: diff.removed.length > 0 ? diff.removed : undefined,
|
|
86
65
|
modified: diff.modified.length > 0 ? diff.modified : undefined,
|
|
87
66
|
unchanged: diff.unchanged.length > 0 ? diff.unchanged : undefined,
|
|
88
67
|
fieldChanges: diff.fieldChanges,
|
|
89
|
-
};
|
|
68
|
+
}, { byName: true });
|
|
90
69
|
}
|
|
91
70
|
export function registerUpdatePlanSectionTool(server, bridge, snapshots) {
|
|
92
71
|
server.registerTool("projectionlab_update_plan_section", {
|
|
@@ -106,13 +85,13 @@ export function registerUpdatePlanSectionTool(server, bridge, snapshots) {
|
|
|
106
85
|
.string()
|
|
107
86
|
.trim()
|
|
108
87
|
.min(1)
|
|
109
|
-
.describe("Plan name (case-insensitive
|
|
88
|
+
.describe("Plan name (case-insensitive; a partial match must identify exactly one plan) or exact plan ID"),
|
|
110
89
|
section: z
|
|
111
90
|
.enum(PLAN_SECTIONS)
|
|
112
91
|
.describe("Which section of the plan to update"),
|
|
113
92
|
sectionData: z
|
|
114
93
|
.unknown()
|
|
115
|
-
.describe("Complete replacement data for the section. Must be the full section
|
|
94
|
+
.describe("Complete replacement data for the section. Must be the full section, not a partial patch, and in the section's container shape: an array for milestones, an object with an events array for income, expenses, accounts, assets and priorities, an object for variables, montecarlo and withdrawalStrategy. null, primitives and mismatched shapes are refused."),
|
|
116
95
|
confirm: z
|
|
117
96
|
.boolean()
|
|
118
97
|
.default(false)
|
|
@@ -133,13 +112,18 @@ export function registerUpdatePlanSectionTool(server, bridge, snapshots) {
|
|
|
133
112
|
if (config.readOnly) {
|
|
134
113
|
throw new ProjectionLabError("READ_ONLY_MODE", "Write operations are disabled (read-only mode; PL_READ_ONLY is not \"false\")", "Ask the user whether to enable writes: set PL_READ_ONLY=false in the MCP host env block or ~/.projectionlab-mcp/.env, then restart the server");
|
|
135
114
|
}
|
|
115
|
+
const redactedPaths = findRedactedSecretPaths(sectionData);
|
|
116
|
+
if (redactedPaths.length > 0) {
|
|
117
|
+
throw redactedSecretsError("sectionData", redactedPaths);
|
|
118
|
+
}
|
|
136
119
|
const data = await bridge.exportData({ fresh: true });
|
|
137
120
|
const plans = requirePlans(data);
|
|
138
|
-
const planIndex =
|
|
121
|
+
const planIndex = resolvePlanIndex(plans, planIdentifier);
|
|
139
122
|
if (planIndex === -1)
|
|
140
123
|
throw planNotFoundError(plans, planIdentifier);
|
|
141
124
|
const plan = plans[planIndex];
|
|
142
125
|
const currentSection = plan[section];
|
|
126
|
+
assertSectionShape(section, String(plan.name), currentSection, sectionData);
|
|
143
127
|
const diff = diffSection(currentSection, sectionData);
|
|
144
128
|
if (!confirm) {
|
|
145
129
|
return {
|
|
@@ -162,7 +146,7 @@ export function registerUpdatePlanSectionTool(server, bridge, snapshots) {
|
|
|
162
146
|
}
|
|
163
147
|
assertPlanVersion(plan, expectedPlanVersion);
|
|
164
148
|
// Snapshot all plans before mutation
|
|
165
|
-
await snapshots.create("updatePlanSection", ["plans"], {
|
|
149
|
+
const snapshot = await snapshots.create("updatePlanSection", ["plans"], {
|
|
166
150
|
plans,
|
|
167
151
|
});
|
|
168
152
|
// Rebuild plans array with the one section replaced
|
|
@@ -190,6 +174,7 @@ export function registerUpdatePlanSectionTool(server, bridge, snapshots) {
|
|
|
190
174
|
section,
|
|
191
175
|
diff: renderDiff(diff),
|
|
192
176
|
verified: check.ok,
|
|
177
|
+
snapshotId: snapshot.id,
|
|
193
178
|
message: check.ok
|
|
194
179
|
? "Section updated and verified. Snapshot saved automatically."
|
|
195
180
|
: `Section update sent but could not be verified (${check.reason}) - check with projectionlab_get_plan_section. A snapshot was saved; roll back with projectionlab_rollback if needed.`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updatePlanSection.js","sourceRoot":"","sources":["../../src/tools/updatePlanSection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"updatePlanSection.js","sourceRoot":"","sources":["../../src/tools/updatePlanSection.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,27 +6,28 @@ import { toJson } from "../json.js";
|
|
|
6
6
|
import { log } from "../logger.js";
|
|
7
7
|
import { redactSecrets } from "../redact.js";
|
|
8
8
|
import { PLAN_SETTING_SECTIONS, applyPlanSettingChanges, planSettingChangesApplied, } from "../planSettings.js";
|
|
9
|
-
import {
|
|
9
|
+
import { resolvePlanIndex, planNotFoundError, requirePlans, } from "../plans.js";
|
|
10
10
|
export function registerUpdatePlanSettingsTool(server, bridge, snapshots) {
|
|
11
11
|
server.registerTool("projectionlab_update_plan_settings", {
|
|
12
12
|
title: "Update Plan Settings",
|
|
13
13
|
description: "Safely patches discrete existing settings in ONE configuration section of ONE plan. " +
|
|
14
14
|
"Paths come from projectionlab_get_plan_settings and may address nested fields, such as " +
|
|
15
15
|
'"estate.enabled". Sibling values are preserved server-side. Unknown paths and JSON type ' +
|
|
16
|
-
"changes are rejected
|
|
16
|
+
"changes are rejected, and values outside an observed field's allowed values are refused; " +
|
|
17
|
+
"see projectionlab://data-model for units and allowed values. When confirm is false (default), returns a dry-run diff. When " +
|
|
17
18
|
"confirm is true, auto-snapshots all plans, restores the patched plan, and verifies each value.",
|
|
18
19
|
inputSchema: {
|
|
19
20
|
planIdentifier: z
|
|
20
21
|
.string()
|
|
21
22
|
.trim()
|
|
22
23
|
.min(1)
|
|
23
|
-
.describe("Plan name (case-insensitive
|
|
24
|
+
.describe("Plan name (case-insensitive; a partial match must identify exactly one plan) or exact plan ID"),
|
|
24
25
|
section: z
|
|
25
26
|
.enum(PLAN_SETTING_SECTIONS)
|
|
26
27
|
.describe("The configuration section containing the settings"),
|
|
27
28
|
changes: z
|
|
28
29
|
.record(z.string(), z.unknown())
|
|
29
|
-
.describe('Dot-path to value map, e.g. { "inflation":
|
|
30
|
+
.describe('Dot-path to value map, e.g. { "inflation": 3, "estate.enabled": true }. Every path must already exist and retain its current JSON type. Rates use the scale of the current value: most are percentage points (inflation 3 means 3%), some are fractions (taxStrategy.bracketRate 0.22 means 22%).'),
|
|
30
31
|
confirm: z
|
|
31
32
|
.boolean()
|
|
32
33
|
.default(false)
|
|
@@ -45,11 +46,11 @@ export function registerUpdatePlanSettingsTool(server, bridge, snapshots) {
|
|
|
45
46
|
}
|
|
46
47
|
const data = await bridge.exportData({ fresh: true });
|
|
47
48
|
const plans = requirePlans(data);
|
|
48
|
-
const planIndex =
|
|
49
|
+
const planIndex = resolvePlanIndex(plans, planIdentifier);
|
|
49
50
|
if (planIndex === -1)
|
|
50
51
|
throw planNotFoundError(plans, planIdentifier);
|
|
51
52
|
const plan = plans[planIndex];
|
|
52
|
-
const { updated, changes } = applyPlanSettingChanges(plan[section], incoming);
|
|
53
|
+
const { updated, changes } = applyPlanSettingChanges(plan[section], incoming, section);
|
|
53
54
|
if (!confirm) {
|
|
54
55
|
return {
|
|
55
56
|
content: [
|
|
@@ -87,7 +88,9 @@ export function registerUpdatePlanSettingsTool(server, bridge, snapshots) {
|
|
|
87
88
|
],
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
|
-
await snapshots.create("updatePlanSettings", ["plans"], {
|
|
91
|
+
const snapshot = await snapshots.create("updatePlanSettings", ["plans"], {
|
|
92
|
+
plans,
|
|
93
|
+
});
|
|
91
94
|
const updatedPlans = [...plans];
|
|
92
95
|
updatedPlans[planIndex] = { ...plan, [section]: updated };
|
|
93
96
|
log.info("updatePlanSettings", `Patching ${Object.keys(changes).length} setting(s) in "${section}" of plan "${plan.name}"`);
|
|
@@ -109,6 +112,7 @@ export function registerUpdatePlanSettingsTool(server, bridge, snapshots) {
|
|
|
109
112
|
section,
|
|
110
113
|
changes: redactSecrets(changes, { byName: true }),
|
|
111
114
|
verified,
|
|
115
|
+
snapshotId: snapshot.id,
|
|
112
116
|
message: verified
|
|
113
117
|
? "Plan settings patched and verified. Snapshot saved automatically."
|
|
114
118
|
: "Plan settings update was sent but verification did not confirm every value. A snapshot was saved; inspect the plan settings and roll back if needed.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updatePlanSettings.js","sourceRoot":"","sources":["../../src/tools/updatePlanSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"updatePlanSettings.js","sourceRoot":"","sources":["../../src/tools/updatePlanSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,GAEb,MAAM,aAAa,CAAC;AAErB,MAAM,UAAU,8BAA8B,CAC5C,MAAiB,EACjB,MAAc,EACd,SAA0B;IAE1B,MAAM,CAAC,YAAY,CACjB,oCAAoC,EACpC;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,sFAAsF;YACtF,yFAAyF;YACzF,0FAA0F;YAC1F,2FAA2F;YAC3F,6HAA6H;YAC7H,gGAAgG;QAClG,WAAW,EAAE;YACX,cAAc,EAAE,CAAC;iBACd,MAAM,EAAE;iBACR,IAAI,EAAE;iBACN,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CACP,+FAA+F,CAChG;YACH,OAAO,EAAE,CAAC;iBACP,IAAI,CAAC,qBAAqB,CAAC;iBAC3B,QAAQ,CAAC,mDAAmD,CAAC;YAChE,OAAO,EAAE,CAAC;iBACP,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;iBAC/B,QAAQ,CACP,mSAAmS,CACpS;YACH,OAAO,EAAE,CAAC;iBACP,OAAO,EAAE;iBACT,OAAO,CAAC,KAAK,CAAC;iBACd,QAAQ,CACP,kEAAkE,CACnE;SACJ;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QAChE,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,IAAI,kBAAkB,CAC1B,gBAAgB,EAChB,+EAA+E,EAC/E,+IAA+I,CAChJ,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YAC1D,IAAI,SAAS,KAAK,CAAC,CAAC;gBAAE,MAAM,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YACrE,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAY,CAAC;YACzC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,uBAAuB,CAClD,IAAI,CAAC,OAAO,CAAC,EACb,QAAQ,EACR,OAAO,CACR,CAAC;YAEF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,MAAM,CAAC;gCACX,MAAM,EAAE,IAAI;gCACZ,SAAS,EAAE,oBAAoB;gCAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI;gCACnB,MAAM,EAAE,IAAI,CAAC,EAAE;gCACf,OAAO;gCACP,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;gCACjD,OAAO,EACL,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;oCAC/B,CAAC,CAAC,oEAAoE;oCACtE,CAAC,CAAC,mBAAmB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,mBAAmB,OAAO,cAAc,IAAI,CAAC,IAAI,iCAAiC;6BACvI,CAAC;yBACH;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,MAAM,CAAC;gCACX,OAAO,EAAE,IAAI;gCACb,QAAQ,EAAE,IAAI,CAAC,IAAI;gCACnB,OAAO;gCACP,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;gCACjD,QAAQ,EAAE,IAAI;gCACd,OAAO,EAAE,mEAAmE;6BAC7E,CAAC;yBACH;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;gBACvE,KAAK;aACN,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YAChC,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;YAC1D,GAAG,CAAC,IAAI,CACN,oBAAoB,EACpB,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,mBAAmB,OAAO,cAAc,IAAI,CAAC,IAAI,GAAG,CAC5F,CAAC;YACF,MAAM,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC1C,MAAM,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;YAExC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,YAAY,GAAG,CACnB,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CACxD,CAAC,IAAI,CACJ,CAAC,IAAI,EAAE,EAAE,CACP,IAAI;gBACJ,OAAO,IAAI,KAAK,QAAQ;gBACvB,IAAgB,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CACZ,CAAC;YACzB,MAAM,QAAQ,GACZ,CAAC,CAAC,YAAY;gBACd,yBAAyB,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;YAE5D,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,MAAM,CAAC;4BACX,OAAO,EAAE,IAAI;4BACb,QAAQ,EAAE,IAAI,CAAC,IAAI;4BACnB,OAAO;4BACP,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;4BACjD,QAAQ;4BACR,UAAU,EAAE,QAAQ,CAAC,EAAE;4BACvB,OAAO,EAAE,QAAQ;gCACf,CAAC,CAAC,mEAAmE;gCACrE,CAAC,CAAC,sJAAsJ;yBAC3J,CAAC;qBACH;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/types/wire.d.ts
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Transport: JSON text frames over ws://127.0.0.1:<port>. The browser side is
|
|
9
9
|
* always the WebSocket client. The server accepts one active executor
|
|
10
|
-
* connection at a time
|
|
10
|
+
* connection at a time. The incumbent keeps it: a second authenticated
|
|
11
|
+
* executor is refused with 4004 and retries until the incumbent goes away,
|
|
12
|
+
* unless it requests takeover or repeats the incumbent's instanceId.
|
|
11
13
|
*/
|
|
12
14
|
/** Bumped on any breaking change to frame shapes or semantics. */
|
|
13
15
|
export declare const PROTOCOL_VERSION = 1;
|
|
@@ -33,11 +35,32 @@ export interface HelloFrame {
|
|
|
33
35
|
protocolVersion: number;
|
|
34
36
|
/** "extension/<version>" or "bootstrap/<version>", the release version from package.json */
|
|
35
37
|
executor: string;
|
|
38
|
+
/**
|
|
39
|
+
* Stable id of this executor installation (one UUID per extension
|
|
40
|
+
* installation, one per page load for the snippet). Additive: absent from
|
|
41
|
+
* 1.1.0 executors, and the server treats it as absent unless it is a
|
|
42
|
+
* string of 1 to 64 characters. A hello whose instanceId equals the
|
|
43
|
+
* connected executor's replaces that connection, so an executor is never
|
|
44
|
+
* locked out by its own stale socket.
|
|
45
|
+
*/
|
|
46
|
+
instanceId?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Ask the server to switch to this executor now, closing the incumbent
|
|
49
|
+
* with 4003. Additive: only exactly `true` counts. The extension sends it
|
|
50
|
+
* when the user presses Save on the options page.
|
|
51
|
+
*/
|
|
52
|
+
takeover?: boolean;
|
|
36
53
|
}
|
|
37
54
|
/** Server acknowledges a valid hello. Requests only flow after this. */
|
|
38
55
|
export interface HelloAckFrame {
|
|
39
56
|
type: "helloAck";
|
|
40
57
|
protocolVersion: number;
|
|
58
|
+
/**
|
|
59
|
+
* The server's release version (package.json). Additive: executors that
|
|
60
|
+
* ignore it keep working, and older servers simply omit it. The extension
|
|
61
|
+
* shows a line when its own version differs.
|
|
62
|
+
*/
|
|
63
|
+
serverVersion?: string;
|
|
41
64
|
}
|
|
42
65
|
export interface RequestFrame {
|
|
43
66
|
type: "request";
|
|
@@ -83,6 +106,8 @@ export declare const CLOSE_CODES: {
|
|
|
83
106
|
readonly AUTH_FAILED: 4001;
|
|
84
107
|
/** Protocol version mismatch. */
|
|
85
108
|
readonly VERSION_MISMATCH: 4002;
|
|
86
|
-
/** A
|
|
109
|
+
/** A takeover replaced this executor; retry slowly, the next attempt normally gets BUSY. */
|
|
87
110
|
readonly REPLACED: 4003;
|
|
111
|
+
/** Another executor holds the connection; retry later. */
|
|
112
|
+
readonly BUSY: 4004;
|
|
88
113
|
};
|
package/dist/types/wire.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Transport: JSON text frames over ws://127.0.0.1:<port>. The browser side is
|
|
9
9
|
* always the WebSocket client. The server accepts one active executor
|
|
10
|
-
* connection at a time
|
|
10
|
+
* connection at a time. The incumbent keeps it: a second authenticated
|
|
11
|
+
* executor is refused with 4004 and retries until the incumbent goes away,
|
|
12
|
+
* unless it requests takeover or repeats the incumbent's instanceId.
|
|
11
13
|
*/
|
|
12
14
|
/** Bumped on any breaking change to frame shapes or semantics. */
|
|
13
15
|
export const PROTOCOL_VERSION = 1;
|
|
@@ -21,7 +23,9 @@ export const CLOSE_CODES = {
|
|
|
21
23
|
AUTH_FAILED: 4001,
|
|
22
24
|
/** Protocol version mismatch. */
|
|
23
25
|
VERSION_MISMATCH: 4002,
|
|
24
|
-
/** A
|
|
26
|
+
/** A takeover replaced this executor; retry slowly, the next attempt normally gets BUSY. */
|
|
25
27
|
REPLACED: 4003,
|
|
28
|
+
/** Another executor holds the connection; retry later. */
|
|
29
|
+
BUSY: 4004,
|
|
26
30
|
};
|
|
27
31
|
//# sourceMappingURL=wire.js.map
|
package/dist/types/wire.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wire.js","sourceRoot":"","sources":["../../src/types/wire.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wire.js","sourceRoot":"","sources":["../../src/types/wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC,kFAAkF;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAqG5C,gDAAgD;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,8FAA8F;IAC9F,WAAW,EAAE,IAAI;IACjB,iCAAiC;IACjC,gBAAgB,EAAE,IAAI;IACtB,4FAA4F;IAC5F,QAAQ,EAAE,IAAI;IACd,0DAA0D;IAC1D,IAAI,EAAE,IAAI;CACF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type FetchLike = (url: string, init: {
|
|
2
|
+
headers: Record<string, string>;
|
|
3
|
+
signal: AbortSignal;
|
|
4
|
+
}) => Promise<{
|
|
5
|
+
ok: boolean;
|
|
6
|
+
json(): Promise<unknown>;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Read the `version` field of the registry's latest-release document.
|
|
10
|
+
* Any failure (offline, timeout, non-200, bad JSON, missing or unparsable
|
|
11
|
+
* version) resolves to null; this never rejects.
|
|
12
|
+
*/
|
|
13
|
+
export declare function fetchLatestVersion(fetchImpl?: FetchLike, timeoutMs?: number): Promise<string | null>;
|
|
14
|
+
export interface UpdateCheck {
|
|
15
|
+
/** Start the lookup; without PL_UPDATE_CHECK=false and at most once. */
|
|
16
|
+
start(fetchImpl?: FetchLike): void;
|
|
17
|
+
/** The latest version found, or null while unknown or disabled. */
|
|
18
|
+
latest(): string | null;
|
|
19
|
+
}
|
|
20
|
+
/** A fresh holder; the module-level one is what the server uses. */
|
|
21
|
+
export declare function createUpdateCheck(): UpdateCheck;
|
|
22
|
+
export declare const updateCheck: UpdateCheck;
|