@suveren/gateway 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/integrations/calendar.json +3 -0
- package/content/integrations/crm.json +10 -0
- package/content/integrations/deploy-github.json +1 -0
- package/content/integrations/erp.json +4 -0
- package/content/integrations/gmail.json +4 -0
- package/content/integrations/linkedin.json +4 -0
- package/content/integrations/mail.json +1 -0
- package/content/integrations/mollie.json +5 -0
- package/content/integrations/records.json +4 -0
- package/dist/control-plane/index.mjs +81 -32
- package/dist/mcp-server/http.mjs +51 -5
- package/dist/ui/assets/index-CSC5vFza.css +1 -0
- package/dist/ui/assets/index-CoAHzend.js +123 -0
- package/dist/ui/index.html +2 -2
- package/node_modules/undici/docs/docs/api/Client.md +2 -0
- package/node_modules/undici/lib/core/connect.js +10 -4
- package/node_modules/undici/lib/core/symbols.js +1 -0
- package/node_modules/undici/lib/dispatcher/agent.js +6 -2
- package/node_modules/undici/lib/dispatcher/client-h1.js +0 -2
- package/node_modules/undici/lib/dispatcher/client-h2.js +0 -4
- package/node_modules/undici/lib/dispatcher/client.js +3 -2
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +12 -0
- package/node_modules/undici/lib/handler/cache-handler.js +48 -0
- package/node_modules/undici/lib/handler/deduplication-handler.js +57 -13
- package/node_modules/undici/lib/handler/redirect-handler.js +8 -1
- package/node_modules/undici/lib/interceptor/decompress.js +15 -5
- package/node_modules/undici/lib/web/cookies/index.js +3 -1
- package/node_modules/undici/lib/web/cookies/parse.js +138 -137
- package/node_modules/undici/lib/web/cookies/util.js +21 -2
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +90 -9
- package/node_modules/undici/lib/web/eventsource/eventsource.js +4 -1
- package/node_modules/undici/lib/web/fetch/index.js +3 -3
- package/node_modules/undici/lib/web/infra/index.js +14 -0
- package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +5 -5
- package/node_modules/undici/lib/web/websocket/receiver.js +13 -0
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/client.d.ts +14 -0
- package/package.json +1 -1
- package/dist/ui/assets/index-C2BnlNib.js +0 -123
- package/dist/ui/assets/index-DPgewsLG.css +0 -1
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
124
|
"create_event": {
|
|
125
|
+
"summary": "Event: {summary|short}[ on {start.dateTime,start.date|date}]",
|
|
125
126
|
"executionMapping": {
|
|
126
127
|
"duration_minutes": "duration",
|
|
127
128
|
"lookahead_days": "lookahead",
|
|
@@ -143,6 +144,7 @@
|
|
|
143
144
|
"actionLabel": "Event created"
|
|
144
145
|
},
|
|
145
146
|
"update_event": {
|
|
147
|
+
"summary": "Update event[: {summary|short}]",
|
|
146
148
|
"executionMapping": {
|
|
147
149
|
"attendees": [
|
|
148
150
|
{
|
|
@@ -164,6 +166,7 @@
|
|
|
164
166
|
"actionLabel": "Event updated"
|
|
165
167
|
},
|
|
166
168
|
"delete_event": {
|
|
169
|
+
"summary": "Delete an event",
|
|
167
170
|
"executionMapping": {
|
|
168
171
|
"calendarId": "allowed_calendars"
|
|
169
172
|
},
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
"overrides": {
|
|
76
76
|
"create_contact": {
|
|
77
|
+
"summary": "Create contact {name}[ ({company})]",
|
|
77
78
|
"executionMapping": {
|
|
78
79
|
"type": "contact_type"
|
|
79
80
|
},
|
|
@@ -94,6 +95,7 @@
|
|
|
94
95
|
}
|
|
95
96
|
},
|
|
96
97
|
"update_contact": {
|
|
98
|
+
"summary": "Update contact {name,id}",
|
|
97
99
|
"executionMapping": {
|
|
98
100
|
"contact_type": "contact_type"
|
|
99
101
|
},
|
|
@@ -123,6 +125,7 @@
|
|
|
123
125
|
}
|
|
124
126
|
},
|
|
125
127
|
"delete_contact": {
|
|
128
|
+
"summary": "Archive a {contact_type} contact",
|
|
126
129
|
"executionMapping": {
|
|
127
130
|
"contact_type": "contact_type"
|
|
128
131
|
},
|
|
@@ -152,6 +155,7 @@
|
|
|
152
155
|
}
|
|
153
156
|
},
|
|
154
157
|
"restore_contact": {
|
|
158
|
+
"summary": "Restore a {contact_type} contact",
|
|
155
159
|
"executionMapping": {
|
|
156
160
|
"contact_type": "contact_type"
|
|
157
161
|
},
|
|
@@ -181,6 +185,7 @@
|
|
|
181
185
|
}
|
|
182
186
|
},
|
|
183
187
|
"convert_contact": {
|
|
188
|
+
"summary": "Convert a contact to {to_type}",
|
|
184
189
|
"executionMapping": {
|
|
185
190
|
"contact_type": "contact_type"
|
|
186
191
|
},
|
|
@@ -210,6 +215,7 @@
|
|
|
210
215
|
}
|
|
211
216
|
},
|
|
212
217
|
"log_activity": {
|
|
218
|
+
"summary": "Log {type}: {summary|short}",
|
|
213
219
|
"executionMapping": {
|
|
214
220
|
"contact_type": "contact_type"
|
|
215
221
|
},
|
|
@@ -229,6 +235,7 @@
|
|
|
229
235
|
}
|
|
230
236
|
},
|
|
231
237
|
"create_deal": {
|
|
238
|
+
"summary": "Create deal: {title|short}[ — {value|money}]",
|
|
232
239
|
"executionMapping": {
|
|
233
240
|
"contact_type": "contact_type"
|
|
234
241
|
},
|
|
@@ -248,6 +255,7 @@
|
|
|
248
255
|
}
|
|
249
256
|
},
|
|
250
257
|
"update_deal": {
|
|
258
|
+
"summary": "Update deal[: {title|short}][ — {value|money}]",
|
|
251
259
|
"executionMapping": {
|
|
252
260
|
"contact_type": "contact_type"
|
|
253
261
|
},
|
|
@@ -276,6 +284,7 @@
|
|
|
276
284
|
}
|
|
277
285
|
},
|
|
278
286
|
"create_task": {
|
|
287
|
+
"summary": "Create task: {title|short}[ (due {due_date|date})]",
|
|
279
288
|
"executionMapping": {
|
|
280
289
|
"contact_type": "contact_type"
|
|
281
290
|
},
|
|
@@ -295,6 +304,7 @@
|
|
|
295
304
|
}
|
|
296
305
|
},
|
|
297
306
|
"complete_task": {
|
|
307
|
+
"summary": "Complete a task",
|
|
298
308
|
"executionMapping": {
|
|
299
309
|
"contact_type": "contact_type"
|
|
300
310
|
},
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
"requiredValue": "unlimited"
|
|
100
100
|
},
|
|
101
101
|
"create_quote": {
|
|
102
|
+
"summary": "Quote of {value|money} net[ — {discount_pct|percent} discount]",
|
|
102
103
|
"executionMapping": {
|
|
103
104
|
"value": "value",
|
|
104
105
|
"discount_pct": "discount_pct",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
}
|
|
134
135
|
},
|
|
135
136
|
"update_quote": {
|
|
137
|
+
"summary": "Update quote to {value|money} net[ — {discount_pct|percent} discount]",
|
|
136
138
|
"executionMapping": {
|
|
137
139
|
"value": "value",
|
|
138
140
|
"discount_pct": "discount_pct",
|
|
@@ -161,6 +163,7 @@
|
|
|
161
163
|
}
|
|
162
164
|
},
|
|
163
165
|
"send_quote": {
|
|
166
|
+
"summary": "Send quote of {value|money} net[ — {discount_pct|percent} discount]",
|
|
164
167
|
"executionMapping": {
|
|
165
168
|
"value": "value",
|
|
166
169
|
"discount_pct": "discount_pct",
|
|
@@ -179,6 +182,7 @@
|
|
|
179
182
|
}
|
|
180
183
|
},
|
|
181
184
|
"convert_quote_to_order": {
|
|
185
|
+
"summary": "Order of {value|money} net from a quote",
|
|
182
186
|
"executionMapping": {
|
|
183
187
|
"value": "value",
|
|
184
188
|
"discount_pct": "discount_pct",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
},
|
|
81
81
|
"overrides": {
|
|
82
82
|
"send_message": {
|
|
83
|
+
"summary": "Email to {to|list}: {subject|short}",
|
|
83
84
|
"executionMapping": {
|
|
84
85
|
"to": [
|
|
85
86
|
{
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
"actionLabel": "Email sent"
|
|
109
110
|
},
|
|
110
111
|
"create_draft": {
|
|
112
|
+
"summary": "Draft email to {to|list}[: {subject|short}]",
|
|
111
113
|
"executionMapping": {
|
|
112
114
|
"to": [
|
|
113
115
|
{
|
|
@@ -136,6 +138,7 @@
|
|
|
136
138
|
"actionLabel": "Email drafted"
|
|
137
139
|
},
|
|
138
140
|
"send_draft": {
|
|
141
|
+
"summary": "Send a draft email",
|
|
139
142
|
"executionMapping": {},
|
|
140
143
|
"staticExecution": {
|
|
141
144
|
"recipient_count": 1,
|
|
@@ -206,6 +209,7 @@
|
|
|
206
209
|
}
|
|
207
210
|
},
|
|
208
211
|
"delete_draft": {
|
|
212
|
+
"summary": "Delete a draft email",
|
|
209
213
|
"executionMapping": {},
|
|
210
214
|
"staticExecution": {
|
|
211
215
|
"recipient_count": 0,
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"overrides": {
|
|
64
64
|
"create_post": {
|
|
65
|
+
"summary": "LinkedIn post: {text|short}",
|
|
65
66
|
"executionMapping": {
|
|
66
67
|
"visibility": "audience"
|
|
67
68
|
},
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
"actionLabel": "Post published"
|
|
74
75
|
},
|
|
75
76
|
"create_image_post": {
|
|
77
|
+
"summary": "LinkedIn image post: {text|short}",
|
|
76
78
|
"executionMapping": {
|
|
77
79
|
"visibility": "audience"
|
|
78
80
|
},
|
|
@@ -84,6 +86,7 @@
|
|
|
84
86
|
"actionLabel": "Image post published"
|
|
85
87
|
},
|
|
86
88
|
"create_article_post": {
|
|
89
|
+
"summary": "LinkedIn article: {title,articleUrl|short}",
|
|
87
90
|
"executionMapping": {
|
|
88
91
|
"visibility": "audience"
|
|
89
92
|
},
|
|
@@ -95,6 +98,7 @@
|
|
|
95
98
|
"actionLabel": "Article published"
|
|
96
99
|
},
|
|
97
100
|
"delete_post": {
|
|
101
|
+
"summary": "Delete a LinkedIn post",
|
|
98
102
|
"executionMapping": {},
|
|
99
103
|
"staticExecution": {
|
|
100
104
|
"allowed_platforms": "linkedin",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"overrides": {
|
|
40
40
|
"CreatePayment": {
|
|
41
|
+
"summary": "Payment of {amount|money}: {description|short}",
|
|
41
42
|
"executionMapping": {
|
|
42
43
|
"amount": "amount",
|
|
43
44
|
"currency": "currency"
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
59
|
"CreatePaymentLink": {
|
|
60
|
+
"summary": "Payment link[ of {amount|money}]: {description|short}",
|
|
59
61
|
"executionMapping": {
|
|
60
62
|
"amount": "amount",
|
|
61
63
|
"currency": "currency"
|
|
@@ -89,12 +91,14 @@
|
|
|
89
91
|
}
|
|
90
92
|
},
|
|
91
93
|
"CancelSubscription": {
|
|
94
|
+
"summary": "Cancel a subscription",
|
|
92
95
|
"executionMapping": {},
|
|
93
96
|
"staticExecution": {
|
|
94
97
|
"action_type": "subscribe"
|
|
95
98
|
}
|
|
96
99
|
},
|
|
97
100
|
"CreateCustomer": {
|
|
101
|
+
"summary": "Create payment customer[ {name}]",
|
|
98
102
|
"executionMapping": {},
|
|
99
103
|
"staticExecution": {
|
|
100
104
|
"action_type": "charge"
|
|
@@ -113,6 +117,7 @@
|
|
|
113
117
|
}
|
|
114
118
|
},
|
|
115
119
|
"RevokeMandate": {
|
|
120
|
+
"summary": "Revoke a payment mandate",
|
|
116
121
|
"executionMapping": {},
|
|
117
122
|
"staticExecution": {
|
|
118
123
|
"action_type": "charge"
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"category": "disabled"
|
|
53
53
|
},
|
|
54
54
|
"create_record": {
|
|
55
|
+
"summary": "Create {type}: {title|short}",
|
|
55
56
|
"executionMapping": {},
|
|
56
57
|
"staticExecution": {
|
|
57
58
|
"action_type": "write"
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
"actionLabel": "Record created"
|
|
60
61
|
},
|
|
61
62
|
"archive_record": {
|
|
63
|
+
"summary": "Archive a record",
|
|
62
64
|
"boundField": "archive_access",
|
|
63
65
|
"requiredValue": "allowed",
|
|
64
66
|
"executionMapping": {},
|
|
@@ -68,10 +70,12 @@
|
|
|
68
70
|
"actionLabel": "Record archived"
|
|
69
71
|
},
|
|
70
72
|
"update_record": {
|
|
73
|
+
"summary": "Update record[: {title|short}]",
|
|
71
74
|
"category": "disabled",
|
|
72
75
|
"actionLabel": "Record updated"
|
|
73
76
|
},
|
|
74
77
|
"delete_record": {
|
|
78
|
+
"summary": "Delete a record",
|
|
75
79
|
"boundField": "delete_access",
|
|
76
80
|
"requiredValue": "allowed",
|
|
77
81
|
"executionMapping": {},
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
8
|
-
import { existsSync as existsSync13, readFileSync as
|
|
9
|
-
import { dirname as
|
|
10
|
-
import { homedir as
|
|
8
|
+
import { existsSync as existsSync13, readFileSync as readFileSync17, renameSync as renameSync5 } from "fs";
|
|
9
|
+
import { dirname as dirname12, join as join17 } from "path";
|
|
10
|
+
import { homedir as homedir10 } from "os";
|
|
11
11
|
import express from "express";
|
|
12
12
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
13
13
|
|
|
@@ -3384,15 +3384,15 @@ import { promisify } from "util";
|
|
|
3384
3384
|
var run = promisify(execFile);
|
|
3385
3385
|
var SUPPORTED = /* @__PURE__ */ new Set(["darwin", "win32", "linux"]);
|
|
3386
3386
|
var MODULE_DIR = pathDirname(fileURLToPath(import.meta.url));
|
|
3387
|
-
function findCli(
|
|
3387
|
+
function findCli(dirname13 = MODULE_DIR) {
|
|
3388
3388
|
const candidates = [
|
|
3389
3389
|
// Bundled (the shipped layout): dist/control-plane → dist → root → bin
|
|
3390
|
-
resolve(
|
|
3390
|
+
resolve(dirname13, "..", "..", "bin", "suveren-gateway.js"),
|
|
3391
3391
|
// Bundled, were the routes/ directory ever preserved.
|
|
3392
|
-
resolve(
|
|
3392
|
+
resolve(dirname13, "..", "..", "..", "bin", "suveren-gateway.js"),
|
|
3393
3393
|
// Dev, running from source: the repo's own bundle directory.
|
|
3394
|
-
resolve(
|
|
3395
|
-
resolve(
|
|
3394
|
+
resolve(dirname13, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
|
|
3395
|
+
resolve(dirname13, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
|
|
3396
3396
|
// Deliberately NO process.cwd() fallback: it makes the result depend on
|
|
3397
3397
|
// where the process happened to be launched from, so the same install
|
|
3398
3398
|
// resolves differently between a shell and a login service — and it would
|
|
@@ -4677,14 +4677,62 @@ function createBlockedSeenRouter(dataDir) {
|
|
|
4677
4677
|
return router;
|
|
4678
4678
|
}
|
|
4679
4679
|
|
|
4680
|
-
// src/routes/
|
|
4680
|
+
// src/routes/tickets-seen.ts
|
|
4681
4681
|
import { Router as Router20 } from "express";
|
|
4682
|
+
|
|
4683
|
+
// src/lib/tickets-seen-store.ts
|
|
4684
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, renameSync as renameSync4 } from "fs";
|
|
4685
|
+
import { homedir as homedir9 } from "os";
|
|
4686
|
+
import { join as join15, dirname as dirname11 } from "path";
|
|
4687
|
+
function storePath3(dataDir) {
|
|
4688
|
+
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join15(homedir9(), ".suveren");
|
|
4689
|
+
return join15(dir, "tickets-seen.json");
|
|
4690
|
+
}
|
|
4691
|
+
function readLastSeenTicketsAt(dataDir) {
|
|
4692
|
+
try {
|
|
4693
|
+
const raw = JSON.parse(readFileSync15(storePath3(dataDir), "utf8"));
|
|
4694
|
+
return typeof raw.lastSeenTicketsAt === "number" && Number.isFinite(raw.lastSeenTicketsAt) ? raw.lastSeenTicketsAt : 0;
|
|
4695
|
+
} catch {
|
|
4696
|
+
return 0;
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
function markTicketsSeen(ts, dataDir) {
|
|
4700
|
+
const safeTs = typeof ts === "number" && Number.isFinite(ts) ? ts : Date.now();
|
|
4701
|
+
const path = storePath3(dataDir);
|
|
4702
|
+
mkdirSync10(dirname11(path), { recursive: true });
|
|
4703
|
+
const tmp = `${path}.tmp`;
|
|
4704
|
+
writeFileSync10(tmp, JSON.stringify({ lastSeenTicketsAt: safeTs }, null, 2) + "\n", "utf8");
|
|
4705
|
+
renameSync4(tmp, path);
|
|
4706
|
+
return safeTs;
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
// src/routes/tickets-seen.ts
|
|
4710
|
+
function createTicketsSeenRouter(dataDir) {
|
|
4711
|
+
const router = Router20();
|
|
4712
|
+
router.get("/", (_req, res) => {
|
|
4713
|
+
res.json({ lastSeenTicketsAt: readLastSeenTicketsAt(dataDir) });
|
|
4714
|
+
});
|
|
4715
|
+
router.post("/", (req, res) => {
|
|
4716
|
+
const body = req.body;
|
|
4717
|
+
const ts = typeof body?.ts === "number" && Number.isFinite(body.ts) ? body.ts : Date.now();
|
|
4718
|
+
try {
|
|
4719
|
+
res.json({ lastSeenTicketsAt: markTicketsSeen(ts, dataDir) });
|
|
4720
|
+
} catch (err) {
|
|
4721
|
+
res.status(500).json({ error: `Could not save: ${err.message}` });
|
|
4722
|
+
}
|
|
4723
|
+
});
|
|
4724
|
+
return router;
|
|
4725
|
+
}
|
|
4726
|
+
|
|
4727
|
+
// src/routes/internal-events.ts
|
|
4728
|
+
import { Router as Router21 } from "express";
|
|
4682
4729
|
import { timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
4683
4730
|
var ALLOWED = [
|
|
4684
4731
|
"proposal-added",
|
|
4685
4732
|
"action-approval-needed",
|
|
4686
4733
|
"execution-failed",
|
|
4687
|
-
"denial-recorded"
|
|
4734
|
+
"denial-recorded",
|
|
4735
|
+
"ticket-recorded"
|
|
4688
4736
|
];
|
|
4689
4737
|
var SESSION_EXPIRED = "session-expired";
|
|
4690
4738
|
var AS_KEY_MISMATCH = "as-key-mismatch";
|
|
@@ -4698,7 +4746,7 @@ function secretMatches2(provided, expected) {
|
|
|
4698
4746
|
return timingSafeEqual3(a, b);
|
|
4699
4747
|
}
|
|
4700
4748
|
function createInternalEventsRouter(getSecret, onSessionExpired, onAsKeyMismatch, onAsTlsMismatch) {
|
|
4701
|
-
const router =
|
|
4749
|
+
const router = Router21();
|
|
4702
4750
|
router.post("/event", (req, res) => {
|
|
4703
4751
|
if (!secretMatches2(req.headers["x-internal-secret"], getSecret())) {
|
|
4704
4752
|
res.status(401).json({ error: "Unauthorized" });
|
|
@@ -4732,7 +4780,7 @@ function createInternalEventsRouter(getSecret, onSessionExpired, onAsKeyMismatch
|
|
|
4732
4780
|
}
|
|
4733
4781
|
|
|
4734
4782
|
// src/routes/internal-mandate.ts
|
|
4735
|
-
import { Router as
|
|
4783
|
+
import { Router as Router22 } from "express";
|
|
4736
4784
|
import { timingSafeEqual as timingSafeEqual4, randomUUID } from "crypto";
|
|
4737
4785
|
|
|
4738
4786
|
// src/lib/mandate-ceremony.ts
|
|
@@ -4914,7 +4962,7 @@ function secretMatches3(provided, expected) {
|
|
|
4914
4962
|
return a.length === b.length && timingSafeEqual4(a, b);
|
|
4915
4963
|
}
|
|
4916
4964
|
function createInternalMandateRouter(getSecret, deps) {
|
|
4917
|
-
const router =
|
|
4965
|
+
const router = Router22();
|
|
4918
4966
|
router.post("/mandate", async (req, res) => {
|
|
4919
4967
|
if (!secretMatches3(req.header("X-Internal-Secret") ?? void 0, getSecret())) {
|
|
4920
4968
|
res.status(401).json({ error: "unauthorized" });
|
|
@@ -5117,17 +5165,17 @@ function buildSessionHealth(vault2) {
|
|
|
5117
5165
|
}
|
|
5118
5166
|
|
|
5119
5167
|
// src/lib/denials-reader.ts
|
|
5120
|
-
import { existsSync as existsSync12, readFileSync as
|
|
5121
|
-
import { join as
|
|
5168
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16 } from "fs";
|
|
5169
|
+
import { join as join16 } from "path";
|
|
5122
5170
|
function loadDenials(dataDir, decrypt) {
|
|
5123
|
-
const encPath =
|
|
5124
|
-
const plainPath =
|
|
5171
|
+
const encPath = join16(dataDir, "denials.enc.json");
|
|
5172
|
+
const plainPath = join16(dataDir, "denials.json");
|
|
5125
5173
|
if (existsSync12(encPath)) {
|
|
5126
|
-
const { blob } = JSON.parse(
|
|
5174
|
+
const { blob } = JSON.parse(readFileSync16(encPath, "utf-8"));
|
|
5127
5175
|
return JSON.parse(decrypt(blob)).records ?? [];
|
|
5128
5176
|
}
|
|
5129
5177
|
if (existsSync12(plainPath)) {
|
|
5130
|
-
return JSON.parse(
|
|
5178
|
+
return JSON.parse(readFileSync16(plainPath, "utf-8")).records ?? [];
|
|
5131
5179
|
}
|
|
5132
5180
|
return [];
|
|
5133
5181
|
}
|
|
@@ -5151,11 +5199,11 @@ function isSimulationMode() {
|
|
|
5151
5199
|
// src/index.ts
|
|
5152
5200
|
(function migrateDataDir() {
|
|
5153
5201
|
if (process.env.SUVEREN_DATA_DIR) return;
|
|
5154
|
-
const oldDir =
|
|
5155
|
-
const newDir =
|
|
5202
|
+
const oldDir = join17(homedir10(), ".hap");
|
|
5203
|
+
const newDir = join17(homedir10(), ".suveren");
|
|
5156
5204
|
if (!existsSync13(newDir) && existsSync13(oldDir)) {
|
|
5157
5205
|
try {
|
|
5158
|
-
|
|
5206
|
+
renameSync5(oldDir, newDir);
|
|
5159
5207
|
console.error(`[Control Plane] Migrated data directory: ${oldDir} \u2192 ${newDir}`);
|
|
5160
5208
|
} catch (err) {
|
|
5161
5209
|
console.error(`[Control Plane] FATAL: could not migrate data directory ${oldDir} \u2192 ${newDir}:`, err);
|
|
@@ -5163,7 +5211,7 @@ function isSimulationMode() {
|
|
|
5163
5211
|
}
|
|
5164
5212
|
}
|
|
5165
5213
|
})();
|
|
5166
|
-
var DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
5214
|
+
var DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
5167
5215
|
var SP_URL = resolveAsUrl(DATA_DIR);
|
|
5168
5216
|
validatePinTlsForUrl(resolvePinTls(DATA_DIR), SP_URL);
|
|
5169
5217
|
var POLICY_LOCKED = [...readPolicy().locked];
|
|
@@ -5171,7 +5219,7 @@ var POLICY_LOCKED_INSTALL_METHOD = readPolicy().policy.installMethod;
|
|
|
5171
5219
|
var POLICY_LOCKED_TEAM = readPolicy().policy.team;
|
|
5172
5220
|
var port = parseInt(process.env.SUVEREN_CP_PORT ?? "3402", 10);
|
|
5173
5221
|
var HAP_MODE = process.env.HAP_MODE ?? "personal";
|
|
5174
|
-
var UI_DIST = process.env.HAP_UI_DIST ??
|
|
5222
|
+
var UI_DIST = process.env.HAP_UI_DIST ?? join17(import.meta.dirname ?? __dirname, "../../ui/dist");
|
|
5175
5223
|
var vault = new Vault(DATA_DIR);
|
|
5176
5224
|
var shownSnapshotStore = new ShownSnapshotStore(DATA_DIR);
|
|
5177
5225
|
(function repairIfAsUrlChanged() {
|
|
@@ -5481,6 +5529,7 @@ app.use("/autostart", jsonParser, authGuard, createAutostartRouter());
|
|
|
5481
5529
|
app.use("/api/gateway-settings", jsonParser, authGuard, createGatewaySettingsRouter());
|
|
5482
5530
|
app.use("/api/archived-mandates", jsonParser, authGuard, createArchivedMandatesRouter());
|
|
5483
5531
|
app.use("/api/blocked-seen", jsonParser, authGuard, createBlockedSeenRouter());
|
|
5532
|
+
app.use("/api/tickets-seen", jsonParser, authGuard, createTicketsSeenRouter());
|
|
5484
5533
|
app.use("/api/encrypt-intent", jsonParser, authGuard, createEncryptIntentRouter());
|
|
5485
5534
|
app.use("/api/evidence-export", authGuard, createEvidenceExportRouter(SP_URL, vault, DATA_DIR, lockAsTlsMismatch));
|
|
5486
5535
|
app.use("/proposal-status", jsonParser, authGuard, createProposalStatusRouter(SP_URL, vault, DATA_DIR, lockAsTlsMismatch, shownSnapshotStore));
|
|
@@ -5657,7 +5706,7 @@ app.get("/as-pairing", authGuard, (_req, res) => {
|
|
|
5657
5706
|
});
|
|
5658
5707
|
app.get("/denials", authGuard, (req, res) => {
|
|
5659
5708
|
try {
|
|
5660
|
-
const dataDir = process.env.SUVEREN_DATA_DIR ??
|
|
5709
|
+
const dataDir = process.env.SUVEREN_DATA_DIR ?? join17(homedir10(), ".suveren");
|
|
5661
5710
|
const all = loadDenials(dataDir, (blob) => vault.decrypt(blob));
|
|
5662
5711
|
const since = Number(req.query.since);
|
|
5663
5712
|
const limit = Number(req.query.limit);
|
|
@@ -5716,12 +5765,12 @@ app.put("/agent-brief/context", jsonParser, authGuard, async (req, res) => {
|
|
|
5716
5765
|
res.status(413).json({ error: `Context exceeds ${AGENT_CONTEXT_MAX_BYTES}-byte cap` });
|
|
5717
5766
|
return;
|
|
5718
5767
|
}
|
|
5719
|
-
const { mkdirSync:
|
|
5768
|
+
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync11, renameSync: renameSync6 } = await import("fs");
|
|
5720
5769
|
const filePath = agentBriefPath();
|
|
5721
|
-
|
|
5770
|
+
mkdirSync11(dirname12(filePath), { recursive: true });
|
|
5722
5771
|
const tmpPath = `${filePath}.tmp`;
|
|
5723
|
-
|
|
5724
|
-
|
|
5772
|
+
writeFileSync11(tmpPath, content, "utf-8");
|
|
5773
|
+
renameSync6(tmpPath, filePath);
|
|
5725
5774
|
res.json({ ok: true });
|
|
5726
5775
|
} catch (err) {
|
|
5727
5776
|
console.error("[Control Plane] agent-brief/context PUT failed:", err);
|
|
@@ -5813,10 +5862,10 @@ function detectRunningVersion() {
|
|
|
5813
5862
|
return process.env.HAP_BUILD_SHA ?? "dev";
|
|
5814
5863
|
}
|
|
5815
5864
|
const dir = import.meta.dirname ?? __dirname;
|
|
5816
|
-
const bundlePkg =
|
|
5865
|
+
const bundlePkg = join17(dir, "..", "..", "package.json");
|
|
5817
5866
|
if (existsSync13(bundlePkg)) {
|
|
5818
5867
|
try {
|
|
5819
|
-
const pkg = JSON.parse(
|
|
5868
|
+
const pkg = JSON.parse(readFileSync17(bundlePkg, "utf8"));
|
|
5820
5869
|
if (pkg.name === "@suveren/gateway" && typeof pkg.version === "string") {
|
|
5821
5870
|
return pkg.version;
|
|
5822
5871
|
}
|
|
@@ -5868,7 +5917,7 @@ if (existsSync13(UI_DIST)) {
|
|
|
5868
5917
|
}));
|
|
5869
5918
|
app.get("*", (_req, res) => {
|
|
5870
5919
|
res.setHeader("Cache-Control", "no-store, must-revalidate");
|
|
5871
|
-
res.sendFile(
|
|
5920
|
+
res.sendFile(join17(UI_DIST, "index.html"));
|
|
5872
5921
|
});
|
|
5873
5922
|
} else {
|
|
5874
5923
|
app.get("/", (_req, res) => {
|
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -3348,6 +3348,7 @@ var SharedState = class {
|
|
|
3348
3348
|
} catch (err) {
|
|
3349
3349
|
throw new ArchiveWriteError(`Receipt archive write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3350
3350
|
}
|
|
3351
|
+
void notifyControlPlane("ticket-recorded");
|
|
3351
3352
|
}
|
|
3352
3353
|
setGateContent(path, authorizationId, profileId, content, opts) {
|
|
3353
3354
|
this.gateStore.set(authorizationId, {
|
|
@@ -4020,10 +4021,44 @@ function invalidDisplayHintsReason(toolName, entry) {
|
|
|
4020
4021
|
}
|
|
4021
4022
|
return null;
|
|
4022
4023
|
}
|
|
4024
|
+
var SUMMARY_FORMATS = ["money", "percent", "list", "short", "date"];
|
|
4025
|
+
function invalidSummaryReason(toolName, entry) {
|
|
4026
|
+
if (entry === null || typeof entry !== "object") return null;
|
|
4027
|
+
const summary = entry.summary;
|
|
4028
|
+
if (summary === void 0) return null;
|
|
4029
|
+
const at = `override "${toolName}".summary`;
|
|
4030
|
+
if (typeof summary !== "string" || summary.trim().length === 0) return `${at} must be a non-empty string`;
|
|
4031
|
+
if (summary.length > 200) return `${at} must be at most 200 characters`;
|
|
4032
|
+
const balanced = (open, close) => {
|
|
4033
|
+
let d = 0;
|
|
4034
|
+
for (const ch of summary) {
|
|
4035
|
+
if (ch === open) {
|
|
4036
|
+
d += 1;
|
|
4037
|
+
if (d > 1) return false;
|
|
4038
|
+
}
|
|
4039
|
+
if (ch === close) {
|
|
4040
|
+
d -= 1;
|
|
4041
|
+
if (d < 0) return false;
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
return d === 0;
|
|
4045
|
+
};
|
|
4046
|
+
if (!balanced("{", "}")) return `${at} has unbalanced or nested { }`;
|
|
4047
|
+
if (!balanced("[", "]")) return `${at} has unbalanced or nested [ ]`;
|
|
4048
|
+
for (const m of summary.matchAll(/\{([^{}]+)\}/g)) {
|
|
4049
|
+
const [paths, fmt, extra] = m[1].split("|").map((x) => x.trim());
|
|
4050
|
+
if (extra !== void 0) return `${at} {${m[1]}} has more than one format`;
|
|
4051
|
+
if (!paths.split(",").every((p) => /^[A-Za-z_][\w-]*(\.[A-Za-z_][\w-]*)*$/.test(p.trim()))) {
|
|
4052
|
+
return `${at} {${m[1]}} has an invalid field path`;
|
|
4053
|
+
}
|
|
4054
|
+
if (fmt !== void 0 && !SUMMARY_FORMATS.includes(fmt)) return `${at} {${m[1]}} has unknown format "${fmt}"`;
|
|
4055
|
+
}
|
|
4056
|
+
return null;
|
|
4057
|
+
}
|
|
4023
4058
|
function invalidManifestPreviewReason(manifest) {
|
|
4024
4059
|
const overrides = manifest.toolGating?.overrides ?? {};
|
|
4025
4060
|
for (const [toolName, entry] of Object.entries(overrides)) {
|
|
4026
|
-
const reason = invalidPreviewReason(toolName, entry) ?? invalidDisplayHintsReason(toolName, entry);
|
|
4061
|
+
const reason = invalidPreviewReason(toolName, entry) ?? invalidDisplayHintsReason(toolName, entry) ?? invalidSummaryReason(toolName, entry);
|
|
4027
4062
|
if (reason) return reason;
|
|
4028
4063
|
}
|
|
4029
4064
|
return null;
|
|
@@ -5338,10 +5373,10 @@ function zeroCappedBound(profileId, bounds, actionType) {
|
|
|
5338
5373
|
}
|
|
5339
5374
|
return null;
|
|
5340
5375
|
}
|
|
5341
|
-
function toolAlwaysListed(tool, isBuiltin) {
|
|
5376
|
+
function toolAlwaysListed(tool, isBuiltin, builtinAlwaysListed = () => false) {
|
|
5342
5377
|
if (tool.internal || !tool.gating?.profile) return false;
|
|
5343
5378
|
if (tool.gating.category === "disabled") return false;
|
|
5344
|
-
if (isBuiltin(tool.integrationId)) return false;
|
|
5379
|
+
if (isBuiltin(tool.integrationId) && !builtinAlwaysListed(tool.integrationId)) return false;
|
|
5345
5380
|
if (!tool.gating.hideUnlessAuthorized) return true;
|
|
5346
5381
|
return Boolean(tool.gating.simulationOnly) && isSimulationMode();
|
|
5347
5382
|
}
|
|
@@ -6406,9 +6441,10 @@ function buildCapabilityMap(profileId, integrationManager2) {
|
|
|
6406
6441
|
function listedWithoutMandate(authorizations, integrationManager2) {
|
|
6407
6442
|
if (!integrationManager2) return [];
|
|
6408
6443
|
const isBuiltin = (id) => integrationManager2.isBuiltin?.(id) ?? false;
|
|
6444
|
+
const builtinAlwaysListed = (id) => integrationManager2.builtinAlwaysListed?.(id) ?? false;
|
|
6409
6445
|
const byProfile = /* @__PURE__ */ new Map();
|
|
6410
6446
|
for (const tool of integrationManager2.getAllTools()) {
|
|
6411
|
-
if (!toolAlwaysListed(tool, isBuiltin)) continue;
|
|
6447
|
+
if (!toolAlwaysListed(tool, isBuiltin, builtinAlwaysListed)) continue;
|
|
6412
6448
|
const profile = tool.gating.profile;
|
|
6413
6449
|
if (authorizations.some((a) => a.complete && profileMatches(a.profileId, profile))) continue;
|
|
6414
6450
|
const short = shortProfileName2(profile);
|
|
@@ -7383,8 +7419,9 @@ function createMcpServer(state2, integrationManager2) {
|
|
|
7383
7419
|
function refreshTools() {
|
|
7384
7420
|
const auths = state2.getEnrichedAuthorizations();
|
|
7385
7421
|
const isBuiltin = (id) => integrationManager2?.isBuiltin?.(id) ?? false;
|
|
7422
|
+
const builtinAlwaysListed = (id) => integrationManager2?.builtinAlwaysListed?.(id) ?? false;
|
|
7386
7423
|
for (const [, { tool, registered }] of proxiedTools) {
|
|
7387
|
-
if (toolAlwaysListed(tool, isBuiltin)) {
|
|
7424
|
+
if (toolAlwaysListed(tool, isBuiltin, builtinAlwaysListed)) {
|
|
7388
7425
|
registered.enable();
|
|
7389
7426
|
} else if (tool.gating?.profile) {
|
|
7390
7427
|
const matchingAuths = auths.filter(
|
|
@@ -8233,6 +8270,10 @@ var IntegrationManager = class {
|
|
|
8233
8270
|
isBuiltin(id) {
|
|
8234
8271
|
return this.builtins.has(id);
|
|
8235
8272
|
}
|
|
8273
|
+
/** A built-in that declares `alwaysListed` (see builtin-integration.ts). */
|
|
8274
|
+
builtinAlwaysListed(id) {
|
|
8275
|
+
return this.builtins.get(id)?.def.alwaysListed === true;
|
|
8276
|
+
}
|
|
8236
8277
|
/**
|
|
8237
8278
|
* Whether `id` may run while simulation mode is on: a connector whose manifest
|
|
8238
8279
|
* carries the `simulation` marker, or a built-in that declares `simulation: true`.
|
|
@@ -9209,6 +9250,11 @@ var reportBuiltin = (deps) => ({
|
|
|
9209
9250
|
// read-only export CLI; writes only the local, vault-encrypted report file)
|
|
9210
9251
|
// — safe during a simulation-mode test.
|
|
9211
9252
|
simulation: true,
|
|
9253
|
+
// Listed without a mandate, like connector tools: an AI client that ignores
|
|
9254
|
+
// tools/list_changed (ChatGPT) otherwise never sees report__* after the
|
|
9255
|
+
// reporting mandate is signed mid-chat (simulation finding, 2026-10-16).
|
|
9256
|
+
// Listing authorizes nothing — the gate still refuses a call without one.
|
|
9257
|
+
alwaysListed: true,
|
|
9212
9258
|
// The same predicate the reporting window uses to refuse a mandate
|
|
9213
9259
|
// (reporting@0.1, or no window set): the gate never selects such a mandate
|
|
9214
9260
|
// for ANY report tool — so write_report is never ticketed under (and never
|