@suveren/gateway 0.2.9 → 0.2.11
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/dist/control-plane/index.mjs +8 -0
- package/dist/mcp-server/http.mjs +98 -82
- package/dist/ui/assets/{index-DIC0vtHi.js → index-D3srGi9r.js} +16 -16
- package/dist/ui/index.html +1 -1
- package/node_modules/@hap/core/dist/index.d.mts +83 -1
- package/node_modules/@hap/core/dist/index.d.ts +83 -1
- package/node_modules/@hap/core/dist/index.js +39 -6
- package/node_modules/@hap/core/dist/index.mjs +36 -6
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/content-binding.ts +83 -0
- package/node_modules/@hap/core/src/index.ts +1 -0
- package/node_modules/@hap/core/src/types.ts +35 -0
- package/package.json +1 -1
- package/profiles/customers/0.4.profile.json +2 -1
- package/profiles/records/0.4.profile.json +2 -1
|
@@ -270,6 +270,12 @@ async function resyncGates() {
|
|
|
270
270
|
}
|
|
271
271
|
return res.json();
|
|
272
272
|
}
|
|
273
|
+
async function runCommittedProposals() {
|
|
274
|
+
await fetch(`${MCP_BASE}/internal/run-committed`, {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: internalHeaders()
|
|
277
|
+
});
|
|
278
|
+
}
|
|
273
279
|
async function getIntegrations() {
|
|
274
280
|
const res = await fetch(`${MCP_BASE}/internal/integrations`, {
|
|
275
281
|
headers: internalHeaders()
|
|
@@ -1935,6 +1941,8 @@ app.use(
|
|
|
1935
1941
|
eventBus.emit("proposal-added");
|
|
1936
1942
|
} else if (method === "POST" && /^\/api\/proposals\/[^/]+\/resolve$/.test(path)) {
|
|
1937
1943
|
eventBus.emit("proposal-resolved");
|
|
1944
|
+
void runCommittedProposals().catch(() => {
|
|
1945
|
+
});
|
|
1938
1946
|
} else if (method === "POST" && /^\/api\/proposals\/[^/]+\/approve$/.test(path)) {
|
|
1939
1947
|
eventBus.emit("proposal-approved");
|
|
1940
1948
|
} else if (method === "POST" && /^\/api\/proposals\/[^/]+\/reject$/.test(path)) {
|
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -902,12 +902,12 @@ function buildMandateBrief(opts) {
|
|
|
902
902
|
}
|
|
903
903
|
|
|
904
904
|
// src/tools/authorizations.ts
|
|
905
|
-
import { getProfile as
|
|
905
|
+
import { getProfile as getProfile3 } from "@hap/core";
|
|
906
906
|
|
|
907
907
|
// src/lib/receipt-footer.ts
|
|
908
908
|
var AS_BASE = (process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai").replace(/\/$/, "");
|
|
909
909
|
var FOOTER_PROFILES = /* @__PURE__ */ new Set(["email", "calendar", "publish"]);
|
|
910
|
-
var CONTENT_FIELD_CANDIDATES = ["body", "text", "description"];
|
|
910
|
+
var CONTENT_FIELD_CANDIDATES = ["body", "text", "description", "content"];
|
|
911
911
|
var FOOTER_MARKER = "\u2014 Sent by an AI agent via Suveren";
|
|
912
912
|
function shouldAttachFooter() {
|
|
913
913
|
return true;
|
|
@@ -940,18 +940,51 @@ function stripFooter(value) {
|
|
|
940
940
|
function appendVerificationFooter(tool, args, receiptId) {
|
|
941
941
|
const profile = tool.gating?.profile;
|
|
942
942
|
if (!profile || !FOOTER_PROFILES.has(profile)) return args;
|
|
943
|
-
if (typeof args.raw === "string" && args.raw.trim().length > 0) {
|
|
944
|
-
console.error(
|
|
945
|
-
`[Suveren MCP] ${tool.namespacedName}: 'raw' message present \u2014 skipping verification footer.`
|
|
946
|
-
);
|
|
947
|
-
return args;
|
|
948
|
-
}
|
|
949
943
|
const field = detectContentField(tool);
|
|
950
944
|
if (!field) return args;
|
|
951
945
|
const current = typeof args[field] === "string" ? args[field] : "";
|
|
952
946
|
return { ...args, [field]: stripFooter(current) + footerText(receiptId) };
|
|
953
947
|
}
|
|
954
948
|
|
|
949
|
+
// src/lib/content-binding.ts
|
|
950
|
+
import { createHash } from "crypto";
|
|
951
|
+
import { canonicalize, getProfile as getProfile2 } from "@hap/core";
|
|
952
|
+
function canonicalizeText(input) {
|
|
953
|
+
const nfc = input.normalize("NFC");
|
|
954
|
+
const lf = nfc.replace(/\r\n?/g, "\n");
|
|
955
|
+
const lines = lf.split("\n").map((line) => line.replace(/[ \t]+$/, ""));
|
|
956
|
+
return lines.join("\n").replace(/\n+$/, "");
|
|
957
|
+
}
|
|
958
|
+
function sha256Hex(bytes) {
|
|
959
|
+
return createHash("sha256").update(bytes, "utf8").digest("hex");
|
|
960
|
+
}
|
|
961
|
+
function getContentBinding(profileId) {
|
|
962
|
+
const profile = getProfile2(profileId);
|
|
963
|
+
return profile?.content_binding;
|
|
964
|
+
}
|
|
965
|
+
function computeContentBinding(profileId, tool, toolArgs) {
|
|
966
|
+
const binding = getContentBinding(profileId);
|
|
967
|
+
if (!binding) return void 0;
|
|
968
|
+
let canonicalBytes;
|
|
969
|
+
if (binding.kind === "jcs") {
|
|
970
|
+
canonicalBytes = canonicalize(toolArgs);
|
|
971
|
+
} else {
|
|
972
|
+
const field = tool ? detectContentField(tool) : null;
|
|
973
|
+
if (!field) return void 0;
|
|
974
|
+
const raw = typeof toolArgs[field] === "string" ? toolArgs[field] : "";
|
|
975
|
+
canonicalBytes = canonicalizeText(raw);
|
|
976
|
+
}
|
|
977
|
+
return {
|
|
978
|
+
contentHash: `sha256:${sha256Hex(canonicalBytes)}`,
|
|
979
|
+
contentBinding: { version: binding.version, kind: binding.kind }
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
function attachReceiptId(tool, args, receiptId) {
|
|
983
|
+
const schema = tool.inputSchema;
|
|
984
|
+
if (!schema?.properties || !("receipt_id" in schema.properties)) return args;
|
|
985
|
+
return { ...args, receipt_id: receiptId };
|
|
986
|
+
}
|
|
987
|
+
|
|
955
988
|
// src/lib/tool-proxy.ts
|
|
956
989
|
import { readFile } from "fs/promises";
|
|
957
990
|
import { extname } from "path";
|
|
@@ -1120,6 +1153,7 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
1120
1153
|
`[Suveren MCP] Warning: tool ${tool.namespacedName} has no action_type in staticExecution. Bounds check may be skipped. Fix the integration manifest.`
|
|
1121
1154
|
);
|
|
1122
1155
|
}
|
|
1156
|
+
const binding = computeContentBinding(auth.profileId, tool, args);
|
|
1123
1157
|
const { receipt } = await state2.spClient.postReceipt({
|
|
1124
1158
|
// v0.5: send the bare content address; the AS reconstructs the
|
|
1125
1159
|
// per-user storage key. Fall back to frameHash only for legacy
|
|
@@ -1130,7 +1164,8 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
1130
1164
|
actionType,
|
|
1131
1165
|
executionContext: { ...execution },
|
|
1132
1166
|
amount: typeof execution.amount === "number" ? execution.amount : void 0,
|
|
1133
|
-
idempotencyKey: randomUUID()
|
|
1167
|
+
idempotencyKey: randomUUID(),
|
|
1168
|
+
...binding ?? {}
|
|
1134
1169
|
});
|
|
1135
1170
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
1136
1171
|
} catch (err) {
|
|
@@ -1210,7 +1245,8 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.`
|
|
|
1210
1245
|
execution: { ...execution },
|
|
1211
1246
|
timestamp: Math.floor(Date.now() / 1e3)
|
|
1212
1247
|
});
|
|
1213
|
-
|
|
1248
|
+
let outgoingArgs = shouldAttachFooter() && receiptId ? appendVerificationFooter(tool, args, receiptId) : args;
|
|
1249
|
+
if (receiptId) outgoingArgs = attachReceiptId(tool, outgoingArgs, receiptId);
|
|
1214
1250
|
return integrationManager2.callTool(tool.integrationId, tool.originalName, outgoingArgs);
|
|
1215
1251
|
}
|
|
1216
1252
|
const reasons = result.errors.map((e) => {
|
|
@@ -1287,7 +1323,9 @@ function buildCapabilityMap(profileId, toolGating, integrationManager2) {
|
|
|
1287
1323
|
} else if (override !== void 0) {
|
|
1288
1324
|
const mappingDesc = Object.entries(override.executionMapping ?? {}).map(([arg, mapping]) => {
|
|
1289
1325
|
if (typeof mapping === "string") return `${mapping} from ${arg}`;
|
|
1290
|
-
return `${mapping.field} from ${arg}
|
|
1326
|
+
if (Array.isArray(mapping)) return `${mapping.map((m) => m.field).join("+")} from ${arg}`;
|
|
1327
|
+
if ("divisor" in mapping) return `${mapping.field} from ${arg} (/${mapping.divisor})`;
|
|
1328
|
+
return `${mapping.field} from ${arg}`;
|
|
1291
1329
|
}).join(", ");
|
|
1292
1330
|
const actionType = override.staticExecution?.action_type ?? "unknown";
|
|
1293
1331
|
gated.push(` - ${tool.originalName}: ${actionType}${mappingDesc ? `, ${mappingDesc}` : ""}`);
|
|
@@ -1353,7 +1391,7 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
1353
1391
|
output2.push("");
|
|
1354
1392
|
output2.push(` Bounds: ${boundsDesc}`);
|
|
1355
1393
|
const shortName = shortProfileName2(auth.profileId);
|
|
1356
|
-
const profile =
|
|
1394
|
+
const profile = getProfile3(auth.profileId) ?? getProfile3(shortName);
|
|
1357
1395
|
if (profile) {
|
|
1358
1396
|
const consumption = getConsumptionState(auth, state2.executionLog, profile);
|
|
1359
1397
|
const consumptionText = formatConsumptionFull(consumption);
|
|
@@ -1406,7 +1444,7 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
1406
1444
|
const lines = [` [${auth.path}] ${auth.profileId} \u2014 ${remainingMin} min remaining`];
|
|
1407
1445
|
lines.push(` Bounds: ${boundsDesc}`);
|
|
1408
1446
|
const shortName = shortProfileName2(auth.profileId);
|
|
1409
|
-
const profile =
|
|
1447
|
+
const profile = getProfile3(auth.profileId) ?? getProfile3(shortName);
|
|
1410
1448
|
if (profile) {
|
|
1411
1449
|
const consumption = getConsumptionState(auth, state2.executionLog, profile);
|
|
1412
1450
|
const compact = formatConsumptionCompact(consumption);
|
|
@@ -1547,15 +1585,18 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
1547
1585
|
}
|
|
1548
1586
|
const integrationId = proposal.tool.slice(0, sep);
|
|
1549
1587
|
const toolName = proposal.tool.slice(sep + 2);
|
|
1588
|
+
const discovered = integrationManager2.getAllTools().find((t) => t.integrationId === integrationId && t.originalName === toolName);
|
|
1550
1589
|
const proposalActionType = typeof proposal.executionContext.action_type === "string" ? proposal.executionContext.action_type : void 0;
|
|
1551
1590
|
if (!proposalActionType) {
|
|
1552
1591
|
console.error(
|
|
1553
1592
|
`[Suveren MCP] Warning: proposal ${proposal.id} has no action_type in executionContext. Bounds check may be skipped. Fix the integration manifest for ${proposal.tool}.`
|
|
1554
1593
|
);
|
|
1555
1594
|
}
|
|
1595
|
+
let receiptId;
|
|
1556
1596
|
try {
|
|
1557
1597
|
const boundsHash = proposal.frameHash.split(":").slice(0, 2).join(":");
|
|
1558
|
-
|
|
1598
|
+
const binding = computeContentBinding(proposal.profileId, discovered, proposal.toolArgs);
|
|
1599
|
+
const { receipt } = await state2.spClient.postReceipt({
|
|
1559
1600
|
boundsHash,
|
|
1560
1601
|
profileId: proposal.profileId,
|
|
1561
1602
|
action: proposal.tool,
|
|
@@ -1563,8 +1604,10 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
1563
1604
|
executionContext: proposal.executionContext,
|
|
1564
1605
|
amount: typeof proposal.executionContext.amount === "number" ? proposal.executionContext.amount : void 0,
|
|
1565
1606
|
proposalId: proposal.id,
|
|
1566
|
-
toolArgs: proposal.toolArgs
|
|
1607
|
+
toolArgs: proposal.toolArgs,
|
|
1608
|
+
...binding ?? {}
|
|
1567
1609
|
});
|
|
1610
|
+
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
1568
1611
|
} catch (err) {
|
|
1569
1612
|
if (err instanceof SPReceiptError) {
|
|
1570
1613
|
const code = err.body.errors?.[0]?.code;
|
|
@@ -1584,7 +1627,20 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
1584
1627
|
};
|
|
1585
1628
|
}
|
|
1586
1629
|
try {
|
|
1587
|
-
|
|
1630
|
+
let outgoingArgs = proposal.toolArgs;
|
|
1631
|
+
if (discovered && receiptId) {
|
|
1632
|
+
if (shouldAttachFooter()) {
|
|
1633
|
+
outgoingArgs = appendVerificationFooter(discovered, outgoingArgs, receiptId);
|
|
1634
|
+
}
|
|
1635
|
+
outgoingArgs = attachReceiptId(discovered, outgoingArgs, receiptId);
|
|
1636
|
+
}
|
|
1637
|
+
const result = await integrationManager2.callTool(integrationId, toolName, outgoingArgs);
|
|
1638
|
+
state2.executionLog.record({
|
|
1639
|
+
profileId: proposal.profileId,
|
|
1640
|
+
path: proposal.path,
|
|
1641
|
+
execution: proposal.executionContext,
|
|
1642
|
+
timestamp: Math.floor(Date.now() / 1e3)
|
|
1643
|
+
});
|
|
1588
1644
|
const resultText = result.content?.[0]?.text ?? JSON.stringify(result);
|
|
1589
1645
|
return { text: `Proposal ${proposal.id} committed and executed.
|
|
1590
1646
|
Result: ${resultText}` };
|
|
@@ -1810,10 +1866,10 @@ function createMcpServer(state2, integrationManager2) {
|
|
|
1810
1866
|
}
|
|
1811
1867
|
|
|
1812
1868
|
// src/lib/gate-content.ts
|
|
1813
|
-
import { createHash } from "crypto";
|
|
1869
|
+
import { createHash as createHash2 } from "crypto";
|
|
1814
1870
|
import { decodeAttestationBlob } from "@hap/core";
|
|
1815
1871
|
function hashGateContent(text) {
|
|
1816
|
-
const hex =
|
|
1872
|
+
const hex = createHash2("sha256").update(text, "utf-8").digest("hex");
|
|
1817
1873
|
return `sha256:${hex}`;
|
|
1818
1874
|
}
|
|
1819
1875
|
function verifyGateContentHashes(content, auth) {
|
|
@@ -1887,15 +1943,14 @@ var IntegrationRegistry = class {
|
|
|
1887
1943
|
const migrated = data.integrations.map((i) => {
|
|
1888
1944
|
if ("toolGating" in i && !("profile" in i)) {
|
|
1889
1945
|
const old = i;
|
|
1890
|
-
const toolGating = old.toolGating;
|
|
1891
1946
|
const config = {
|
|
1892
|
-
id:
|
|
1893
|
-
name:
|
|
1894
|
-
command:
|
|
1895
|
-
args:
|
|
1896
|
-
envKeys:
|
|
1897
|
-
profile: toolGating?.profile ?? null,
|
|
1898
|
-
enabled:
|
|
1947
|
+
id: old.id,
|
|
1948
|
+
name: old.name,
|
|
1949
|
+
command: old.command,
|
|
1950
|
+
args: old.args,
|
|
1951
|
+
envKeys: old.envKeys,
|
|
1952
|
+
profile: old.toolGating?.profile ?? null,
|
|
1953
|
+
enabled: old.enabled
|
|
1899
1954
|
};
|
|
1900
1955
|
return config;
|
|
1901
1956
|
}
|
|
@@ -1924,7 +1979,7 @@ import { existsSync as existsSync5, writeFileSync as writeFileSync4, mkdirSync a
|
|
|
1924
1979
|
import { execSync } from "child_process";
|
|
1925
1980
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
1926
1981
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
1927
|
-
import { getProfile as
|
|
1982
|
+
import { getProfile as getProfile4 } from "@hap/core";
|
|
1928
1983
|
var DEFAULT_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join5(homedir5(), ".suveren");
|
|
1929
1984
|
var INTEGRATIONS_DIR = process.env.SUVEREN_INTEGRATIONS_DIR ?? join5(DEFAULT_DATA_DIR2, "integrations");
|
|
1930
1985
|
var INTEGRATIONS_BIN = join5(INTEGRATIONS_DIR, "node_modules", ".bin");
|
|
@@ -2009,7 +2064,7 @@ var IntegrationManager = class {
|
|
|
2009
2064
|
await client.connect(transport);
|
|
2010
2065
|
console.error(`[IntegrationManager] Connected to ${config.id} (${config.command} ${config.args.join(" ")})`);
|
|
2011
2066
|
const toolsResult = await client.listTools();
|
|
2012
|
-
const profileGating = config.toolGating ?? (config.profile ?
|
|
2067
|
+
const profileGating = config.toolGating ?? (config.profile ? getProfile4(config.profile)?.toolGating ?? null : null);
|
|
2013
2068
|
const tools = (toolsResult.tools ?? []).map((tool) => {
|
|
2014
2069
|
const gating = this.resolveToolGating(config.profile, profileGating, tool.name);
|
|
2015
2070
|
return {
|
|
@@ -2406,7 +2461,8 @@ app.post("/internal/gate-content", internalOnly, async (req, res) => {
|
|
|
2406
2461
|
const { frameHash, boundsHash, contextHash, context, path: rawPath, gateContent } = req.body;
|
|
2407
2462
|
const storageHash = frameHash ?? boundsHash;
|
|
2408
2463
|
const hasIntent = !!gateContent?.intent;
|
|
2409
|
-
const
|
|
2464
|
+
const legacy = gateContent;
|
|
2465
|
+
const hasLegacy = !!legacy?.problem && !!legacy?.objective && !!legacy?.tradeoffs;
|
|
2410
2466
|
if (!storageHash || !hasIntent && !hasLegacy) {
|
|
2411
2467
|
res.status(400).json({ error: "Missing required fields: frameHash (or boundsHash), gateContent.{intent} or gateContent.{problem,objective,tradeoffs}" });
|
|
2412
2468
|
return;
|
|
@@ -2462,6 +2518,12 @@ app.post("/internal/start-pending-integrations", internalOnly, async (_req, res)
|
|
|
2462
2518
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
2463
2519
|
}
|
|
2464
2520
|
});
|
|
2521
|
+
var triggerCommittedExecution = () => {
|
|
2522
|
+
};
|
|
2523
|
+
app.post("/internal/run-committed", internalOnly, (_req, res) => {
|
|
2524
|
+
triggerCommittedExecution();
|
|
2525
|
+
res.json({ ok: true });
|
|
2526
|
+
});
|
|
2465
2527
|
app.post("/internal/resync-gates", internalOnly, async (_req, res) => {
|
|
2466
2528
|
const gates = state.gateStore.getAll();
|
|
2467
2529
|
if (gates.length === 0) {
|
|
@@ -2763,59 +2825,10 @@ app.listen(port, "0.0.0.0", () => {
|
|
|
2763
2825
|
const committed = await state.spClient.getCommittedProposals();
|
|
2764
2826
|
for (const proposal of committed) {
|
|
2765
2827
|
try {
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
if (parts.length !== 2) {
|
|
2771
|
-
console.error(`[Suveren MCP] Invalid tool name in proposal ${proposal.id}: ${proposal.tool}`);
|
|
2772
|
-
continue;
|
|
2773
|
-
}
|
|
2774
|
-
[integrationId, toolName] = parts;
|
|
2775
|
-
} else {
|
|
2776
|
-
const sep = proposal.tool.indexOf("__");
|
|
2777
|
-
if (sep < 0) {
|
|
2778
|
-
console.error(`[Suveren MCP] Invalid tool name in proposal ${proposal.id}: ${proposal.tool}`);
|
|
2779
|
-
continue;
|
|
2780
|
-
}
|
|
2781
|
-
integrationId = proposal.tool.slice(0, sep);
|
|
2782
|
-
toolName = proposal.tool.slice(sep + 2);
|
|
2783
|
-
}
|
|
2784
|
-
const proposalActionType = typeof proposal.executionContext.action_type === "string" ? proposal.executionContext.action_type : void 0;
|
|
2785
|
-
if (!proposalActionType) {
|
|
2786
|
-
console.error(
|
|
2787
|
-
`[Suveren MCP] Warning: proposal ${proposal.id} has no action_type in executionContext. Bounds check may be skipped. Fix the integration manifest for ${proposal.tool}.`
|
|
2788
|
-
);
|
|
2789
|
-
}
|
|
2790
|
-
try {
|
|
2791
|
-
await state.spClient.postReceipt({
|
|
2792
|
-
attestationHash: proposal.frameHash,
|
|
2793
|
-
profileId: proposal.profileId,
|
|
2794
|
-
path: proposal.path,
|
|
2795
|
-
action: proposal.tool,
|
|
2796
|
-
actionType: proposalActionType,
|
|
2797
|
-
executionContext: proposal.executionContext,
|
|
2798
|
-
amount: typeof proposal.executionContext.amount === "number" ? proposal.executionContext.amount : void 0,
|
|
2799
|
-
proposalId: proposal.id,
|
|
2800
|
-
toolArgs: proposal.toolArgs
|
|
2801
|
-
});
|
|
2802
|
-
} catch (err) {
|
|
2803
|
-
console.error(`[Suveren MCP] Receipt failed for proposal ${proposal.id}:`, err instanceof Error ? err.message : err);
|
|
2804
|
-
continue;
|
|
2805
|
-
}
|
|
2806
|
-
try {
|
|
2807
|
-
await integrationManager.callTool(integrationId, toolName, proposal.toolArgs);
|
|
2808
|
-
} catch (err) {
|
|
2809
|
-
console.error(`[Suveren MCP] Tool execution failed for proposal ${proposal.id} after receipt issued:`, err);
|
|
2810
|
-
continue;
|
|
2811
|
-
}
|
|
2812
|
-
state.executionLog.record({
|
|
2813
|
-
profileId: proposal.profileId,
|
|
2814
|
-
path: proposal.path,
|
|
2815
|
-
execution: proposal.executionContext,
|
|
2816
|
-
timestamp: Math.floor(Date.now() / 1e3)
|
|
2817
|
-
});
|
|
2818
|
-
console.error(`[Suveren MCP] Auto-executed proposal ${proposal.id}: ${proposal.tool}`);
|
|
2828
|
+
const { text, isError } = await executeCommitted(proposal, state, integrationManager);
|
|
2829
|
+
console.error(
|
|
2830
|
+
isError ? `[Suveren MCP] Auto-exec proposal ${proposal.id}: ${text}` : `[Suveren MCP] Auto-executed proposal ${proposal.id}: ${proposal.tool}`
|
|
2831
|
+
);
|
|
2819
2832
|
} catch (err) {
|
|
2820
2833
|
console.error(`[Suveren MCP] Failed to execute proposal ${proposal.id}:`, err);
|
|
2821
2834
|
}
|
|
@@ -2824,4 +2837,7 @@ app.listen(port, "0.0.0.0", () => {
|
|
|
2824
2837
|
}
|
|
2825
2838
|
}
|
|
2826
2839
|
setInterval(executeCommittedProposals, PROPOSAL_POLL_INTERVAL);
|
|
2840
|
+
triggerCommittedExecution = () => {
|
|
2841
|
+
void executeCommittedProposals();
|
|
2842
|
+
};
|
|
2827
2843
|
});
|