@suveren/gateway 0.13.0 → 0.14.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/README.md +19 -3
- package/bin/suveren-gateway.js +5 -0
- package/dist/control-plane/index.mjs +146 -114
- package/dist/mcp-server/http.mjs +162 -118
- package/dist/ui/assets/{index-CmLqzgqA.js → index-Cg6VaGKb.js} +12 -12
- package/dist/ui/index.html +1 -1
- package/lib/autostart-templates.mjs +15 -7
- package/node_modules/@hap/core/dist/index.d.mts +49 -1
- package/node_modules/@hap/core/dist/index.d.ts +49 -1
- package/node_modules/@hap/core/dist/index.js +50 -0
- package/node_modules/@hap/core/dist/index.mjs +49 -0
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/frame.ts +63 -1
- package/node_modules/@hap/core/src/gatekeeper.ts +37 -0
- package/node_modules/@hap/core/src/types.ts +29 -1
- package/node_modules/hono/dist/cjs/hono-base.js +2 -0
- package/node_modules/hono/dist/cjs/middleware/language/language.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/mount/index.js +71 -0
- package/node_modules/hono/dist/cjs/request.js +4 -4
- package/node_modules/hono/dist/hono-base.js +2 -0
- package/node_modules/hono/dist/middleware/mount/index.js +70 -0
- package/node_modules/hono/dist/request.js +4 -4
- package/node_modules/hono/dist/types/hono-base.d.ts +2 -0
- package/node_modules/hono/dist/types/jsx/base.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/mount/index.d.ts +46 -0
- package/node_modules/hono/dist/types/request.d.ts +4 -4
- package/node_modules/hono/package.json +9 -1
- package/package.json +2 -2
- package/profiles/index.json +3 -1
- package/profiles/purchase/0.6.profile.json +234 -0
- package/profiles/sales/0.3.profile.json +290 -0
- package/server.js +6 -3
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -2202,7 +2202,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2202
2202
|
import { z as z2 } from "zod";
|
|
2203
2203
|
|
|
2204
2204
|
// src/lib/mandate-brief.ts
|
|
2205
|
-
import { getProfile } from "@hap/core";
|
|
2205
|
+
import { getProfile as getProfile3 } from "@hap/core";
|
|
2206
2206
|
|
|
2207
2207
|
// src/lib/consumption.ts
|
|
2208
2208
|
import { boundActionTypes } from "@hap/core";
|
|
@@ -2296,87 +2296,16 @@ function getContextForBrief(dataDir2) {
|
|
|
2296
2296
|
return { brief: truncated, truncated: true };
|
|
2297
2297
|
}
|
|
2298
2298
|
|
|
2299
|
-
// src/lib/
|
|
2300
|
-
function
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
return
|
|
2304
|
-
}
|
|
2305
|
-
function countToolsByGating(profileId, integrationManager2) {
|
|
2306
|
-
if (!integrationManager2) return { gated: 0, readOnly: 0 };
|
|
2307
|
-
const allTools = integrationManager2.getAllTools();
|
|
2308
|
-
let gated = 0;
|
|
2309
|
-
let readOnly = 0;
|
|
2310
|
-
for (const tool of allTools) {
|
|
2311
|
-
if (!tool.gating || !tool.gating.profile) {
|
|
2312
|
-
readOnly++;
|
|
2313
|
-
} else if (tool.gating.profile === profileId || tool.gating.profile === shortProfileName(profileId)) {
|
|
2314
|
-
if (tool.gating.staticExecution?.action_type === "read" && Object.keys(tool.gating.executionMapping ?? {}).length === 0) {
|
|
2315
|
-
readOnly++;
|
|
2316
|
-
} else {
|
|
2317
|
-
gated++;
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
return { gated, readOnly };
|
|
2299
|
+
// src/lib/simulation-mode.ts
|
|
2300
|
+
function isSimulationMode() {
|
|
2301
|
+
const policySimulation = readPolicy().policy.simulation;
|
|
2302
|
+
if (policySimulation !== void 0) return policySimulation;
|
|
2303
|
+
return process.env.SUVEREN_SIMULATION === "1";
|
|
2322
2304
|
}
|
|
2323
|
-
function
|
|
2324
|
-
|
|
2325
|
-
const lines = [
|
|
2326
|
-
"You are connected to Suveren \u2014 the gateway that gates every privileged tool call you make.",
|
|
2327
|
-
"Suveren implements the bounded-authority model from the open Human Agency Protocol (HAP).",
|
|
2328
|
-
"You have bounded authorities granted by human decision owners.",
|
|
2329
|
-
"You MUST stay within these bounds \u2014 the Gatekeeper will reject actions that exceed them."
|
|
2330
|
-
];
|
|
2331
|
-
const { brief: contextBrief } = getContextForBrief(contextDir);
|
|
2332
|
-
if (contextBrief) {
|
|
2333
|
-
lines.push("");
|
|
2334
|
-
lines.push("=== CONTEXT ===");
|
|
2335
|
-
lines.push("");
|
|
2336
|
-
lines.push(contextBrief);
|
|
2337
|
-
}
|
|
2338
|
-
const active = authorizations.filter((a) => a.complete);
|
|
2339
|
-
const pending = authorizations.filter((a) => !a.complete);
|
|
2340
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
2341
|
-
if (active.length > 0) {
|
|
2342
|
-
lines.push("");
|
|
2343
|
-
lines.push("=== ACTIVE AUTHORITIES ===");
|
|
2344
|
-
lines.push("");
|
|
2345
|
-
for (const auth of active) {
|
|
2346
|
-
const earliestExpiry = Math.min(...auth.attestations.map((a) => a.expiresAt));
|
|
2347
|
-
const remainingMin = Math.max(0, Math.round((earliestExpiry - now) / 60));
|
|
2348
|
-
const shortName = shortProfileName(auth.profileId);
|
|
2349
|
-
const version = auth.profileId.match(/@(.+)$/)?.[1] ?? "";
|
|
2350
|
-
const shortId = version ? `${shortName}@${version}` : shortName;
|
|
2351
|
-
const boundsDesc = Object.entries(auth.frame).filter(([key]) => key !== "profile" && key !== "path").map(([key, value]) => `${key}:${value}`).join(" \xB7 ");
|
|
2352
|
-
const parts = [];
|
|
2353
|
-
if (boundsDesc) parts.push(boundsDesc);
|
|
2354
|
-
if (executionLog) {
|
|
2355
|
-
const profile = getProfile(auth.profileId) ?? getProfile(shortName);
|
|
2356
|
-
const consumption = getConsumptionState(auth, executionLog, profile);
|
|
2357
|
-
const compact = formatConsumptionCompact(consumption);
|
|
2358
|
-
if (compact) parts.push(compact);
|
|
2359
|
-
}
|
|
2360
|
-
const { gated, readOnly } = countToolsByGating(auth.profileId, integrationManager2);
|
|
2361
|
-
if (gated > 0 || readOnly > 0) parts.push(`${gated} gated tools`);
|
|
2362
|
-
parts.push(`${remainingMin} min remaining`);
|
|
2363
|
-
lines.push(`[${shortId}] ${parts.join(" \xB7 ")}`);
|
|
2364
|
-
lines.push(` \u2192 list-authorizations(domain: "${shortName}") for intent & details`);
|
|
2365
|
-
lines.push("");
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
if (pending.length > 0) {
|
|
2369
|
-
lines.push("=== PENDING (awaiting attestations) ===");
|
|
2370
|
-
lines.push("");
|
|
2371
|
-
for (const auth of pending) {
|
|
2372
|
-
const missing = auth.requiredDomains.filter((d) => !auth.attestedDomains.includes(d));
|
|
2373
|
-
lines.push(`[${auth.path}] ${auth.profileId} \u2014 needs: ${missing.join(", ")}`);
|
|
2374
|
-
}
|
|
2375
|
-
lines.push("");
|
|
2376
|
-
}
|
|
2377
|
-
lines.push("When you receive a task, call list-authorizations(domain) to load full details for the relevant domain.");
|
|
2378
|
-
return lines.join("\n");
|
|
2305
|
+
function manifestIsSimulated(manifest) {
|
|
2306
|
+
return Boolean(manifest?.simulation);
|
|
2379
2307
|
}
|
|
2308
|
+
var SIMULATION_BLOCK_REASON = "blocked: simulation mode \u2014 real systems are off";
|
|
2380
2309
|
|
|
2381
2310
|
// src/lib/locked-notice.ts
|
|
2382
2311
|
function uiUrl() {
|
|
@@ -2426,9 +2355,6 @@ function lockedNotice(action, reason = "restart") {
|
|
|
2426
2355
|
}
|
|
2427
2356
|
}
|
|
2428
2357
|
|
|
2429
|
-
// src/tools/authorizations.ts
|
|
2430
|
-
import { getProfile as getProfile4 } from "@hap/core";
|
|
2431
|
-
|
|
2432
2358
|
// src/lib/receipt-footer.ts
|
|
2433
2359
|
import { deriveIdentityLine } from "@hap/core";
|
|
2434
2360
|
var AS_BASE = (process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai").replace(/\/$/, "");
|
|
@@ -2490,10 +2416,10 @@ import {
|
|
|
2490
2416
|
selectBoundFields,
|
|
2491
2417
|
isFieldBinding,
|
|
2492
2418
|
bindingAppliesTo,
|
|
2493
|
-
getProfile
|
|
2419
|
+
getProfile
|
|
2494
2420
|
} from "@hap/core";
|
|
2495
2421
|
function getContentBinding(profileId) {
|
|
2496
|
-
return
|
|
2422
|
+
return getProfile(profileId)?.content_binding;
|
|
2497
2423
|
}
|
|
2498
2424
|
function computeContentBinding(profileId, tool, toolArgs, actionType) {
|
|
2499
2425
|
const binding = getContentBinding(profileId);
|
|
@@ -2913,7 +2839,7 @@ function clampAgeFloor(requested, maxAgeDays, nowMs, format = "iso") {
|
|
|
2913
2839
|
}
|
|
2914
2840
|
|
|
2915
2841
|
// src/lib/tool-proxy.ts
|
|
2916
|
-
import { getProfile as
|
|
2842
|
+
import { getProfile as getProfile2, ContentBindingError, boundActionTypes as boundActionTypes2 } from "@hap/core";
|
|
2917
2843
|
import { readFile } from "fs/promises";
|
|
2918
2844
|
import { extname } from "path";
|
|
2919
2845
|
import { randomUUID } from "crypto";
|
|
@@ -2978,17 +2904,6 @@ function getAllManifests() {
|
|
|
2978
2904
|
return Array.from(manifests.values());
|
|
2979
2905
|
}
|
|
2980
2906
|
|
|
2981
|
-
// src/lib/simulation-mode.ts
|
|
2982
|
-
function isSimulationMode() {
|
|
2983
|
-
const policySimulation = readPolicy().policy.simulation;
|
|
2984
|
-
if (policySimulation !== void 0) return policySimulation;
|
|
2985
|
-
return process.env.SUVEREN_SIMULATION === "1";
|
|
2986
|
-
}
|
|
2987
|
-
function manifestIsSimulated(manifest) {
|
|
2988
|
-
return Boolean(manifest?.simulation);
|
|
2989
|
-
}
|
|
2990
|
-
var SIMULATION_BLOCK_REASON = "blocked: simulation mode \u2014 real systems are off";
|
|
2991
|
-
|
|
2992
2907
|
// src/lib/tool-proxy.ts
|
|
2993
2908
|
var IMAGE_MIME = {
|
|
2994
2909
|
".jpg": "image/jpeg",
|
|
@@ -3050,7 +2965,7 @@ function profileMatches(profileId, shortName) {
|
|
|
3050
2965
|
return profileId === shortName || profileId.includes("/" + shortName + "@") || profileId.endsWith("/" + shortName);
|
|
3051
2966
|
}
|
|
3052
2967
|
function countBoundsFor(profileId, actionType) {
|
|
3053
|
-
const fields =
|
|
2968
|
+
const fields = getProfile2(profileId)?.boundsSchema?.fields;
|
|
3054
2969
|
if (!fields) return null;
|
|
3055
2970
|
return Object.entries(fields).filter(([, def]) => def.boundType?.kind === "cumulative_count").filter(([name, def]) => {
|
|
3056
2971
|
const applies = boundActionTypes2(name, def);
|
|
@@ -3110,7 +3025,7 @@ function createGatedToolHandler(tool, integrationManager2, state2) {
|
|
|
3110
3025
|
return async () => ({
|
|
3111
3026
|
content: [{
|
|
3112
3027
|
type: "text",
|
|
3113
|
-
text: `Refused: "${tool.namespacedName}"
|
|
3028
|
+
text: `Refused: "${tool.namespacedName}" is not available. No ticket was requested.`
|
|
3114
3029
|
}],
|
|
3115
3030
|
isError: true
|
|
3116
3031
|
});
|
|
@@ -3131,6 +3046,17 @@ function createGatedToolHandler(tool, integrationManager2, state2) {
|
|
|
3131
3046
|
};
|
|
3132
3047
|
};
|
|
3133
3048
|
}
|
|
3049
|
+
function isStaleMandateRefusal(err) {
|
|
3050
|
+
const errors = err.body?.errors;
|
|
3051
|
+
const code = errors?.[0]?.code;
|
|
3052
|
+
if (err.statusCode === 403 && (code === "ATTESTATION_REVOKED" || code === "ATTESTATION_EXPIRED")) {
|
|
3053
|
+
return true;
|
|
3054
|
+
}
|
|
3055
|
+
if (err.statusCode === 404 && code === "ATTESTATION_NOT_FOUND") {
|
|
3056
|
+
return true;
|
|
3057
|
+
}
|
|
3058
|
+
return false;
|
|
3059
|
+
}
|
|
3134
3060
|
function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
3135
3061
|
if (!tool.gating || !tool.gating.profile) {
|
|
3136
3062
|
return async () => {
|
|
@@ -3202,7 +3128,7 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
3202
3128
|
);
|
|
3203
3129
|
}
|
|
3204
3130
|
}
|
|
3205
|
-
const readProfile = readAdapter ?
|
|
3131
|
+
const readProfile = readAdapter ? getProfile2(matchingAuths[0].profileId) : void 0;
|
|
3206
3132
|
const boundsSchema = readProfile?.boundsSchema;
|
|
3207
3133
|
const ageBoundField = readAdapter?.ageField ? resolveAgeBoundField(boundsSchema, readAdapter.ageField) : null;
|
|
3208
3134
|
const hasAgeDimension = Boolean(readAdapter?.ageField);
|
|
@@ -3358,7 +3284,7 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
3358
3284
|
};
|
|
3359
3285
|
}
|
|
3360
3286
|
{
|
|
3361
|
-
const profileDef =
|
|
3287
|
+
const profileDef = getProfile2(profile);
|
|
3362
3288
|
const registry = profileDef?.boundsSchema?.actionTypes;
|
|
3363
3289
|
if (Array.isArray(registry) && registry.length > 0 && !registry.includes(declaredActionType)) {
|
|
3364
3290
|
return {
|
|
@@ -3415,23 +3341,24 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
3415
3341
|
isError: true
|
|
3416
3342
|
};
|
|
3417
3343
|
}
|
|
3418
|
-
const contextKeys =
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
if (selection.superseded.length > 0) {
|
|
3430
|
-
console.error(
|
|
3431
|
-
`[Suveren MCP] selection(${tool.namespacedName}): chose ${auth.authorizationId} (${selection.reason}) over [${selection.superseded.map((s) => s.id).join(", ")}]`
|
|
3344
|
+
const contextKeys = getProfile2(passers[0].profileId)?.contextSchema?.keyOrder ?? [];
|
|
3345
|
+
return attemptWithCandidates(passers);
|
|
3346
|
+
async function attemptWithCandidates(candidates) {
|
|
3347
|
+
const selection = selectAuthorization(
|
|
3348
|
+
contextKeys,
|
|
3349
|
+
candidates.map((a) => ({
|
|
3350
|
+
id: a.authorizationId,
|
|
3351
|
+
auth: a,
|
|
3352
|
+
context: a.context ?? {},
|
|
3353
|
+
requiresApproval: (a.deferredCommitmentDomains ?? []).length > 0
|
|
3354
|
+
}))
|
|
3432
3355
|
);
|
|
3433
|
-
|
|
3434
|
-
|
|
3356
|
+
const auth = selection.chosen.auth;
|
|
3357
|
+
if (selection.superseded.length > 0) {
|
|
3358
|
+
console.error(
|
|
3359
|
+
`[Suveren MCP] selection(${tool.namespacedName}): chose ${auth.authorizationId} (${selection.reason}) over [${selection.superseded.map((s) => s.id).join(", ")}]`
|
|
3360
|
+
);
|
|
3361
|
+
}
|
|
3435
3362
|
const authzId = auth.authorizationId;
|
|
3436
3363
|
if (isCommitmentDowngrade(auth)) {
|
|
3437
3364
|
return {
|
|
@@ -3544,6 +3471,24 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
3544
3471
|
isError: true
|
|
3545
3472
|
};
|
|
3546
3473
|
}
|
|
3474
|
+
if (err instanceof SPReceiptError && isStaleMandateRefusal(err)) {
|
|
3475
|
+
state2.cache.invalidate(auth.authorizationId);
|
|
3476
|
+
const code = err.body?.errors?.[0]?.code ?? "unknown";
|
|
3477
|
+
const remaining = candidates.filter((c) => c.authorizationId !== auth.authorizationId);
|
|
3478
|
+
if (remaining.length === 0) {
|
|
3479
|
+
console.error(
|
|
3480
|
+
`[Suveren MCP] fallback(${tool.namespacedName}): mandate ${auth.authorizationId} invalid (${code}) \u2014 no remaining candidates`
|
|
3481
|
+
);
|
|
3482
|
+
return {
|
|
3483
|
+
content: [{ type: "text", text: `Blocked by SP: ${err.message}` }],
|
|
3484
|
+
isError: true
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
console.error(
|
|
3488
|
+
`[Suveren MCP] fallback(${tool.namespacedName}): mandate ${auth.authorizationId} invalid (${code}) \u2192 retrying with [${remaining.map((c) => c.authorizationId).join(", ")}]`
|
|
3489
|
+
);
|
|
3490
|
+
return attemptWithCandidates(remaining);
|
|
3491
|
+
}
|
|
3547
3492
|
if (err instanceof SPReceiptError && err.statusCode === 409) {
|
|
3548
3493
|
const spBody = err.body;
|
|
3549
3494
|
let pendingApprovers = spBody.approvers ?? [];
|
|
@@ -3700,7 +3645,106 @@ function buildProxiedToolDescription(tool, state2) {
|
|
|
3700
3645
|
return `[Suveren: ${profile} \u2014 ${tag}] ${tool.description}`;
|
|
3701
3646
|
}
|
|
3702
3647
|
|
|
3648
|
+
// src/lib/agent-visibility.ts
|
|
3649
|
+
function agentVisibleAuthorizations(authorizations, integrationManager2) {
|
|
3650
|
+
if (!isSimulationMode()) return authorizations;
|
|
3651
|
+
if (!integrationManager2) return [];
|
|
3652
|
+
const runningProfiles = /* @__PURE__ */ new Set();
|
|
3653
|
+
for (const tool of integrationManager2.getAllTools()) {
|
|
3654
|
+
const profile = tool.gating?.profile;
|
|
3655
|
+
if (profile) runningProfiles.add(profile);
|
|
3656
|
+
}
|
|
3657
|
+
if (runningProfiles.size === 0) return [];
|
|
3658
|
+
return authorizations.filter(
|
|
3659
|
+
(auth) => [...runningProfiles].some((profile) => profileMatches(auth.profileId, profile))
|
|
3660
|
+
);
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
// src/lib/mandate-brief.ts
|
|
3664
|
+
function shortProfileName(profileId) {
|
|
3665
|
+
const withoutVersion = profileId.replace(/@.*$/, "");
|
|
3666
|
+
const parts = withoutVersion.split("/");
|
|
3667
|
+
return parts[parts.length - 1];
|
|
3668
|
+
}
|
|
3669
|
+
function countToolsByGating(profileId, integrationManager2) {
|
|
3670
|
+
if (!integrationManager2) return { gated: 0, readOnly: 0 };
|
|
3671
|
+
const allTools = integrationManager2.getAllTools();
|
|
3672
|
+
let gated = 0;
|
|
3673
|
+
let readOnly = 0;
|
|
3674
|
+
for (const tool of allTools) {
|
|
3675
|
+
if (!tool.gating || !tool.gating.profile) {
|
|
3676
|
+
readOnly++;
|
|
3677
|
+
} else if (tool.gating.profile === profileId || tool.gating.profile === shortProfileName(profileId)) {
|
|
3678
|
+
if (tool.gating.staticExecution?.action_type === "read" && Object.keys(tool.gating.executionMapping ?? {}).length === 0) {
|
|
3679
|
+
readOnly++;
|
|
3680
|
+
} else {
|
|
3681
|
+
gated++;
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
return { gated, readOnly };
|
|
3686
|
+
}
|
|
3687
|
+
function buildMandateBrief(opts) {
|
|
3688
|
+
const { executionLog, integrationManager: integrationManager2, contextDir } = opts;
|
|
3689
|
+
const authorizations = agentVisibleAuthorizations(opts.authorizations, integrationManager2);
|
|
3690
|
+
const lines = [
|
|
3691
|
+
"You are connected to Suveren \u2014 the gateway that gates every privileged tool call you make.",
|
|
3692
|
+
"Suveren implements the bounded-authority model from the open Human Agency Protocol (HAP).",
|
|
3693
|
+
"You have bounded authorities granted by human decision owners.",
|
|
3694
|
+
"You MUST stay within these bounds \u2014 the Gatekeeper will reject actions that exceed them."
|
|
3695
|
+
];
|
|
3696
|
+
const { brief: contextBrief } = getContextForBrief(contextDir);
|
|
3697
|
+
if (contextBrief) {
|
|
3698
|
+
lines.push("");
|
|
3699
|
+
lines.push("=== CONTEXT ===");
|
|
3700
|
+
lines.push("");
|
|
3701
|
+
lines.push(contextBrief);
|
|
3702
|
+
}
|
|
3703
|
+
const active = authorizations.filter((a) => a.complete);
|
|
3704
|
+
const pending = authorizations.filter((a) => !a.complete);
|
|
3705
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3706
|
+
if (active.length > 0) {
|
|
3707
|
+
lines.push("");
|
|
3708
|
+
lines.push("=== ACTIVE AUTHORITIES ===");
|
|
3709
|
+
lines.push("");
|
|
3710
|
+
for (const auth of active) {
|
|
3711
|
+
const earliestExpiry = Math.min(...auth.attestations.map((a) => a.expiresAt));
|
|
3712
|
+
const remainingMin = Math.max(0, Math.round((earliestExpiry - now) / 60));
|
|
3713
|
+
const shortName = shortProfileName(auth.profileId);
|
|
3714
|
+
const version = auth.profileId.match(/@(.+)$/)?.[1] ?? "";
|
|
3715
|
+
const shortId = version ? `${shortName}@${version}` : shortName;
|
|
3716
|
+
const boundsDesc = Object.entries(auth.frame).filter(([key]) => key !== "profile" && key !== "path").map(([key, value]) => `${key}:${value}`).join(" \xB7 ");
|
|
3717
|
+
const parts = [];
|
|
3718
|
+
if (boundsDesc) parts.push(boundsDesc);
|
|
3719
|
+
if (executionLog) {
|
|
3720
|
+
const profile = getProfile3(auth.profileId) ?? getProfile3(shortName);
|
|
3721
|
+
const consumption = getConsumptionState(auth, executionLog, profile);
|
|
3722
|
+
const compact = formatConsumptionCompact(consumption);
|
|
3723
|
+
if (compact) parts.push(compact);
|
|
3724
|
+
}
|
|
3725
|
+
const { gated, readOnly } = countToolsByGating(auth.profileId, integrationManager2);
|
|
3726
|
+
if (gated > 0 || readOnly > 0) parts.push(`${gated} gated tools`);
|
|
3727
|
+
parts.push(`${remainingMin} min remaining`);
|
|
3728
|
+
lines.push(`[${shortId}] ${parts.join(" \xB7 ")}`);
|
|
3729
|
+
lines.push(` \u2192 list-authorizations(domain: "${shortName}") for intent & details`);
|
|
3730
|
+
lines.push("");
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
if (pending.length > 0) {
|
|
3734
|
+
lines.push("=== PENDING (awaiting attestations) ===");
|
|
3735
|
+
lines.push("");
|
|
3736
|
+
for (const auth of pending) {
|
|
3737
|
+
const missing = auth.requiredDomains.filter((d) => !auth.attestedDomains.includes(d));
|
|
3738
|
+
lines.push(`[${auth.path}] ${auth.profileId} \u2014 needs: ${missing.join(", ")}`);
|
|
3739
|
+
}
|
|
3740
|
+
lines.push("");
|
|
3741
|
+
}
|
|
3742
|
+
lines.push("When you receive a task, call list-authorizations(domain) to load full details for the relevant domain.");
|
|
3743
|
+
return lines.join("\n");
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3703
3746
|
// src/tools/authorizations.ts
|
|
3747
|
+
import { getProfile as getProfile4 } from "@hap/core";
|
|
3704
3748
|
function shortProfileName2(profileId) {
|
|
3705
3749
|
const withoutVersion = profileId.replace(/@.*$/, "");
|
|
3706
3750
|
const parts = withoutVersion.split("/");
|
|
@@ -3761,7 +3805,7 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
3761
3805
|
if (!state2.spClient.isUnlocked()) {
|
|
3762
3806
|
return { content: [{ type: "text", text: lockedNotice("list authorizations", state2.spClient.getLockReason() ?? "restart") }] };
|
|
3763
3807
|
}
|
|
3764
|
-
const authorizations = state2.getEnrichedAuthorizations();
|
|
3808
|
+
const authorizations = agentVisibleAuthorizations(state2.getEnrichedAuthorizations(), integrationManager2);
|
|
3765
3809
|
const now = Math.floor(Date.now() / 1e3);
|
|
3766
3810
|
const domain = args?.domain;
|
|
3767
3811
|
if (authorizations.length === 0) {
|