multicorn-shield 0.10.0 → 0.11.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/CHANGELOG.md +10 -0
- package/dist/badge.js +44 -0
- package/dist/index.cjs +143 -0
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +143 -1
- package/dist/openclaw-plugin/multicorn-shield.js +3 -1
- package/dist/shield-extension.js +126 -5
- package/package.json +15 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.11.0] - 2026-04-25
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `<multicorn-badge>` trust badge web component for embedding in third-party products. Shadow DOM encapsulation, dark/light themes, compact/standard sizes, optional action count display.
|
|
13
|
+
- CDN entrypoint (`dist/badge.js`) for single-script-tag embedding: `<script src="https://cdn.multicorn.ai/badge.js" data-agent-id="..."></script>`. Self-contained, no Lit runtime dependency.
|
|
14
|
+
- `MulticornBadge` class exported from the main SDK barrel for programmatic usage.
|
|
15
|
+
- Shared `shield-tokens.ts` module (`src/shared/`) extracting `SHIELD_COLORS` design tokens for reuse across consent and badge components.
|
|
16
|
+
- `size-limit` budget enforcement for `dist/badge.js` at 5 kB gzip (actual ~1.75 kB).
|
|
17
|
+
|
|
8
18
|
## [0.10.0] - 2026-04-21
|
|
9
19
|
|
|
10
20
|
### Added
|
package/dist/badge.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
var n={surface:"#14141f",surfaceHover:"#1a1a2e",border:"#2a2a3d",text:"#e8e8f0",accent:"#8b5cf6",accentDim:"rgba(139, 92, 246, 0.12)"};var E="#0f172a",y="#f8fafc",A="#f1f5f9",v="#e2e8f0";function h(){return `
|
|
2
|
+
:host { display: inline-block; line-height: 0; }
|
|
3
|
+
.badge {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
gap: 6px;
|
|
9
|
+
min-height: 28px;
|
|
10
|
+
padding: 4px 10px 4px 8px;
|
|
11
|
+
border-radius: 9999px;
|
|
12
|
+
text-decoration: none;
|
|
13
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
14
|
+
font-size: 12px;
|
|
15
|
+
font-weight: 500;
|
|
16
|
+
border: 1px solid ${n.border};
|
|
17
|
+
background: ${n.surface};
|
|
18
|
+
color: ${n.text};
|
|
19
|
+
transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
20
|
+
}
|
|
21
|
+
:host([theme="light"]) .badge {
|
|
22
|
+
border-color: ${v};
|
|
23
|
+
background: ${y};
|
|
24
|
+
color: ${E};
|
|
25
|
+
}
|
|
26
|
+
.badge:hover {
|
|
27
|
+
background: ${n.surfaceHover};
|
|
28
|
+
border-color: ${n.accent};
|
|
29
|
+
box-shadow: 0 0 0 1px ${n.accentDim};
|
|
30
|
+
}
|
|
31
|
+
:host([theme="light"]) .badge:hover {
|
|
32
|
+
background: ${A};
|
|
33
|
+
border-color: ${n.accent};
|
|
34
|
+
}
|
|
35
|
+
.badge:focus-visible {
|
|
36
|
+
outline: 2px solid ${n.accent};
|
|
37
|
+
outline-offset: 2px;
|
|
38
|
+
}
|
|
39
|
+
.icon { flex-shrink: 0; display: block; }
|
|
40
|
+
.text { white-space: nowrap; }
|
|
41
|
+
:host([size="compact"]) .text { display: none; }
|
|
42
|
+
:host([size="compact"]) .badge { padding: 4px 6px; }
|
|
43
|
+
@media (prefers-reduced-motion: reduce) { .badge { transition: none; } }
|
|
44
|
+
`.trim()}var L="https://multicorn.ai/verify/",x="multicorn-badge",w="M12 1L3 5v6c0 5.55 3.84 9.95 9 12 5.16-2.05 9-6.45 9-12V5l-9-4z";function C(e){if(e==null||e==="")return;let t=Number(e);return Number.isNaN(t)?void 0:t}var m=class extends HTMLElement{#e=false;ensureShadow(){return this.shadowRoot!=null?this.shadowRoot:this.attachShadow({mode:"open"})}static get observedAttributes(){return ["agent-id","size","theme","action-count"]}connectedCallback(){this.render();}attributeChangedCallback(){this.render();}render(){let t=this.ensureShadow();if(!this.#e){let g=document.createElement("style");g.textContent=h(),t.appendChild(g),this.#e=true;}let s=(this.getAttribute("agent-id")??"").trim(),c=C(this.getAttribute("action-count")),a=t.querySelector("a.badge");if(a&&a.remove(),s==="")return;let d,l;if(c==null)d="Secured by Multicorn",l="Secured by Multicorn, verify this agent";else {let f=String(c);d="Secured by Multicorn \xB7 "+f+" actions secured",l="Secured by Multicorn \xB7 "+f+" actions secured, verify this agent";}let S=`${L}${encodeURIComponent(s)}`,r=document.createElement("a");r.className="badge",r.href=S,r.target="_blank",r.rel="noopener noreferrer",r.setAttribute("aria-label",l);let p="http://www.w3.org/2000/svg",o=document.createElementNS(p,"svg");o.setAttribute("class","icon"),o.setAttribute("width","16"),o.setAttribute("height","16"),o.setAttribute("viewBox","0 0 24 24"),o.setAttribute("aria-hidden","true");let u=document.createElementNS(p,"path");u.setAttribute("d",w),u.setAttribute("fill",n.accent),o.appendChild(u),r.appendChild(o);let b=document.createElement("span");b.className="text",b.textContent=d,r.appendChild(b),t.appendChild(r);}};customElements.get(x)===void 0&&customElements.define(x,m);function T(e){return e==="compact"||e==="standard"}function H(e){return e==="dark"||e==="light"}var i=(typeof document<"u"&&document.currentScript!==null?document.currentScript:null)??null;if(i==null)console.warn("[Multicorn] badge.js must be loaded as a classic script (document.currentScript was null).");else {let e=i.dataset.agentId?.trim();if(e==null||e==="")console.warn("[Multicorn] Skipping trust badge: missing data-agent-id on the badge script tag.");else {let t=document.createElement("multicorn-badge");t.setAttribute("agent-id",e);let s=i.dataset.size;T(s)&&t.setAttribute("size",s);let c=i.dataset.theme;H(c)&&t.setAttribute("theme",c);let a=i.dataset.actionCount;a!=null&&a!==""&&t.setAttribute("action-count",a),i.parentNode?.insertBefore(t,i.nextSibling);}}
|
package/dist/index.cjs
CHANGED
|
@@ -432,6 +432,8 @@ function getScopeWarning(scopeString) {
|
|
|
432
432
|
const metadata = getScopeMetadata(scopeString);
|
|
433
433
|
return metadata?.warningMessage;
|
|
434
434
|
}
|
|
435
|
+
|
|
436
|
+
// src/shared/shield-tokens.ts
|
|
435
437
|
var SHIELD_COLORS = {
|
|
436
438
|
bg: "#0d0d14",
|
|
437
439
|
surface: "#14141f",
|
|
@@ -452,6 +454,8 @@ var SHIELD_COLORS = {
|
|
|
452
454
|
red: "#ef4444",
|
|
453
455
|
redDim: "rgba(239, 68, 68, 0.12)"
|
|
454
456
|
};
|
|
457
|
+
|
|
458
|
+
// src/consent/consent-styles.ts
|
|
455
459
|
var consentStyles = lit.css`
|
|
456
460
|
:host {
|
|
457
461
|
display: block;
|
|
@@ -1599,6 +1603,144 @@ exports.MulticornConsent = __decorateClass([
|
|
|
1599
1603
|
decorators_js.customElement(CONSENT_ELEMENT_TAG)
|
|
1600
1604
|
], exports.MulticornConsent);
|
|
1601
1605
|
|
|
1606
|
+
// src/badge/badge-styles.ts
|
|
1607
|
+
var LIGHT_TEXT = "#0f172a";
|
|
1608
|
+
var LIGHT_SURFACE = "#f8fafc";
|
|
1609
|
+
var LIGHT_SURFACE_HOVER = "#f1f5f9";
|
|
1610
|
+
var LIGHT_BORDER = "#e2e8f0";
|
|
1611
|
+
function getBadgeStyleText() {
|
|
1612
|
+
return `
|
|
1613
|
+
:host { display: inline-block; line-height: 0; }
|
|
1614
|
+
.badge {
|
|
1615
|
+
display: inline-flex;
|
|
1616
|
+
align-items: center;
|
|
1617
|
+
justify-content: center;
|
|
1618
|
+
box-sizing: border-box;
|
|
1619
|
+
gap: 6px;
|
|
1620
|
+
min-height: 28px;
|
|
1621
|
+
padding: 4px 10px 4px 8px;
|
|
1622
|
+
border-radius: 9999px;
|
|
1623
|
+
text-decoration: none;
|
|
1624
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1625
|
+
font-size: 12px;
|
|
1626
|
+
font-weight: 500;
|
|
1627
|
+
border: 1px solid ${SHIELD_COLORS.border};
|
|
1628
|
+
background: ${SHIELD_COLORS.surface};
|
|
1629
|
+
color: ${SHIELD_COLORS.text};
|
|
1630
|
+
transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1631
|
+
}
|
|
1632
|
+
:host([theme="light"]) .badge {
|
|
1633
|
+
border-color: ${LIGHT_BORDER};
|
|
1634
|
+
background: ${LIGHT_SURFACE};
|
|
1635
|
+
color: ${LIGHT_TEXT};
|
|
1636
|
+
}
|
|
1637
|
+
.badge:hover {
|
|
1638
|
+
background: ${SHIELD_COLORS.surfaceHover};
|
|
1639
|
+
border-color: ${SHIELD_COLORS.accent};
|
|
1640
|
+
box-shadow: 0 0 0 1px ${SHIELD_COLORS.accentDim};
|
|
1641
|
+
}
|
|
1642
|
+
:host([theme="light"]) .badge:hover {
|
|
1643
|
+
background: ${LIGHT_SURFACE_HOVER};
|
|
1644
|
+
border-color: ${SHIELD_COLORS.accent};
|
|
1645
|
+
}
|
|
1646
|
+
.badge:focus-visible {
|
|
1647
|
+
outline: 2px solid ${SHIELD_COLORS.accent};
|
|
1648
|
+
outline-offset: 2px;
|
|
1649
|
+
}
|
|
1650
|
+
.icon { flex-shrink: 0; display: block; }
|
|
1651
|
+
.text { white-space: nowrap; }
|
|
1652
|
+
:host([size="compact"]) .text { display: none; }
|
|
1653
|
+
:host([size="compact"]) .badge { padding: 4px 6px; }
|
|
1654
|
+
@media (prefers-reduced-motion: reduce) { .badge { transition: none; } }
|
|
1655
|
+
`.trim();
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
// src/badge/multicorn-badge.ts
|
|
1659
|
+
var VERIFY_BASE = "https://multicorn.ai/verify/";
|
|
1660
|
+
var BADGE_ELEMENT_TAG = "multicorn-badge";
|
|
1661
|
+
var SHIELD_PATH = "M12 1L3 5v6c0 5.55 3.84 9.95 9 12 5.16-2.05 9-6.45 9-12V5l-9-4z";
|
|
1662
|
+
function parseOptionalCount(raw) {
|
|
1663
|
+
if (raw == null || raw === "") {
|
|
1664
|
+
return void 0;
|
|
1665
|
+
}
|
|
1666
|
+
const n = Number(raw);
|
|
1667
|
+
return Number.isNaN(n) ? void 0 : n;
|
|
1668
|
+
}
|
|
1669
|
+
var MulticornBadge = class extends HTMLElement {
|
|
1670
|
+
#didInjectStyle = false;
|
|
1671
|
+
ensureShadow() {
|
|
1672
|
+
if (this.shadowRoot != null) {
|
|
1673
|
+
return this.shadowRoot;
|
|
1674
|
+
}
|
|
1675
|
+
return this.attachShadow({ mode: "open" });
|
|
1676
|
+
}
|
|
1677
|
+
static get observedAttributes() {
|
|
1678
|
+
return ["agent-id", "size", "theme", "action-count"];
|
|
1679
|
+
}
|
|
1680
|
+
connectedCallback() {
|
|
1681
|
+
this.render();
|
|
1682
|
+
}
|
|
1683
|
+
attributeChangedCallback() {
|
|
1684
|
+
this.render();
|
|
1685
|
+
}
|
|
1686
|
+
render() {
|
|
1687
|
+
const root = this.ensureShadow();
|
|
1688
|
+
if (this.#didInjectStyle) ; else {
|
|
1689
|
+
const style = document.createElement("style");
|
|
1690
|
+
style.textContent = getBadgeStyleText();
|
|
1691
|
+
root.appendChild(style);
|
|
1692
|
+
this.#didInjectStyle = true;
|
|
1693
|
+
}
|
|
1694
|
+
const agentId = (this.getAttribute("agent-id") ?? "").trim();
|
|
1695
|
+
const actionCount = parseOptionalCount(this.getAttribute("action-count"));
|
|
1696
|
+
const prior = root.querySelector("a.badge");
|
|
1697
|
+
if (prior) {
|
|
1698
|
+
prior.remove();
|
|
1699
|
+
}
|
|
1700
|
+
if (agentId === "") {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
let labelSuffix;
|
|
1704
|
+
let ariaLabel;
|
|
1705
|
+
if (actionCount == null) {
|
|
1706
|
+
labelSuffix = "Secured by Multicorn";
|
|
1707
|
+
ariaLabel = "Secured by Multicorn, verify this agent";
|
|
1708
|
+
} else {
|
|
1709
|
+
const count = actionCount;
|
|
1710
|
+
const countText = String(count);
|
|
1711
|
+
labelSuffix = "Secured by Multicorn \xB7 " + countText + " actions secured";
|
|
1712
|
+
ariaLabel = "Secured by Multicorn \xB7 " + countText + " actions secured, verify this agent";
|
|
1713
|
+
}
|
|
1714
|
+
const href = `${VERIFY_BASE}${encodeURIComponent(agentId)}`;
|
|
1715
|
+
const a = document.createElement("a");
|
|
1716
|
+
a.className = "badge";
|
|
1717
|
+
a.href = href;
|
|
1718
|
+
a.target = "_blank";
|
|
1719
|
+
a.rel = "noopener noreferrer";
|
|
1720
|
+
a.setAttribute("aria-label", ariaLabel);
|
|
1721
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
1722
|
+
const svg = document.createElementNS(svgNs, "svg");
|
|
1723
|
+
svg.setAttribute("class", "icon");
|
|
1724
|
+
svg.setAttribute("width", "16");
|
|
1725
|
+
svg.setAttribute("height", "16");
|
|
1726
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
1727
|
+
svg.setAttribute("aria-hidden", "true");
|
|
1728
|
+
const path = document.createElementNS(svgNs, "path");
|
|
1729
|
+
path.setAttribute("d", SHIELD_PATH);
|
|
1730
|
+
path.setAttribute("fill", SHIELD_COLORS.accent);
|
|
1731
|
+
svg.appendChild(path);
|
|
1732
|
+
a.appendChild(svg);
|
|
1733
|
+
const text = document.createElement("span");
|
|
1734
|
+
text.className = "text";
|
|
1735
|
+
text.textContent = labelSuffix;
|
|
1736
|
+
a.appendChild(text);
|
|
1737
|
+
root.appendChild(a);
|
|
1738
|
+
}
|
|
1739
|
+
};
|
|
1740
|
+
if (customElements.get(BADGE_ELEMENT_TAG) === void 0) {
|
|
1741
|
+
customElements.define(BADGE_ELEMENT_TAG, MulticornBadge);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1602
1744
|
// src/logger/action-logger.ts
|
|
1603
1745
|
function createActionLogger(config) {
|
|
1604
1746
|
if (!config.apiKey || config.apiKey.trim().length === 0) {
|
|
@@ -2749,6 +2891,7 @@ exports.ACTION_STATUSES = ACTION_STATUSES;
|
|
|
2749
2891
|
exports.AGENT_STATUSES = AGENT_STATUSES;
|
|
2750
2892
|
exports.BUILT_IN_SERVICES = BUILT_IN_SERVICES;
|
|
2751
2893
|
exports.CONSENT_ELEMENT_TAG = CONSENT_ELEMENT_TAG;
|
|
2894
|
+
exports.MulticornBadge = MulticornBadge;
|
|
2752
2895
|
exports.MulticornShield = MulticornShield;
|
|
2753
2896
|
exports.PERMISSION_LEVELS = PERMISSION_LEVELS;
|
|
2754
2897
|
exports.SERVICE_NAME_PATTERN = SERVICE_NAME_PATTERN;
|
package/dist/index.d.cts
CHANGED
|
@@ -1069,6 +1069,29 @@ interface FocusTrap {
|
|
|
1069
1069
|
*/
|
|
1070
1070
|
declare function createFocusTrap(container: HTMLElement, initialFocus?: HTMLElement | null): FocusTrap;
|
|
1071
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* `<multicorn-badge>`: small embeddable trust badge (Shadow DOM).
|
|
1074
|
+
* Implemented as a native custom element to keep the CDN `badge.js` under the
|
|
1075
|
+
* size budget. Styling and tokens align with the Lit-based consent screen.
|
|
1076
|
+
*
|
|
1077
|
+
* @module badge/multicorn-badge
|
|
1078
|
+
*/
|
|
1079
|
+
/** Custom element tag for the trust badge. */
|
|
1080
|
+
declare const BADGE_ELEMENT_TAG: "multicorn-badge";
|
|
1081
|
+
declare class MulticornBadge extends HTMLElement {
|
|
1082
|
+
#private;
|
|
1083
|
+
private ensureShadow;
|
|
1084
|
+
static get observedAttributes(): string[];
|
|
1085
|
+
connectedCallback(): void;
|
|
1086
|
+
attributeChangedCallback(): void;
|
|
1087
|
+
private render;
|
|
1088
|
+
}
|
|
1089
|
+
declare global {
|
|
1090
|
+
interface HTMLElementTagNameMap {
|
|
1091
|
+
[BADGE_ELEMENT_TAG]: MulticornBadge;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1072
1095
|
/**
|
|
1073
1096
|
* Action logging client for Multicorn Shield.
|
|
1074
1097
|
*
|
|
@@ -2283,4 +2306,4 @@ interface ContentReviewRequestPayload {
|
|
|
2283
2306
|
*/
|
|
2284
2307
|
declare function requestContentReview(payload: ContentReviewRequestPayload, apiKey: string, baseUrl: string, logger?: PluginLogger): Promise<ContentReviewResult>;
|
|
2285
2308
|
|
|
2286
|
-
export { ACTION_STATUSES, AGENT_STATUSES, type Action, type ActionInput, type ActionLogger, type ActionLoggerConfig, type ActionPayload, type ActionStatus, type Agent, type AgentStatus, type ApiError, BUILT_IN_SERVICES, type BatchModeConfig, type BuiltInServiceName, CONSENT_ELEMENT_TAG, type ConsentDecision, type ConsentDeniedEventDetail, type ConsentEventDetail, type ConsentEventMap, type ConsentEventName, type ConsentGrantedEventDetail, type ConsentOptions, type ConsentPartialEventDetail, type ContentReviewRequestPayload, type ContentReviewResult, type ContentReviewStatusResponse, type FocusTrap, type McpAdapter, type McpAdapterConfig, type McpAdapterResult, type McpBlockedResult, type McpToolCall, type McpToolHandler, type McpToolResult, MulticornConsent, MulticornShield, type MulticornShieldConfig, PERMISSION_LEVELS, type Permission, type PermissionLevel, type RemainingBudget, SERVICE_NAME_PATTERN, type Scope, ScopeParseError, type ScopeParseResult, type ScopeRegistry, type ScopeRequest, type ServiceDefinition, type SpendCheckResult, type SpendingCheckResult, type SpendingChecker, type SpendingLimit, type SpendingLimits, type SpendingTrackerConfig, type ValidationResult, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
|
2309
|
+
export { ACTION_STATUSES, AGENT_STATUSES, type Action, type ActionInput, type ActionLogger, type ActionLoggerConfig, type ActionPayload, type ActionStatus, type Agent, type AgentStatus, type ApiError, BUILT_IN_SERVICES, type BatchModeConfig, type BuiltInServiceName, CONSENT_ELEMENT_TAG, type ConsentDecision, type ConsentDeniedEventDetail, type ConsentEventDetail, type ConsentEventMap, type ConsentEventName, type ConsentGrantedEventDetail, type ConsentOptions, type ConsentPartialEventDetail, type ContentReviewRequestPayload, type ContentReviewResult, type ContentReviewStatusResponse, type FocusTrap, type McpAdapter, type McpAdapterConfig, type McpAdapterResult, type McpBlockedResult, type McpToolCall, type McpToolHandler, type McpToolResult, MulticornBadge, MulticornConsent, MulticornShield, type MulticornShieldConfig, PERMISSION_LEVELS, type Permission, type PermissionLevel, type RemainingBudget, SERVICE_NAME_PATTERN, type Scope, ScopeParseError, type ScopeParseResult, type ScopeRegistry, type ScopeRequest, type ServiceDefinition, type SpendCheckResult, type SpendingCheckResult, type SpendingChecker, type SpendingLimit, type SpendingLimits, type SpendingTrackerConfig, type ValidationResult, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
package/dist/index.d.ts
CHANGED
|
@@ -1069,6 +1069,29 @@ interface FocusTrap {
|
|
|
1069
1069
|
*/
|
|
1070
1070
|
declare function createFocusTrap(container: HTMLElement, initialFocus?: HTMLElement | null): FocusTrap;
|
|
1071
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* `<multicorn-badge>`: small embeddable trust badge (Shadow DOM).
|
|
1074
|
+
* Implemented as a native custom element to keep the CDN `badge.js` under the
|
|
1075
|
+
* size budget. Styling and tokens align with the Lit-based consent screen.
|
|
1076
|
+
*
|
|
1077
|
+
* @module badge/multicorn-badge
|
|
1078
|
+
*/
|
|
1079
|
+
/** Custom element tag for the trust badge. */
|
|
1080
|
+
declare const BADGE_ELEMENT_TAG: "multicorn-badge";
|
|
1081
|
+
declare class MulticornBadge extends HTMLElement {
|
|
1082
|
+
#private;
|
|
1083
|
+
private ensureShadow;
|
|
1084
|
+
static get observedAttributes(): string[];
|
|
1085
|
+
connectedCallback(): void;
|
|
1086
|
+
attributeChangedCallback(): void;
|
|
1087
|
+
private render;
|
|
1088
|
+
}
|
|
1089
|
+
declare global {
|
|
1090
|
+
interface HTMLElementTagNameMap {
|
|
1091
|
+
[BADGE_ELEMENT_TAG]: MulticornBadge;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1072
1095
|
/**
|
|
1073
1096
|
* Action logging client for Multicorn Shield.
|
|
1074
1097
|
*
|
|
@@ -2283,4 +2306,4 @@ interface ContentReviewRequestPayload {
|
|
|
2283
2306
|
*/
|
|
2284
2307
|
declare function requestContentReview(payload: ContentReviewRequestPayload, apiKey: string, baseUrl: string, logger?: PluginLogger): Promise<ContentReviewResult>;
|
|
2285
2308
|
|
|
2286
|
-
export { ACTION_STATUSES, AGENT_STATUSES, type Action, type ActionInput, type ActionLogger, type ActionLoggerConfig, type ActionPayload, type ActionStatus, type Agent, type AgentStatus, type ApiError, BUILT_IN_SERVICES, type BatchModeConfig, type BuiltInServiceName, CONSENT_ELEMENT_TAG, type ConsentDecision, type ConsentDeniedEventDetail, type ConsentEventDetail, type ConsentEventMap, type ConsentEventName, type ConsentGrantedEventDetail, type ConsentOptions, type ConsentPartialEventDetail, type ContentReviewRequestPayload, type ContentReviewResult, type ContentReviewStatusResponse, type FocusTrap, type McpAdapter, type McpAdapterConfig, type McpAdapterResult, type McpBlockedResult, type McpToolCall, type McpToolHandler, type McpToolResult, MulticornConsent, MulticornShield, type MulticornShieldConfig, PERMISSION_LEVELS, type Permission, type PermissionLevel, type RemainingBudget, SERVICE_NAME_PATTERN, type Scope, ScopeParseError, type ScopeParseResult, type ScopeRegistry, type ScopeRequest, type ServiceDefinition, type SpendCheckResult, type SpendingCheckResult, type SpendingChecker, type SpendingLimit, type SpendingLimits, type SpendingTrackerConfig, type ValidationResult, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
|
2309
|
+
export { ACTION_STATUSES, AGENT_STATUSES, type Action, type ActionInput, type ActionLogger, type ActionLoggerConfig, type ActionPayload, type ActionStatus, type Agent, type AgentStatus, type ApiError, BUILT_IN_SERVICES, type BatchModeConfig, type BuiltInServiceName, CONSENT_ELEMENT_TAG, type ConsentDecision, type ConsentDeniedEventDetail, type ConsentEventDetail, type ConsentEventMap, type ConsentEventName, type ConsentGrantedEventDetail, type ConsentOptions, type ConsentPartialEventDetail, type ContentReviewRequestPayload, type ContentReviewResult, type ContentReviewStatusResponse, type FocusTrap, type McpAdapter, type McpAdapterConfig, type McpAdapterResult, type McpBlockedResult, type McpToolCall, type McpToolHandler, type McpToolResult, MulticornBadge, MulticornConsent, MulticornShield, type MulticornShieldConfig, PERMISSION_LEVELS, type Permission, type PermissionLevel, type RemainingBudget, SERVICE_NAME_PATTERN, type Scope, ScopeParseError, type ScopeParseResult, type ScopeRegistry, type ScopeRequest, type ServiceDefinition, type SpendCheckResult, type SpendingCheckResult, type SpendingChecker, type SpendingLimit, type SpendingLimits, type SpendingTrackerConfig, type ValidationResult, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
package/dist/index.js
CHANGED
|
@@ -430,6 +430,8 @@ function getScopeWarning(scopeString) {
|
|
|
430
430
|
const metadata = getScopeMetadata(scopeString);
|
|
431
431
|
return metadata?.warningMessage;
|
|
432
432
|
}
|
|
433
|
+
|
|
434
|
+
// src/shared/shield-tokens.ts
|
|
433
435
|
var SHIELD_COLORS = {
|
|
434
436
|
bg: "#0d0d14",
|
|
435
437
|
surface: "#14141f",
|
|
@@ -450,6 +452,8 @@ var SHIELD_COLORS = {
|
|
|
450
452
|
red: "#ef4444",
|
|
451
453
|
redDim: "rgba(239, 68, 68, 0.12)"
|
|
452
454
|
};
|
|
455
|
+
|
|
456
|
+
// src/consent/consent-styles.ts
|
|
453
457
|
var consentStyles = css`
|
|
454
458
|
:host {
|
|
455
459
|
display: block;
|
|
@@ -1597,6 +1601,144 @@ MulticornConsent = __decorateClass([
|
|
|
1597
1601
|
customElement(CONSENT_ELEMENT_TAG)
|
|
1598
1602
|
], MulticornConsent);
|
|
1599
1603
|
|
|
1604
|
+
// src/badge/badge-styles.ts
|
|
1605
|
+
var LIGHT_TEXT = "#0f172a";
|
|
1606
|
+
var LIGHT_SURFACE = "#f8fafc";
|
|
1607
|
+
var LIGHT_SURFACE_HOVER = "#f1f5f9";
|
|
1608
|
+
var LIGHT_BORDER = "#e2e8f0";
|
|
1609
|
+
function getBadgeStyleText() {
|
|
1610
|
+
return `
|
|
1611
|
+
:host { display: inline-block; line-height: 0; }
|
|
1612
|
+
.badge {
|
|
1613
|
+
display: inline-flex;
|
|
1614
|
+
align-items: center;
|
|
1615
|
+
justify-content: center;
|
|
1616
|
+
box-sizing: border-box;
|
|
1617
|
+
gap: 6px;
|
|
1618
|
+
min-height: 28px;
|
|
1619
|
+
padding: 4px 10px 4px 8px;
|
|
1620
|
+
border-radius: 9999px;
|
|
1621
|
+
text-decoration: none;
|
|
1622
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1623
|
+
font-size: 12px;
|
|
1624
|
+
font-weight: 500;
|
|
1625
|
+
border: 1px solid ${SHIELD_COLORS.border};
|
|
1626
|
+
background: ${SHIELD_COLORS.surface};
|
|
1627
|
+
color: ${SHIELD_COLORS.text};
|
|
1628
|
+
transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1629
|
+
}
|
|
1630
|
+
:host([theme="light"]) .badge {
|
|
1631
|
+
border-color: ${LIGHT_BORDER};
|
|
1632
|
+
background: ${LIGHT_SURFACE};
|
|
1633
|
+
color: ${LIGHT_TEXT};
|
|
1634
|
+
}
|
|
1635
|
+
.badge:hover {
|
|
1636
|
+
background: ${SHIELD_COLORS.surfaceHover};
|
|
1637
|
+
border-color: ${SHIELD_COLORS.accent};
|
|
1638
|
+
box-shadow: 0 0 0 1px ${SHIELD_COLORS.accentDim};
|
|
1639
|
+
}
|
|
1640
|
+
:host([theme="light"]) .badge:hover {
|
|
1641
|
+
background: ${LIGHT_SURFACE_HOVER};
|
|
1642
|
+
border-color: ${SHIELD_COLORS.accent};
|
|
1643
|
+
}
|
|
1644
|
+
.badge:focus-visible {
|
|
1645
|
+
outline: 2px solid ${SHIELD_COLORS.accent};
|
|
1646
|
+
outline-offset: 2px;
|
|
1647
|
+
}
|
|
1648
|
+
.icon { flex-shrink: 0; display: block; }
|
|
1649
|
+
.text { white-space: nowrap; }
|
|
1650
|
+
:host([size="compact"]) .text { display: none; }
|
|
1651
|
+
:host([size="compact"]) .badge { padding: 4px 6px; }
|
|
1652
|
+
@media (prefers-reduced-motion: reduce) { .badge { transition: none; } }
|
|
1653
|
+
`.trim();
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/badge/multicorn-badge.ts
|
|
1657
|
+
var VERIFY_BASE = "https://multicorn.ai/verify/";
|
|
1658
|
+
var BADGE_ELEMENT_TAG = "multicorn-badge";
|
|
1659
|
+
var SHIELD_PATH = "M12 1L3 5v6c0 5.55 3.84 9.95 9 12 5.16-2.05 9-6.45 9-12V5l-9-4z";
|
|
1660
|
+
function parseOptionalCount(raw) {
|
|
1661
|
+
if (raw == null || raw === "") {
|
|
1662
|
+
return void 0;
|
|
1663
|
+
}
|
|
1664
|
+
const n = Number(raw);
|
|
1665
|
+
return Number.isNaN(n) ? void 0 : n;
|
|
1666
|
+
}
|
|
1667
|
+
var MulticornBadge = class extends HTMLElement {
|
|
1668
|
+
#didInjectStyle = false;
|
|
1669
|
+
ensureShadow() {
|
|
1670
|
+
if (this.shadowRoot != null) {
|
|
1671
|
+
return this.shadowRoot;
|
|
1672
|
+
}
|
|
1673
|
+
return this.attachShadow({ mode: "open" });
|
|
1674
|
+
}
|
|
1675
|
+
static get observedAttributes() {
|
|
1676
|
+
return ["agent-id", "size", "theme", "action-count"];
|
|
1677
|
+
}
|
|
1678
|
+
connectedCallback() {
|
|
1679
|
+
this.render();
|
|
1680
|
+
}
|
|
1681
|
+
attributeChangedCallback() {
|
|
1682
|
+
this.render();
|
|
1683
|
+
}
|
|
1684
|
+
render() {
|
|
1685
|
+
const root = this.ensureShadow();
|
|
1686
|
+
if (this.#didInjectStyle) ; else {
|
|
1687
|
+
const style = document.createElement("style");
|
|
1688
|
+
style.textContent = getBadgeStyleText();
|
|
1689
|
+
root.appendChild(style);
|
|
1690
|
+
this.#didInjectStyle = true;
|
|
1691
|
+
}
|
|
1692
|
+
const agentId = (this.getAttribute("agent-id") ?? "").trim();
|
|
1693
|
+
const actionCount = parseOptionalCount(this.getAttribute("action-count"));
|
|
1694
|
+
const prior = root.querySelector("a.badge");
|
|
1695
|
+
if (prior) {
|
|
1696
|
+
prior.remove();
|
|
1697
|
+
}
|
|
1698
|
+
if (agentId === "") {
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
let labelSuffix;
|
|
1702
|
+
let ariaLabel;
|
|
1703
|
+
if (actionCount == null) {
|
|
1704
|
+
labelSuffix = "Secured by Multicorn";
|
|
1705
|
+
ariaLabel = "Secured by Multicorn, verify this agent";
|
|
1706
|
+
} else {
|
|
1707
|
+
const count = actionCount;
|
|
1708
|
+
const countText = String(count);
|
|
1709
|
+
labelSuffix = "Secured by Multicorn \xB7 " + countText + " actions secured";
|
|
1710
|
+
ariaLabel = "Secured by Multicorn \xB7 " + countText + " actions secured, verify this agent";
|
|
1711
|
+
}
|
|
1712
|
+
const href = `${VERIFY_BASE}${encodeURIComponent(agentId)}`;
|
|
1713
|
+
const a = document.createElement("a");
|
|
1714
|
+
a.className = "badge";
|
|
1715
|
+
a.href = href;
|
|
1716
|
+
a.target = "_blank";
|
|
1717
|
+
a.rel = "noopener noreferrer";
|
|
1718
|
+
a.setAttribute("aria-label", ariaLabel);
|
|
1719
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
1720
|
+
const svg = document.createElementNS(svgNs, "svg");
|
|
1721
|
+
svg.setAttribute("class", "icon");
|
|
1722
|
+
svg.setAttribute("width", "16");
|
|
1723
|
+
svg.setAttribute("height", "16");
|
|
1724
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
1725
|
+
svg.setAttribute("aria-hidden", "true");
|
|
1726
|
+
const path = document.createElementNS(svgNs, "path");
|
|
1727
|
+
path.setAttribute("d", SHIELD_PATH);
|
|
1728
|
+
path.setAttribute("fill", SHIELD_COLORS.accent);
|
|
1729
|
+
svg.appendChild(path);
|
|
1730
|
+
a.appendChild(svg);
|
|
1731
|
+
const text = document.createElement("span");
|
|
1732
|
+
text.className = "text";
|
|
1733
|
+
text.textContent = labelSuffix;
|
|
1734
|
+
a.appendChild(text);
|
|
1735
|
+
root.appendChild(a);
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
if (customElements.get(BADGE_ELEMENT_TAG) === void 0) {
|
|
1739
|
+
customElements.define(BADGE_ELEMENT_TAG, MulticornBadge);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1600
1742
|
// src/logger/action-logger.ts
|
|
1601
1743
|
function createActionLogger(config) {
|
|
1602
1744
|
if (!config.apiKey || config.apiKey.trim().length === 0) {
|
|
@@ -2743,4 +2885,4 @@ function validateApiKey(apiKey) {
|
|
|
2743
2885
|
}
|
|
2744
2886
|
}
|
|
2745
2887
|
|
|
2746
|
-
export { ACTION_STATUSES, AGENT_STATUSES, BUILT_IN_SERVICES, CONSENT_ELEMENT_TAG, MulticornConsent, MulticornShield, PERMISSION_LEVELS, SERVICE_NAME_PATTERN, ScopeParseError, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
|
2888
|
+
export { ACTION_STATUSES, AGENT_STATUSES, BUILT_IN_SERVICES, CONSENT_ELEMENT_TAG, MulticornBadge, MulticornConsent, MulticornShield, PERMISSION_LEVELS, SERVICE_NAME_PATTERN, ScopeParseError, centsToDollars, createActionLogger, createFocusTrap, createMcpAdapter, createScopeRegistry, createSpendingChecker, dollarsToCents, formatScope, getPermissionLabel, getScopeLabel, getScopeShortLabel, getServiceDisplayName, getServiceIcon, hasScope, isBlockedResult, isPublicContentAction, isValidScopeString, parseScope, parseScopes, requestContentReview, requiresContentReview, tryParseScope, validateAllScopesAccess, validateScopeAccess };
|
|
@@ -884,7 +884,9 @@ var plugin = {
|
|
|
884
884
|
if (config.agentName !== null) {
|
|
885
885
|
pinnedAgentName = config.agentName;
|
|
886
886
|
}
|
|
887
|
-
|
|
887
|
+
api.logger.info(
|
|
888
|
+
`Multicorn Shield config loaded: hasApiKey=${String((cachedMulticornConfig?.apiKey ?? "").length > 0)} baseUrl=${cachedMulticornConfig?.baseUrl ?? "default"} agentName=${cachedMulticornConfig?.agentName ?? "unset"} defaultAgent=${cachedMulticornConfig?.defaultAgent ?? "unset"} agents=${String(cachedMulticornConfig?.agents?.length ?? 0)}`
|
|
889
|
+
);
|
|
888
890
|
api.on("before_tool_call", beforeToolCall, { priority: 10 });
|
|
889
891
|
api.on("after_tool_call", afterToolCall);
|
|
890
892
|
api.logger.info("Multicorn Shield plugin registered.");
|
package/dist/shield-extension.js
CHANGED
|
@@ -22359,11 +22359,117 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
|
|
|
22359
22359
|
|
|
22360
22360
|
// package.json
|
|
22361
22361
|
var package_default = {
|
|
22362
|
-
version: "0.
|
|
22362
|
+
version: "0.11.0"};
|
|
22363
22363
|
|
|
22364
22364
|
// src/package-meta.ts
|
|
22365
22365
|
var PACKAGE_VERSION = package_default.version;
|
|
22366
22366
|
|
|
22367
|
+
// src/extension/proxy-url-validator.ts
|
|
22368
|
+
var ProxyUrlValidationError = class extends Error {
|
|
22369
|
+
constructor(message) {
|
|
22370
|
+
super(message);
|
|
22371
|
+
this.name = "ProxyUrlValidationError";
|
|
22372
|
+
}
|
|
22373
|
+
};
|
|
22374
|
+
function isPrivateOrReservedIpv4(hostname3) {
|
|
22375
|
+
const parts = hostname3.split(".");
|
|
22376
|
+
if (parts.length !== 4) {
|
|
22377
|
+
return false;
|
|
22378
|
+
}
|
|
22379
|
+
const octets = [];
|
|
22380
|
+
for (const p of parts) {
|
|
22381
|
+
if (!/^\d{1,3}$/.test(p)) {
|
|
22382
|
+
return false;
|
|
22383
|
+
}
|
|
22384
|
+
const n = Number.parseInt(p, 10);
|
|
22385
|
+
if (Number.isNaN(n) || n < 0 || n > 255) {
|
|
22386
|
+
return false;
|
|
22387
|
+
}
|
|
22388
|
+
octets.push(n);
|
|
22389
|
+
}
|
|
22390
|
+
const [a, b] = octets;
|
|
22391
|
+
if (a === void 0 || b === void 0) {
|
|
22392
|
+
return false;
|
|
22393
|
+
}
|
|
22394
|
+
if (a === 127) {
|
|
22395
|
+
return true;
|
|
22396
|
+
}
|
|
22397
|
+
if (a === 10) {
|
|
22398
|
+
return true;
|
|
22399
|
+
}
|
|
22400
|
+
if (a === 172 && b >= 16 && b <= 31) {
|
|
22401
|
+
return true;
|
|
22402
|
+
}
|
|
22403
|
+
if (a === 192 && b === 168) {
|
|
22404
|
+
return true;
|
|
22405
|
+
}
|
|
22406
|
+
if (a === 169 && b === 254) {
|
|
22407
|
+
return true;
|
|
22408
|
+
}
|
|
22409
|
+
if (a === 0 && b === 0 && octets[2] === 0 && octets[3] === 0) {
|
|
22410
|
+
return true;
|
|
22411
|
+
}
|
|
22412
|
+
return false;
|
|
22413
|
+
}
|
|
22414
|
+
function isBlockedIpv6(host) {
|
|
22415
|
+
const h = host.split("%")[0]?.toLowerCase() ?? host.toLowerCase();
|
|
22416
|
+
if (h === "::1") {
|
|
22417
|
+
return true;
|
|
22418
|
+
}
|
|
22419
|
+
if (h.startsWith("fe80:")) {
|
|
22420
|
+
return true;
|
|
22421
|
+
}
|
|
22422
|
+
if (h.startsWith("fc") || h.startsWith("fd")) {
|
|
22423
|
+
return true;
|
|
22424
|
+
}
|
|
22425
|
+
return false;
|
|
22426
|
+
}
|
|
22427
|
+
function hostForValidation(hostname3) {
|
|
22428
|
+
if (hostname3.startsWith("[") && hostname3.endsWith("]")) {
|
|
22429
|
+
return hostname3.slice(1, -1);
|
|
22430
|
+
}
|
|
22431
|
+
return hostname3;
|
|
22432
|
+
}
|
|
22433
|
+
function assertSafeProxyUrl(raw, options) {
|
|
22434
|
+
let url2;
|
|
22435
|
+
try {
|
|
22436
|
+
url2 = new URL(raw);
|
|
22437
|
+
} catch {
|
|
22438
|
+
throw new ProxyUrlValidationError(`Invalid proxy URL: ${raw}`);
|
|
22439
|
+
}
|
|
22440
|
+
if (url2.protocol !== "https:" && url2.protocol !== "http:") {
|
|
22441
|
+
throw new ProxyUrlValidationError(
|
|
22442
|
+
`Unsupported proxy URL scheme: ${url2.protocol} - only https: and http: are allowed`
|
|
22443
|
+
);
|
|
22444
|
+
}
|
|
22445
|
+
const hostname3 = url2.hostname;
|
|
22446
|
+
if (hostname3.length === 0) {
|
|
22447
|
+
throw new ProxyUrlValidationError(`Proxy URL has no hostname: ${raw}`);
|
|
22448
|
+
}
|
|
22449
|
+
if (options?.allowPrivateNetworks === true) {
|
|
22450
|
+
return;
|
|
22451
|
+
}
|
|
22452
|
+
const host = hostForValidation(hostname3);
|
|
22453
|
+
if (host.toLowerCase() === "localhost") {
|
|
22454
|
+
throw new ProxyUrlValidationError(
|
|
22455
|
+
`Proxy URL points to a private/reserved network address: ${url2.hostname}`
|
|
22456
|
+
);
|
|
22457
|
+
}
|
|
22458
|
+
if (host.includes(":")) {
|
|
22459
|
+
if (isBlockedIpv6(host)) {
|
|
22460
|
+
throw new ProxyUrlValidationError(
|
|
22461
|
+
`Proxy URL points to a private/reserved network address: ${url2.hostname}`
|
|
22462
|
+
);
|
|
22463
|
+
}
|
|
22464
|
+
return;
|
|
22465
|
+
}
|
|
22466
|
+
if (isPrivateOrReservedIpv4(host)) {
|
|
22467
|
+
throw new ProxyUrlValidationError(
|
|
22468
|
+
`Proxy URL points to a private/reserved network address: ${url2.hostname}`
|
|
22469
|
+
);
|
|
22470
|
+
}
|
|
22471
|
+
}
|
|
22472
|
+
|
|
22367
22473
|
// src/extension/proxy-client.ts
|
|
22368
22474
|
var MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
22369
22475
|
var ProxyConfigFetchError = class extends Error {
|
|
@@ -22404,8 +22510,12 @@ function isProxyConfigRow(v) {
|
|
|
22404
22510
|
const o = v;
|
|
22405
22511
|
return typeof o["proxy_url"] === "string" && o["proxy_url"].length > 0 && typeof o["server_name"] === "string" && typeof o["target_url"] === "string";
|
|
22406
22512
|
}
|
|
22407
|
-
async function fetchProxyConfigs(baseUrl, apiKey, timeoutMs) {
|
|
22513
|
+
async function fetchProxyConfigs(baseUrl, apiKey, timeoutMs, options) {
|
|
22408
22514
|
const url2 = `${normalizeBaseUrl(baseUrl)}/api/v1/proxy/config`;
|
|
22515
|
+
assertSafeProxyUrl(
|
|
22516
|
+
url2,
|
|
22517
|
+
options?.allowPrivateNetworks === true ? { allowPrivateNetworks: true } : void 0
|
|
22518
|
+
);
|
|
22409
22519
|
let response;
|
|
22410
22520
|
try {
|
|
22411
22521
|
response = await fetch(url2, {
|
|
@@ -22563,6 +22673,10 @@ var ProxySession = class {
|
|
|
22563
22673
|
this.nextId = 1;
|
|
22564
22674
|
this.sessionId = null;
|
|
22565
22675
|
this.closed = false;
|
|
22676
|
+
assertSafeProxyUrl(
|
|
22677
|
+
proxyUrl,
|
|
22678
|
+
options?.allowPrivateNetworks === true ? { allowPrivateNetworks: true } : void 0
|
|
22679
|
+
);
|
|
22566
22680
|
this.proxyUrl = proxyUrl.replace(/\/+$/, "") + "/mcp";
|
|
22567
22681
|
this.apiKey = apiKey;
|
|
22568
22682
|
this.requestTimeoutMs = options?.requestTimeoutMs ?? 6e4;
|
|
@@ -23554,6 +23668,8 @@ async function autoCreateProxyConfig(baseUrl, apiKey, serverName, entry, agentNa
|
|
|
23554
23668
|
const targetUrl = `stdio://${entry.command}/${entry.args.join("/")}`;
|
|
23555
23669
|
const url2 = `${baseUrl.replace(/\/+$/, "")}/api/v1/proxy/config`;
|
|
23556
23670
|
debugLog2(`[SHIELD] Auto-creating proxy config for "${serverName}".`);
|
|
23671
|
+
const allowPrivateNetworks = process.env["MULTICORN_ALLOW_PRIVATE_PROXY_HOSTS"] === "1";
|
|
23672
|
+
assertSafeProxyUrl(url2, { allowPrivateNetworks });
|
|
23557
23673
|
let response;
|
|
23558
23674
|
try {
|
|
23559
23675
|
response = await fetch(url2, {
|
|
@@ -23686,6 +23802,7 @@ async function runShieldExtension() {
|
|
|
23686
23802
|
`[SHIELD] Config read; ${String(serverCount)} MCP server(s) discovered (excluding Shield).`
|
|
23687
23803
|
);
|
|
23688
23804
|
debugLog2("[SHIELD] Resolving proxy configs (local config or API).");
|
|
23805
|
+
const allowPrivateNetworks = process.env["MULTICORN_ALLOW_PRIVATE_PROXY_HOSTS"] === "1";
|
|
23689
23806
|
let configs;
|
|
23690
23807
|
const localConfigs = await readProxyConfigsFromLocalMulticornConfig();
|
|
23691
23808
|
if (localConfigs.length > 0) {
|
|
@@ -23694,7 +23811,9 @@ async function runShieldExtension() {
|
|
|
23694
23811
|
} else {
|
|
23695
23812
|
debugLog2("[SHIELD] No local proxy configs; fetching from API.");
|
|
23696
23813
|
try {
|
|
23697
|
-
configs = await fetchProxyConfigs(baseUrl, apiKey, SETUP_TIMEOUT_MS
|
|
23814
|
+
configs = await fetchProxyConfigs(baseUrl, apiKey, SETUP_TIMEOUT_MS, {
|
|
23815
|
+
allowPrivateNetworks
|
|
23816
|
+
});
|
|
23698
23817
|
} catch (e) {
|
|
23699
23818
|
clearTimeout(setupTimeout);
|
|
23700
23819
|
if (e instanceof ProxyConfigFetchError) {
|
|
@@ -23728,7 +23847,9 @@ async function runShieldExtension() {
|
|
|
23728
23847
|
`[SHIELD] Auto-created ${String(createdCount)} proxy config(s); re-fetching from API.`
|
|
23729
23848
|
);
|
|
23730
23849
|
try {
|
|
23731
|
-
configs = await fetchProxyConfigs(baseUrl, apiKey, SETUP_TIMEOUT_MS
|
|
23850
|
+
configs = await fetchProxyConfigs(baseUrl, apiKey, SETUP_TIMEOUT_MS, {
|
|
23851
|
+
allowPrivateNetworks
|
|
23852
|
+
});
|
|
23732
23853
|
} catch (e) {
|
|
23733
23854
|
const message = e instanceof Error ? e.message : String(e);
|
|
23734
23855
|
debugLog2(`[SHIELD] Re-fetch after auto-creation failed: ${message}`);
|
|
@@ -23766,7 +23887,7 @@ async function runShieldExtension() {
|
|
|
23766
23887
|
const toolsByProxy = /* @__PURE__ */ new Map();
|
|
23767
23888
|
const sessionByProxyUrl = /* @__PURE__ */ new Map();
|
|
23768
23889
|
for (const cfg of configs) {
|
|
23769
|
-
const session = new ProxySession(cfg.proxy_url, apiKey);
|
|
23890
|
+
const session = new ProxySession(cfg.proxy_url, apiKey, { allowPrivateNetworks });
|
|
23770
23891
|
try {
|
|
23771
23892
|
debugLog2(`[SHIELD] Initializing proxy session for ${cfg.server_name}.`);
|
|
23772
23893
|
await session.initialize();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "multicorn-shield",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "The control layer for AI agents: permissions, consent, spending limits, and audit logging.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Multicorn AI Pty Ltd",
|
|
@@ -45,13 +45,18 @@
|
|
|
45
45
|
"access": "public",
|
|
46
46
|
"provenance": true
|
|
47
47
|
},
|
|
48
|
-
"sideEffects":
|
|
48
|
+
"sideEffects": [
|
|
49
|
+
"dist/index.js",
|
|
50
|
+
"dist/index.cjs",
|
|
51
|
+
"dist/badge.js",
|
|
52
|
+
"src/badge/multicorn-badge.ts"
|
|
53
|
+
],
|
|
49
54
|
"engines": {
|
|
50
55
|
"node": ">=20"
|
|
51
56
|
},
|
|
52
57
|
"lint-staged": {
|
|
53
58
|
"*.ts": [
|
|
54
|
-
"eslint --fix",
|
|
59
|
+
"eslint --fix --no-warn-ignored",
|
|
55
60
|
"prettier --write"
|
|
56
61
|
],
|
|
57
62
|
"*.{json,md}": [
|
|
@@ -97,6 +102,11 @@
|
|
|
97
102
|
"path": "dist/index.cjs",
|
|
98
103
|
"limit": "50 kB",
|
|
99
104
|
"gzip": true
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"path": "dist/badge.js",
|
|
108
|
+
"limit": "5 kB",
|
|
109
|
+
"gzip": true
|
|
100
110
|
}
|
|
101
111
|
],
|
|
102
112
|
"keywords": [
|
|
@@ -123,8 +133,8 @@
|
|
|
123
133
|
"scripts": {
|
|
124
134
|
"build": "tsup",
|
|
125
135
|
"dev": "tsup --watch",
|
|
126
|
-
"lint": "eslint . && prettier --check .",
|
|
127
|
-
"lint:fix": "eslint --fix . && prettier --write .",
|
|
136
|
+
"lint": "eslint . --no-warn-ignored && prettier --check .",
|
|
137
|
+
"lint:fix": "eslint --fix . --no-warn-ignored && prettier --write .",
|
|
128
138
|
"test": "vitest run",
|
|
129
139
|
"test:watch": "vitest",
|
|
130
140
|
"test:coverage": "vitest run --coverage",
|