@tangle-network/agent-app 0.45.7 → 0.45.9
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/assistant/index.js +5 -5
- package/dist/auth-Bulnsz3V.d.ts +73 -0
- package/dist/chat-routes/index.d.ts +1 -1
- package/dist/chat-routes/index.js +9 -9
- package/dist/chat-store/index.js +2 -2
- package/dist/{chunk-ITCINLSU.js → chunk-C5OIABSB.js} +2 -2
- package/dist/{chunk-YRFB2KEA.js → chunk-CKUZVDZ7.js} +2 -2
- package/dist/{chunk-4XNCMUVI.js → chunk-EPOPI77J.js} +5 -5
- package/dist/{chunk-DMYCGXBP.js → chunk-OO4DROKM.js} +1 -1
- package/dist/{chunk-UXMIPX3Z.js → chunk-WUZZVQKR.js} +4 -4
- package/dist/{chunk-IVEKCOM7.js → chunk-YOFQO4R6.js} +6 -2
- package/dist/chunk-YOFQO4R6.js.map +1 -0
- package/dist/chunk-ZSJRDHCN.js +129 -0
- package/dist/chunk-ZSJRDHCN.js.map +1 -0
- package/dist/design-canvas/index.d.ts +2 -2
- package/dist/design-canvas/index.js +1 -1
- package/dist/design-canvas-react/index.js +4 -4
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/{mcp-BOgNWSED.d.ts → mcp-C-jV_Xe9.d.ts} +1 -1
- package/dist/peer-floors/check.d.ts +78 -0
- package/dist/peer-floors/check.js +13 -0
- package/dist/peer-floors/check.js.map +1 -0
- package/dist/peer-floors/cli.d.ts +1 -0
- package/dist/peer-floors/cli.js +19 -0
- package/dist/peer-floors/cli.js.map +1 -0
- package/dist/preset-cloudflare/index.js +3 -3
- package/dist/runtime/index.d.ts +2 -2
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +4 -4
- package/dist/sequences/index.d.ts +2 -2
- package/dist/sequences/index.js +1 -1
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/index.js +2 -2
- package/dist/web-react/index.js +10 -10
- package/package.json +9 -3
- package/dist/auth-DJs6lfAs.d.ts +0 -42
- package/dist/chunk-IVEKCOM7.js.map +0 -1
- /package/dist/{chunk-ITCINLSU.js.map → chunk-C5OIABSB.js.map} +0 -0
- /package/dist/{chunk-YRFB2KEA.js.map → chunk-CKUZVDZ7.js.map} +0 -0
- /package/dist/{chunk-4XNCMUVI.js.map → chunk-EPOPI77J.js.map} +0 -0
- /package/dist/{chunk-DMYCGXBP.js.map → chunk-OO4DROKM.js.map} +0 -0
- /package/dist/{chunk-UXMIPX3Z.js.map → chunk-WUZZVQKR.js.map} +0 -0
package/dist/assistant/index.js
CHANGED
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
ChatMessages,
|
|
4
4
|
ModelPicker,
|
|
5
5
|
ProviderLogo
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-CKUZVDZ7.js";
|
|
7
|
+
import "../chunk-6MUJROBT.js";
|
|
8
|
+
import "../chunk-BATKJP3P.js";
|
|
7
9
|
import "../chunk-FBVLEGEG.js";
|
|
8
10
|
import "../chunk-GINKOZFD.js";
|
|
9
11
|
import "../chunk-YTMKRL3L.js";
|
|
10
12
|
import "../chunk-GEYACSFW.js";
|
|
11
|
-
import "../chunk-6MUJROBT.js";
|
|
12
|
-
import "../chunk-BATKJP3P.js";
|
|
13
13
|
import "../chunk-QY4BRKRJ.js";
|
|
14
14
|
import "../chunk-WBHPN5DY.js";
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-ZVEEWGDK.js";
|
|
15
|
+
import "../chunk-WUZZVQKR.js";
|
|
17
16
|
import "../chunk-KWXUBMXU.js";
|
|
17
|
+
import "../chunk-ZVEEWGDK.js";
|
|
18
18
|
import "../chunk-5EPIPT4V.js";
|
|
19
19
|
import "../chunk-3ZK5IJSW.js";
|
|
20
20
|
import "../chunk-YJMCRXQQ.js";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { A as AppToolContext } from './types-DbU-oO5h.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Header names carrying the server-set per-turn context + the capability token.
|
|
5
|
+
* Defaults are product-neutral (`X-Agent-App-*`); a product that already ships
|
|
6
|
+
* a header convention (e.g. `X-Acme-User-Id`) passes its own.
|
|
7
|
+
*/
|
|
8
|
+
interface ToolHeaderNames {
|
|
9
|
+
userId: string;
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
threadId: string;
|
|
12
|
+
}
|
|
13
|
+
/** Provide default HTTP header names for user, workspace, and thread identification */
|
|
14
|
+
declare const DEFAULT_HEADER_NAMES: ToolHeaderNames;
|
|
15
|
+
/**
|
|
16
|
+
* Which identity the bearer is bound to.
|
|
17
|
+
*
|
|
18
|
+
* `'userId'` (default) is right when the product mints a token per user and can
|
|
19
|
+
* deliver it per turn.
|
|
20
|
+
*
|
|
21
|
+
* `'workspaceId'` is the only workable choice when the token has to survive in
|
|
22
|
+
* the BOX ENVIRONMENT. Since agent-interface 0.38 a credential may reach a
|
|
23
|
+
* profile only as a reference the sandbox resolves from that environment, and
|
|
24
|
+
* the environment is workspace-wide and written once at box creation. A
|
|
25
|
+
* per-user token therefore cannot be delivered at all — and a per-user token
|
|
26
|
+
* that IS written there was never per-user in any meaningful sense, because
|
|
27
|
+
* every member of that workspace's box can read it.
|
|
28
|
+
*
|
|
29
|
+
* Binding the bearer to the workspace does NOT collapse the identity: the user
|
|
30
|
+
* header is still required, still server-set, still returned on `ctx`, and is
|
|
31
|
+
* what downstream domain code attributes work to. Only the question "may this
|
|
32
|
+
* caller act at all" moves from the user to the workspace — which is what the
|
|
33
|
+
* shared box already implies.
|
|
34
|
+
*/
|
|
35
|
+
type CapabilitySubject = 'userId' | 'workspaceId';
|
|
36
|
+
/** Define options to verify bearer tokens and customize authentication header names */
|
|
37
|
+
interface AuthenticateOptions {
|
|
38
|
+
/** Verify the bearer capability token belongs to the subject named by
|
|
39
|
+
* {@link AuthenticateOptions.subject}. The product's HMAC/JWT impl — the
|
|
40
|
+
* seam that keeps token crypto out of this package. */
|
|
41
|
+
verifyToken: (subject: string, bearer: string) => Promise<boolean>;
|
|
42
|
+
headerNames?: ToolHeaderNames;
|
|
43
|
+
/** What the bearer is bound to. Defaults to `'userId'`, so an existing caller
|
|
44
|
+
* is byte-unchanged. */
|
|
45
|
+
subject?: CapabilitySubject;
|
|
46
|
+
}
|
|
47
|
+
/** Represent the result of tool authentication with success context or failure response */
|
|
48
|
+
type ToolAuthResult = {
|
|
49
|
+
ok: true;
|
|
50
|
+
ctx: AppToolContext;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
response: Response;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Recover + verify the trusted context for a tool request.
|
|
57
|
+
*
|
|
58
|
+
* Both the user and the workspace come from server-set headers — never from
|
|
59
|
+
* tool args — so the model can neither forge identity nor target another
|
|
60
|
+
* workspace. The bearer must verify against whichever of the two the product
|
|
61
|
+
* declares as its {@link CapabilitySubject}.
|
|
62
|
+
*
|
|
63
|
+
* Fail-closed, and deliberately in this order: a missing credential or a token
|
|
64
|
+
* minted for another subject yields 401 before anything else is read. When the
|
|
65
|
+
* subject is the workspace, its header is required BEFORE verification rather
|
|
66
|
+
* than after — verifying against an absent subject is not a check at all.
|
|
67
|
+
*/
|
|
68
|
+
declare function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult>;
|
|
69
|
+
/** Read a tool's argument object from the request body, tolerant of MCP host
|
|
70
|
+
* aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */
|
|
71
|
+
declare function readToolArgs<T>(request: Request): Promise<T | null>;
|
|
72
|
+
|
|
73
|
+
export { type AuthenticateOptions as A, DEFAULT_HEADER_NAMES as D, type ToolHeaderNames as T, type ToolAuthResult as a, authenticateToolRequest as b, readToolArgs as r };
|
|
@@ -16,7 +16,7 @@ import '../contract-CQNvv5th.js';
|
|
|
16
16
|
import '../types-CCeYywdS.js';
|
|
17
17
|
import '../plans/index.js';
|
|
18
18
|
import '@tangle-network/sandbox/core';
|
|
19
|
-
import '../auth-
|
|
19
|
+
import '../auth-Bulnsz3V.js';
|
|
20
20
|
import '../types-DbU-oO5h.js';
|
|
21
21
|
import '../harness/index.js';
|
|
22
22
|
import '../model-CdCDfBA9.js';
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseJsonObjectBody
|
|
3
|
+
} from "../chunk-J25RST7G.js";
|
|
1
4
|
import {
|
|
2
5
|
createSandboxFileIndexRoute
|
|
3
6
|
} from "../chunk-QY4BRKRJ.js";
|
|
@@ -32,16 +35,12 @@ import {
|
|
|
32
35
|
import {
|
|
33
36
|
createInteractionAnswerRoute
|
|
34
37
|
} from "../chunk-3BK3BC2L.js";
|
|
35
|
-
import {
|
|
36
|
-
parseJsonObjectBody
|
|
37
|
-
} from "../chunk-J25RST7G.js";
|
|
38
38
|
import {
|
|
39
39
|
attachmentInputToPart,
|
|
40
40
|
attachmentKindForMime,
|
|
41
41
|
mentionInputToPart,
|
|
42
42
|
toChatMessageParts
|
|
43
|
-
} from "../chunk-
|
|
44
|
-
import "../chunk-ZVEEWGDK.js";
|
|
43
|
+
} from "../chunk-WUZZVQKR.js";
|
|
45
44
|
import {
|
|
46
45
|
ChatTurnInputError,
|
|
47
46
|
DISPATCH_MAX_MEDIA_PARTS,
|
|
@@ -63,6 +62,7 @@ import {
|
|
|
63
62
|
promptPartsByteSize,
|
|
64
63
|
validateSandboxMentionPath
|
|
65
64
|
} from "../chunk-KWXUBMXU.js";
|
|
65
|
+
import "../chunk-ZVEEWGDK.js";
|
|
66
66
|
import {
|
|
67
67
|
asRecord,
|
|
68
68
|
asString,
|
|
@@ -100,11 +100,11 @@ import {
|
|
|
100
100
|
flattenHistory,
|
|
101
101
|
readSandboxBinaryBytes,
|
|
102
102
|
statSandboxFileSize
|
|
103
|
-
} from "../chunk-
|
|
104
|
-
import "../chunk-LWSJK546.js";
|
|
103
|
+
} from "../chunk-EPOPI77J.js";
|
|
105
104
|
import "../chunk-73F3CKVK.js";
|
|
106
|
-
import "../chunk-
|
|
107
|
-
import "../chunk-
|
|
105
|
+
import "../chunk-LWSJK546.js";
|
|
106
|
+
import "../chunk-C5OIABSB.js";
|
|
107
|
+
import "../chunk-YOFQO4R6.js";
|
|
108
108
|
import "../chunk-YEFFHORB.js";
|
|
109
109
|
import "../chunk-S5SRJJQG.js";
|
|
110
110
|
import "../chunk-JML7WKWU.js";
|
package/dist/chat-store/index.js
CHANGED
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
mentionInputToPart,
|
|
20
20
|
mentionPartsFromMessageParts,
|
|
21
21
|
toChatMessageParts
|
|
22
|
-
} from "../chunk-
|
|
23
|
-
import "../chunk-ZVEEWGDK.js";
|
|
22
|
+
} from "../chunk-WUZZVQKR.js";
|
|
24
23
|
import "../chunk-KWXUBMXU.js";
|
|
24
|
+
import "../chunk-ZVEEWGDK.js";
|
|
25
25
|
import {
|
|
26
26
|
attachmentPartKey
|
|
27
27
|
} from "../chunk-5EPIPT4V.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authenticateToolRequest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YOFQO4R6.js";
|
|
4
4
|
import {
|
|
5
5
|
ToolInputError,
|
|
6
6
|
findCustomTool,
|
|
@@ -198,4 +198,4 @@ export {
|
|
|
198
198
|
createAppToolRuntimeExecutor,
|
|
199
199
|
handleAppToolRequest
|
|
200
200
|
};
|
|
201
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-C5OIABSB.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-YTMKRL3L.js";
|
|
13
13
|
import {
|
|
14
14
|
attachmentPartsFromMessageParts
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-WUZZVQKR.js";
|
|
16
16
|
import {
|
|
17
17
|
formatBytes
|
|
18
18
|
} from "./chunk-KWXUBMXU.js";
|
|
@@ -4309,4 +4309,4 @@ export {
|
|
|
4309
4309
|
useThinkingSeconds,
|
|
4310
4310
|
ChatMessages
|
|
4311
4311
|
};
|
|
4312
|
-
//# sourceMappingURL=chunk-
|
|
4312
|
+
//# sourceMappingURL=chunk-CKUZVDZ7.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertHarnessModelCompatible
|
|
3
|
+
} from "./chunk-73F3CKVK.js";
|
|
1
4
|
import {
|
|
2
5
|
assertProfilePromptWithinBudget,
|
|
3
6
|
fingerprintAgentProfile
|
|
4
7
|
} from "./chunk-LWSJK546.js";
|
|
5
|
-
import {
|
|
6
|
-
assertHarnessModelCompatible
|
|
7
|
-
} from "./chunk-73F3CKVK.js";
|
|
8
8
|
import {
|
|
9
9
|
buildAppToolMcpServer
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-YOFQO4R6.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveTangleExecutionEnvironment,
|
|
13
13
|
trimOrNull
|
|
@@ -2224,4 +2224,4 @@ export {
|
|
|
2224
2224
|
isTerminalPromptEvent,
|
|
2225
2225
|
detectInteractiveQuestion
|
|
2226
2226
|
};
|
|
2227
|
-
//# sourceMappingURL=chunk-
|
|
2227
|
+
//# sourceMappingURL=chunk-EPOPI77J.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
persistedPartToWorkProduct
|
|
3
|
-
} from "./chunk-ZVEEWGDK.js";
|
|
4
1
|
import {
|
|
5
2
|
mentionKindForPath
|
|
6
3
|
} from "./chunk-KWXUBMXU.js";
|
|
4
|
+
import {
|
|
5
|
+
persistedPartToWorkProduct
|
|
6
|
+
} from "./chunk-ZVEEWGDK.js";
|
|
7
7
|
import {
|
|
8
8
|
persistedPartToInteraction
|
|
9
9
|
} from "./chunk-3ZK5IJSW.js";
|
|
@@ -155,4 +155,4 @@ export {
|
|
|
155
155
|
buildAttachmentPromptBlock,
|
|
156
156
|
historyContentWithAttachments
|
|
157
157
|
};
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
158
|
+
//# sourceMappingURL=chunk-WUZZVQKR.js.map
|
|
@@ -13,7 +13,11 @@ async function authenticateToolRequest(request, opts) {
|
|
|
13
13
|
if (!userId || !bearer) {
|
|
14
14
|
return { ok: false, response: Response.json({ error: "Missing capability credentials" }, { status: 401 }) };
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
const subject = opts.subject === "workspaceId" ? workspaceId : userId;
|
|
17
|
+
if (!subject) {
|
|
18
|
+
return { ok: false, response: Response.json({ error: "Missing workspace context" }, { status: 400 }) };
|
|
19
|
+
}
|
|
20
|
+
if (!await opts.verifyToken(subject, bearer)) {
|
|
17
21
|
return { ok: false, response: Response.json({ error: "Invalid capability token" }, { status: 401 }) };
|
|
18
22
|
}
|
|
19
23
|
if (!workspaceId) {
|
|
@@ -268,4 +272,4 @@ export {
|
|
|
268
272
|
MCP_PROTOCOL_VERSIONS,
|
|
269
273
|
createMcpToolHandler
|
|
270
274
|
};
|
|
271
|
-
//# sourceMappingURL=chunk-
|
|
275
|
+
//# sourceMappingURL=chunk-YOFQO4R6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/auth.ts","../src/tools/mcp.ts","../src/tools/mcp-rpc.ts"],"sourcesContent":["import type { AppToolContext } from './types'\n\n/**\n * Header names carrying the server-set per-turn context + the capability token.\n * Defaults are product-neutral (`X-Agent-App-*`); a product that already ships\n * a header convention (e.g. `X-Acme-User-Id`) passes its own.\n */\nexport interface ToolHeaderNames {\n userId: string\n workspaceId: string\n threadId: string\n}\n\n/** Provide default HTTP header names for user, workspace, and thread identification */\nexport const DEFAULT_HEADER_NAMES: ToolHeaderNames = {\n userId: 'X-Agent-App-User-Id',\n workspaceId: 'X-Agent-App-Workspace-Id',\n threadId: 'X-Agent-App-Thread-Id',\n}\n\n/**\n * Which identity the bearer is bound to.\n *\n * `'userId'` (default) is right when the product mints a token per user and can\n * deliver it per turn.\n *\n * `'workspaceId'` is the only workable choice when the token has to survive in\n * the BOX ENVIRONMENT. Since agent-interface 0.38 a credential may reach a\n * profile only as a reference the sandbox resolves from that environment, and\n * the environment is workspace-wide and written once at box creation. A\n * per-user token therefore cannot be delivered at all — and a per-user token\n * that IS written there was never per-user in any meaningful sense, because\n * every member of that workspace's box can read it.\n *\n * Binding the bearer to the workspace does NOT collapse the identity: the user\n * header is still required, still server-set, still returned on `ctx`, and is\n * what downstream domain code attributes work to. Only the question \"may this\n * caller act at all\" moves from the user to the workspace — which is what the\n * shared box already implies.\n */\nexport type CapabilitySubject = 'userId' | 'workspaceId'\n\n/** Define options to verify bearer tokens and customize authentication header names */\nexport interface AuthenticateOptions {\n /** Verify the bearer capability token belongs to the subject named by\n * {@link AuthenticateOptions.subject}. The product's HMAC/JWT impl — the\n * seam that keeps token crypto out of this package. */\n verifyToken: (subject: string, bearer: string) => Promise<boolean>\n headerNames?: ToolHeaderNames\n /** What the bearer is bound to. Defaults to `'userId'`, so an existing caller\n * is byte-unchanged. */\n subject?: CapabilitySubject\n}\n\n/** Represent the result of tool authentication with success context or failure response */\nexport type ToolAuthResult =\n | { ok: true; ctx: AppToolContext }\n | { ok: false; response: Response }\n\n/**\n * Recover + verify the trusted context for a tool request.\n *\n * Both the user and the workspace come from server-set headers — never from\n * tool args — so the model can neither forge identity nor target another\n * workspace. The bearer must verify against whichever of the two the product\n * declares as its {@link CapabilitySubject}.\n *\n * Fail-closed, and deliberately in this order: a missing credential or a token\n * minted for another subject yields 401 before anything else is read. When the\n * subject is the workspace, its header is required BEFORE verification rather\n * than after — verifying against an absent subject is not a check at all.\n */\nexport async function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult> {\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n const userId = request.headers.get(h.userId)?.trim()\n const workspaceId = request.headers.get(h.workspaceId)?.trim()\n const threadId = request.headers.get(h.threadId)?.trim() || null\n const bearer = request.headers.get('authorization')?.match(/^Bearer\\s+(.+)$/i)?.[1]\n\n if (!userId || !bearer) {\n return { ok: false, response: Response.json({ error: 'Missing capability credentials' }, { status: 401 }) }\n }\n const subject = opts.subject === 'workspaceId' ? workspaceId : userId\n if (!subject) {\n return { ok: false, response: Response.json({ error: 'Missing workspace context' }, { status: 400 }) }\n }\n if (!(await opts.verifyToken(subject, bearer))) {\n return { ok: false, response: Response.json({ error: 'Invalid capability token' }, { status: 401 }) }\n }\n if (!workspaceId) {\n return { ok: false, response: Response.json({ error: 'Missing workspace context' }, { status: 400 }) }\n }\n return { ok: true, ctx: { userId, workspaceId, threadId } }\n}\n\n/** Read a tool's argument object from the request body, tolerant of MCP host\n * aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */\nexport async function readToolArgs<T>(request: Request): Promise<T | null> {\n let body: { args?: T; arguments?: T }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return null\n }\n return (body.args ?? body.arguments ?? (body as T)) as T\n}\n","/**\n * The tagged-configuration contract for every MCP server this package emits.\n *\n * An `AgentProfile` is digested, diffed, stored, and logged, so a credential\n * that rides it as plain text is a leak by construction. `@tangle-network/\n * agent-interface` closed that at **0.38.0**: `args`, `env`, and `headers` on\n * an `AgentProfileMcpServer` no longer take strings. Every value is either\n * deliberately public profile material (`defineAgentProfilePublicConfig`) or an\n * opaque reference to a credential (`defineAgentProfileSecretRef`) resolved\n * privately at materialization, validated by a `z.discriminatedUnion('kind')`.\n *\n * The schema also refuses to let a secret hide as public material: a `public`\n * value under a credential-bearing key name (`Authorization`, `*_TOKEN`,\n * `*_API_KEY`, `*_SECRET`, `Cookie`, …) is rejected with \"credential-bearing\n * config names require a secret-ref\", and any value whose bytes look like a\n * credential (`Bearer …`, `sk-…`, `ghp_…`) is rejected outright. So the\n * capability token this package used to inline as `Bearer <token>` cannot be\n * expressed at all — it must become a reference.\n *\n * **A reference resolves ONLY from an environment variable present on the box,\n * named by `key`.** That is why the builders below take a `tokenEnvKey` (the\n * box-env variable NAME) instead of a token VALUE: agent-app cannot guess the\n * name, and a reference to a key nothing places fails the turn at\n * materialization rather than running credential-less. The box env is what\n * `SandboxRuntimeConfig.env` (and the platform secret store via\n * `SandboxRuntimeConfig.secrets`) writes at sandbox creation, so the key must\n * name a variable one of those places — and it must therefore be a real\n * environment-variable name, which this module enforces.\n *\n * A per-request credential is only referenceable when the value written at box\n * creation is byte-identical to the one every later turn would mint (a\n * deterministic derivation such as an HMAC over the workspace id). A token\n * scoped narrower than the box — per-user, per-document — cannot be referenced\n * at all; {@link unresolvableSurfaceCredential} names that blocker instead of\n * emitting a reference that resolves to nothing.\n */\nimport {\n agentProfileMcpServerSchema,\n defineAgentProfilePublicConfig,\n defineAgentProfileSecretRef,\n type AgentProfileConfigValue,\n} from '@tangle-network/agent-interface'\nimport type { AppToolContext } from './types'\nimport type { AppToolName } from './openai'\nimport type { AppToolDefinition } from './registry'\nimport type { ToolHeaderNames } from './auth'\nimport { DEFAULT_HEADER_NAMES } from './auth'\n\n/** Default route path each app tool is served at. A product mounts its routes\n * at these paths (or supplies its own via {@link BuildMcpServerOptions.paths}). */\nexport const DEFAULT_APP_TOOL_PATHS: Record<AppToolName, string> = {\n submit_proposal: '/api/tools/propose',\n schedule_followup: '/api/tools/followup',\n render_ui: '/api/tools/render-ui',\n add_citation: '/api/tools/citation',\n}\n\n/** The portable MCP server entry the sandbox SDK accepts (transport + url +\n * tagged headers). Assignable to `AgentProfileMcpServer` without a cast —\n * products spread it into their profile's `mcp` map. */\nexport interface AppToolMcpServer {\n transport: 'http'\n url: string\n headers: Record<string, AgentProfileConfigValue>\n enabled: true\n metadata: { description: string }\n}\n\n/** POSIX environment-variable name — the same shape `agent-interface`'s\n * `environmentNameSchema` accepts for an env key. A secret reference resolves\n * from the box environment, so a key outside this shape can never resolve. */\nconst ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/**\n * Reject a secret-reference key that names nothing the box can hold.\n *\n * `agent-interface` accepts any non-credential string as a reference key, so a\n * typo or a token VALUE passed where a key belongs validates against the\n * profile schema and fails much later, inside materialization, as an opaque\n * missing-secret error. Failing here names the parameter.\n */\nfunction assertSecretEnvKey(key: string, label: string): string {\n if (!ENV_NAME_PATTERN.test(key)) {\n throw new Error(\n `${label}: tokenEnvKey must be an environment-variable NAME the sandbox box carries ` +\n `(e.g. 'APP_CAPABILITY_TOKEN'), not a token value — got ${JSON.stringify(key)}. ` +\n 'A profile may only REFERENCE a credential; the value is placed on the box by ' +\n 'SandboxRuntimeConfig.env or the platform secret store.',\n )\n }\n return key\n}\n\n/**\n * Validate one emitted entry against the REAL `agentProfileMcpServerSchema`.\n *\n * The contract's rules (which key names demand a reference, which byte patterns\n * read as a credential) live in `agent-interface`. Re-implementing them here\n * would drift the moment that package moves — which it does: 0.36.0 → 0.40.0 in\n * three days. Running the shipped validator instead means a product that passes\n * a credential-bearing custom header name, a relative base URL, or a URL with\n * embedded credentials fails at the builder with the contract's own message.\n *\n * It is also the loud failure for a version skew: if the resolved\n * `@tangle-network/agent-interface` predates 0.38.0, its schema rejects the\n * tagged shape this package now emits, and that surfaces here instead of as a\n * sandbox provisioning error.\n */\nfunction assertProfileMcpServer<T extends AppToolMcpServer>(server: T, label: string): T {\n const result = agentProfileMcpServerSchema.safeParse(server)\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)\n .join('; ')\n throw new Error(\n `${label} produced an MCP server the AgentProfile contract rejects: ${issues}. ` +\n 'Requires @tangle-network/agent-interface >= 0.38.0 (tagged MCP config values).',\n )\n }\n return server\n}\n\n/**\n * Refuse to mount a surface whose credential is scoped narrower than the box.\n *\n * A per-user or per-resource capability token is minted per request. The box\n * environment is written once at sandbox creation and shared by every turn and\n * every member of the workspace, so such a token can neither be placed there\n * ahead of time nor referenced from a per-turn profile. Widening the channel to\n * a workspace-bound token is not a substitute when the route authenticates the\n * CALLER: the agent can read its own box env, so it could forge that identity.\n *\n * Mounting the surface anyway would emit a plain-string `Authorization` header\n * (rejected by the schema) or a reference to a key nothing places (rejected at\n * materialization). Throwing here names the actual blocker. Exported because\n * every product with per-document MCP surfaces hits it and was writing this\n * message itself.\n */\nexport function unresolvableSurfaceCredential(surface: string): never {\n throw new Error(\n `The ${surface} MCP surface cannot be mounted: its capability token is scoped to a single ` +\n 'user and resource, and an AgentProfile may only reference a credential the sandbox can ' +\n 'resolve from the box environment, which is workspace-wide and fixed at sandbox creation. ' +\n 'Mounting it needs a per-session secret channel on the sandbox API, or a route that ' +\n 'authenticates the workspace rather than the caller.',\n )\n}\n\n/** Define configuration options for building an HTTP MCP server including path, baseUrl, token env key, context, and description */\nexport interface BuildHttpMcpServerOptions {\n /** Route path on the app the sandbox POSTs to (e.g. `/api/tools/propose`). */\n path: string\n /** App base URL the sandbox reaches back to (no trailing slash required). */\n baseUrl: string\n /**\n * NAME of the box-environment variable holding the capability token — never\n * the token itself. The emitted `Authorization` header is a `secret-ref` to\n * this key with `format: 'bearer'`, so the sandbox resolves the value\n * privately and the profile carries only the name.\n *\n * The key MUST name a variable the box actually carries (placed by\n * `SandboxRuntimeConfig.env` at creation, or injected from the platform\n * secret store via `SandboxRuntimeConfig.secrets`), and the value written\n * there must be the token this route will accept for every turn — which in\n * practice means a deterministic derivation (e.g. an HMAC over the workspace\n * id), not a freshly-random per-request mint. A token scoped narrower than\n * the box is not referenceable: see {@link unresolvableSurfaceCredential}.\n */\n tokenEnvKey: string\n ctx: AppToolContext\n /** Tool description the model sees. */\n description: string\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build ONE HTTP MCP server entry — the generic agent→app bridge. The\n * capability token (as a secret reference) + the user/workspace/thread ids ride\n * in server-set headers (never tool args), so the model can't forge identity or\n * target another workspace. Workspace/thread headers are omitted when their\n * `ctx` value is empty/null (e.g. an integration-invoke bridge that's\n * user-scoped only). Used directly for non-app-tool bridges\n * (integration_invoke) and via {@link buildAppToolMcpServer} for the four app\n * tools.\n */\nexport function buildHttpMcpServer(opts: BuildHttpMcpServerOptions): AppToolMcpServer {\n const base = opts.baseUrl.replace(/\\/+$/, '')\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n return assertProfileMcpServer(\n {\n transport: 'http',\n url: `${base}${opts.path}`,\n headers: {\n Authorization: defineAgentProfileSecretRef(\n assertSecretEnvKey(opts.tokenEnvKey, 'buildHttpMcpServer'),\n 'bearer',\n ),\n [h.userId]: defineAgentProfilePublicConfig(opts.ctx.userId),\n ...(opts.ctx.workspaceId\n ? { [h.workspaceId]: defineAgentProfilePublicConfig(opts.ctx.workspaceId) }\n : {}),\n ...(opts.ctx.threadId\n ? { [h.threadId]: defineAgentProfilePublicConfig(opts.ctx.threadId) }\n : {}),\n 'Content-Type': defineAgentProfilePublicConfig('application/json'),\n },\n enabled: true,\n metadata: { description: opts.description },\n },\n 'buildHttpMcpServer',\n )\n}\n\n/** Options for a per-document/scoped MCP channel entry (design-canvas,\n * sequences, …). The capability token + path scope ONE resource; the document\n * id lives in the path, never a tool argument. */\nexport interface ScopedMcpServerEntryOptions {\n /** App base URL the sandbox reaches back to (trailing slash tolerated). */\n baseUrl: string\n /** Product route serving the resource's MCP handler — id is part of the path. */\n path: string\n /**\n * NAME of the box-environment variable holding this channel's capability\n * token — never the token itself. See\n * {@link BuildHttpMcpServerOptions.tokenEnvKey}.\n *\n * A per-(user, resource) token cannot satisfy this: the box environment is\n * workspace-wide and fixed at sandbox creation. A product whose channel needs\n * one calls {@link unresolvableSurfaceCredential} rather than mounting an\n * entry that cannot resolve.\n */\n tokenEnvKey: string\n /** Override the channel's default tool-server description. */\n description?: string\n /** Identity headers for products whose route recovers the user via\n * `authenticateToolRequest`. Omit when the bearer token is self-contained. */\n ctx?: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build the `AgentProfileMcpServer`-shaped entry for a scoped, per-resource MCP\n * channel. The shared mechanism behind the per-domain entry builders\n * (`buildDesignCanvasMcpServerEntry`, `buildSequencesMcpServerEntry`): same\n * token/path guards, same description default, same ctx-vs-self-contained-token\n * branching. The domain is two parameters — `label` (for guard messages) and\n * `defaultDescription` — never baked.\n *\n * The no-`ctx` branch is a GENUINE behavioral path, not a shortcut: it emits a\n * self-contained-token entry with ONLY `Authorization` + `Content-Type`.\n * Routing it through {@link buildHttpMcpServer} would unconditionally write a\n * `userId` identity header (here `undefined`), so it stays a distinct branch.\n */\nexport function buildScopedMcpServerEntry(\n opts: ScopedMcpServerEntryOptions & { label: string; defaultDescription: string },\n): AppToolMcpServer {\n if (opts.tokenEnvKey.trim().length === 0) {\n throw new Error(`${opts.label} requires a capability token env key — omit the MCP server when none is available`)\n }\n if (!opts.path.startsWith('/')) {\n throw new Error(`${opts.label} path must start with \"/\" (got \"${opts.path}\")`)\n }\n const description = opts.description ?? opts.defaultDescription\n\n if (opts.ctx) {\n return buildHttpMcpServer({\n path: opts.path,\n baseUrl: opts.baseUrl,\n tokenEnvKey: opts.tokenEnvKey,\n ctx: opts.ctx,\n description,\n headerNames: opts.headerNames ?? DEFAULT_HEADER_NAMES,\n })\n }\n\n return assertProfileMcpServer(\n {\n transport: 'http',\n url: `${opts.baseUrl.replace(/\\/+$/, '')}${opts.path}`,\n headers: {\n Authorization: defineAgentProfileSecretRef(\n assertSecretEnvKey(opts.tokenEnvKey, opts.label),\n 'bearer',\n ),\n 'Content-Type': defineAgentProfilePublicConfig('application/json'),\n },\n enabled: true,\n metadata: { description },\n },\n opts.label,\n )\n}\n\n/** Define configuration options required to build an MCP server including tool, baseUrl, token, and context */\nexport interface BuildMcpServerOptions {\n /** A built-in app tool name, or a product-registered {@link AppToolDefinition}.\n * A custom tool supplies its route via `AppToolDefinition.path` (or `paths`). */\n tool: AppToolName | AppToolDefinition\n baseUrl: string\n /** NAME of the box-environment variable holding the capability token — see\n * {@link BuildHttpMcpServerOptions.tokenEnvKey}. */\n tokenEnvKey: string\n ctx: AppToolContext\n description: string\n headerNames?: ToolHeaderNames\n paths?: Partial<Record<string, string>>\n}\n\n/** Build one app-tool MCP server entry — a thin wrapper over\n * {@link buildHttpMcpServer} that resolves the tool's route path. Built-ins map\n * through {@link DEFAULT_APP_TOOL_PATHS}; a custom tool uses its own `path`\n * (or a `paths` override). */\nexport function buildAppToolMcpServer(opts: BuildMcpServerOptions): AppToolMcpServer {\n const path =\n typeof opts.tool === 'string'\n ? opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool]\n : opts.paths?.[opts.tool.name] ?? opts.tool.path\n if (!path) {\n const name = typeof opts.tool === 'string' ? opts.tool : opts.tool.name\n throw new Error(`buildAppToolMcpServer: tool \"${name}\" has no route path — set AppToolDefinition.path or pass it via opts.paths`)\n }\n return buildHttpMcpServer({\n path,\n baseUrl: opts.baseUrl,\n tokenEnvKey: opts.tokenEnvKey,\n ctx: opts.ctx,\n description: opts.description,\n headerNames: opts.headerNames,\n })\n}\n","/**\n * Generic streamable-HTTP JSON-RPC 2.0 envelope for a tools-only MCP server.\n * Stateless, Workers-compatible: no session table, no SSE — every request gets\n * a single `application/json` response, which the streamable-HTTP transport\n * explicitly permits for tools-only servers.\n *\n * Protocol surface:\n * initialize → echo client's protocolVersion if supported, else latest\n * ping → empty result {}\n * notifications/* (no `id`) → 202 with no body\n * tools/list → tool manifest\n * tools/call → run + surface execution failures as isError text results\n * anything else → -32601\n *\n * Execution failures (argument shape, validation, store throws) become `isError`\n * tool results carrying the thrown message verbatim — the model reads WHY and\n * retries. Protocol misuse becomes a JSON-RPC error object.\n */\n\nexport const MCP_PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'] as const\n/** Resolve a valid protocol version from the predefined MCP_PROTOCOL_VERSIONS array */\nexport type McpProtocolVersion = (typeof MCP_PROTOCOL_VERSIONS)[number]\n\nconst LATEST_PROTOCOL_VERSION: McpProtocolVersion = MCP_PROTOCOL_VERSIONS[0]\n\n/** Describe the structure of server information including name and version */\nexport interface McpServerInfo {\n name: string\n version: string\n}\n\n/** One tool entry in the registry the handler owns. */\nexport interface McpToolDefinition<TEnv = Record<string, never>> {\n name: string\n description: string\n /** JSON Schema for the `params.arguments` object. */\n inputSchema: Record<string, unknown>\n /** Receive validated (Record) args + the env the handler threaded; throw to\n * surface an isError result — never throw for protocol/framing issues. */\n run(args: Record<string, unknown>, env: TEnv): Promise<unknown>\n}\n\n/** Define options for creating a handler that manages MCP tools with environment support */\nexport interface CreateMcpToolHandlerOptions<TEnv = Record<string, never>> {\n serverInfo: McpServerInfo\n /** Full tool list; order IS the tools/list order. */\n tools: McpToolDefinition<TEnv>[]\n /** Per-request environment threaded into every `run` call. If your tools are\n * stateless (or carry state through closure) pass an empty builder:\n * `() => ({} as TEnv)`. */\n buildEnv(request: Request): TEnv | Promise<TEnv>\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype JsonRpcId = string | number | null\n\ninterface ToolCallContent {\n content: Array<{ type: 'text'; text: string }>\n isError?: true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction rpcResult(id: JsonRpcId, result: unknown): Response {\n return Response.json({ jsonrpc: '2.0', id, result })\n}\n\nfunction rpcError(id: JsonRpcId, code: number, message: string, status = 200): Response {\n return Response.json({ jsonrpc: '2.0', id, error: { code, message } }, { status })\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Build a request handler for a tools-only MCP server. The returned function\n * accepts a standard `Request` and resolves to a `Response` — mount it on any\n * Cloudflare Worker route or Remix `loader`.\n *\n * The handler calls `buildEnv` exactly ONCE per `tools/call` request (after\n * the tool is found, before `run`) — non-`tools/call` paths skip it entirely\n * so metadata requests do not pay env-build cost.\n */\nexport function createMcpToolHandler<TEnv = Record<string, never>>(\n opts: CreateMcpToolHandlerOptions<TEnv>,\n): (request: Request) => Promise<Response> {\n const toolMap = new Map<string, McpToolDefinition<TEnv>>()\n for (const tool of opts.tools) {\n if (toolMap.has(tool.name)) throw new Error(`duplicate MCP tool name: ${tool.name}`)\n toolMap.set(tool.name, tool)\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') {\n return new Response('MCP server accepts JSON-RPC 2.0 over POST only', {\n status: 405,\n headers: { Allow: 'POST' },\n })\n }\n\n let body: unknown\n try {\n body = await request.json()\n } catch {\n return rpcError(null, -32700, 'Parse error: request body is not valid JSON', 400)\n }\n\n if (Array.isArray(body)) {\n return rpcError(null, -32600, 'Invalid request: JSON-RPC batching is not supported', 400)\n }\n if (!isRecord(body) || body.jsonrpc !== '2.0' || typeof body.method !== 'string') {\n return rpcError(\n null,\n -32600,\n 'Invalid request: expected a JSON-RPC 2.0 object with jsonrpc \"2.0\" and a string method',\n 400,\n )\n }\n\n const method = body.method\n const params = isRecord(body.params) ? body.params : {}\n\n // Notifications have no `id` — acknowledge without a JSON-RPC body.\n if (!('id' in body) || body.id === undefined) {\n return new Response(null, { status: 202 })\n }\n const id = body.id as JsonRpcId\n\n switch (method) {\n case 'initialize': {\n const requested = typeof params.protocolVersion === 'string' ? params.protocolVersion : undefined\n const protocolVersion =\n requested !== undefined && (MCP_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION\n return rpcResult(id, {\n protocolVersion,\n capabilities: { tools: { listChanged: false } },\n serverInfo: opts.serverInfo,\n })\n }\n\n case 'ping':\n return rpcResult(id, {})\n\n case 'tools/list':\n return rpcResult(id, {\n tools: opts.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n })\n\n case 'tools/call': {\n const name = params.name\n if (typeof name !== 'string' || name.length === 0) {\n return rpcError(id, -32602, 'tools/call requires params.name (string)')\n }\n const tool = toolMap.get(name)\n if (!tool) {\n return rpcError(\n id,\n -32602,\n `Unknown tool: ${name}. Available tools: ${opts.tools.map((t) => t.name).join(', ')}`,\n )\n }\n if (params.arguments !== undefined && !isRecord(params.arguments)) {\n return rpcError(id, -32602, 'tools/call params.arguments must be an object when provided')\n }\n const args = isRecord(params.arguments) ? params.arguments : {}\n let env: TEnv\n try {\n env = await opts.buildEnv(request)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed to build env: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n try {\n const result = await tool.run(args, env)\n const payload: ToolCallContent = { content: [{ type: 'text', text: JSON.stringify(result) }] }\n return rpcResult(id, payload)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n }\n\n default:\n return rpcError(id, -32601, `Method not found: ${method}`)\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/peer-floors/check.ts
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
function readInstalledManifest(name, fromDir, modulesDir) {
|
|
5
|
+
let dir = fromDir;
|
|
6
|
+
for (; ; ) {
|
|
7
|
+
const manifest = join(dir, modulesDir, name, "package.json");
|
|
8
|
+
if (existsSync(manifest)) {
|
|
9
|
+
return JSON.parse(readFileSync(manifest, "utf8"));
|
|
10
|
+
}
|
|
11
|
+
const parent = dirname(dir);
|
|
12
|
+
if (parent === dir) return null;
|
|
13
|
+
dir = parent;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function parseVersion(version) {
|
|
17
|
+
const [core] = version.split(/[-+]/);
|
|
18
|
+
const parts = (core ?? "").split(".").map((p) => Number.parseInt(p, 10));
|
|
19
|
+
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
20
|
+
}
|
|
21
|
+
function compare(a, b) {
|
|
22
|
+
const va = parseVersion(a);
|
|
23
|
+
const vb = parseVersion(b);
|
|
24
|
+
for (let i = 0; i < 3; i += 1) {
|
|
25
|
+
if (va[i] !== vb[i]) return va[i] < vb[i] ? -1 : 1;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
function satisfiesComparator(version, comparator) {
|
|
30
|
+
const trimmed = comparator.trim();
|
|
31
|
+
if (!trimmed || trimmed === "*" || trimmed === "x") return true;
|
|
32
|
+
const match = /^(>=|<=|>|<|=|\^|~)?\s*v?(.+)$/.exec(trimmed);
|
|
33
|
+
if (!match) return false;
|
|
34
|
+
const [, op = "=", target = ""] = match;
|
|
35
|
+
const cmp = compare(version, target);
|
|
36
|
+
switch (op) {
|
|
37
|
+
case ">=":
|
|
38
|
+
return cmp >= 0;
|
|
39
|
+
case "<=":
|
|
40
|
+
return cmp <= 0;
|
|
41
|
+
case ">":
|
|
42
|
+
return cmp > 0;
|
|
43
|
+
case "<":
|
|
44
|
+
return cmp < 0;
|
|
45
|
+
case "=":
|
|
46
|
+
return cmp === 0;
|
|
47
|
+
case "~": {
|
|
48
|
+
const [major, minor] = parseVersion(target);
|
|
49
|
+
const [vMajor, vMinor] = parseVersion(version);
|
|
50
|
+
return cmp >= 0 && vMajor === major && vMinor === minor;
|
|
51
|
+
}
|
|
52
|
+
case "^": {
|
|
53
|
+
const [major, minor] = parseVersion(target);
|
|
54
|
+
const [vMajor, vMinor] = parseVersion(version);
|
|
55
|
+
if (cmp < 0) return false;
|
|
56
|
+
if (major > 0) return vMajor === major;
|
|
57
|
+
if (minor > 0) return vMajor === 0 && vMinor === minor;
|
|
58
|
+
return vMajor === 0 && vMinor === 0;
|
|
59
|
+
}
|
|
60
|
+
default:
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function satisfiesRange(version, range) {
|
|
65
|
+
return range.split("||").some(
|
|
66
|
+
(alternative) => alternative.trim().split(/\s+/).filter(Boolean).every((c) => satisfiesComparator(version, c))
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function checkPeerFloors(options) {
|
|
70
|
+
const {
|
|
71
|
+
appDir,
|
|
72
|
+
shell = "@tangle-network/agent-app",
|
|
73
|
+
scope = "@tangle-network/",
|
|
74
|
+
modulesDir = "node_modules"
|
|
75
|
+
} = options;
|
|
76
|
+
const shellManifest = options.shellManifest ?? readInstalledManifest(shell, appDir, modulesDir);
|
|
77
|
+
if (!shellManifest) throw new Error(`${shell} is not installed under ${appDir}`);
|
|
78
|
+
const appManifest = JSON.parse(readFileSync(join(appDir, "package.json"), "utf8"));
|
|
79
|
+
const declared = {
|
|
80
|
+
...appManifest.dependencies,
|
|
81
|
+
...appManifest.devDependencies,
|
|
82
|
+
...appManifest.optionalDependencies
|
|
83
|
+
};
|
|
84
|
+
const floors = Object.entries(shellManifest.peerDependencies ?? {}).filter(([name]) => name.startsWith(scope));
|
|
85
|
+
const rows = floors.map(([name, range]) => {
|
|
86
|
+
const installed = readInstalledManifest(name, appDir, modulesDir)?.version ?? null;
|
|
87
|
+
if (installed === null) {
|
|
88
|
+
return { name, range, installed, verdict: declared[name] ? "absent-but-declared" : "absent-unused" };
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
name,
|
|
92
|
+
range,
|
|
93
|
+
installed,
|
|
94
|
+
verdict: satisfiesRange(installed, range) ? "satisfied" : "below-floor"
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
const violations = rows.filter((row) => row.verdict === "below-floor" || row.verdict === "absent-but-declared");
|
|
98
|
+
return {
|
|
99
|
+
shellVersion: shellManifest.version ?? "unknown",
|
|
100
|
+
rows,
|
|
101
|
+
violations,
|
|
102
|
+
ok: violations.length === 0
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function describePeerFloorViolation(row, shellVersion, shell = "@tangle-network/agent-app") {
|
|
106
|
+
if (row.verdict === "below-floor") {
|
|
107
|
+
return `PEER FLOOR VIOLATED: ${shell}@${shellVersion} requires ${row.name}@${row.range}, but ${row.installed} is installed. A peer floor encodes a wire contract \u2014 bump the dependency, do not widen the floor. A caret on a 0.x version is minor-locked (^0.36.0 can never resolve to 0.38.0), so reinstalling alone will not fix this: change the pin, in EVERY place it appears including pnpm.overrides.`;
|
|
108
|
+
}
|
|
109
|
+
return `${row.name} is a declared dependency of this app, but no installed version could be read, so its peer floor ${row.range} went UNCHECKED. Failing loudly rather than reporting a pass this guard did not earn.`;
|
|
110
|
+
}
|
|
111
|
+
function formatPeerFloorReport(report, shell = "@tangle-network/agent-app") {
|
|
112
|
+
const width = Math.max(...report.rows.map((r) => r.name.length), 4);
|
|
113
|
+
const lines = [
|
|
114
|
+
`${shell}@${report.shellVersion} \u2014 peer floors`,
|
|
115
|
+
"",
|
|
116
|
+
...report.rows.map((row) => ` ${row.verdict === "satisfied" ? "ok " : row.verdict.startsWith("absent") ? "-- " : "FAIL"} ${row.name.padEnd(width)} installed ${(row.installed ?? "(none)").padEnd(10)} floor ${row.range}`),
|
|
117
|
+
"",
|
|
118
|
+
report.ok ? `all ${report.rows.length} floors satisfied` : report.violations.map((row) => describePeerFloorViolation(row, report.shellVersion, shell)).join("\n\n")
|
|
119
|
+
];
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export {
|
|
124
|
+
satisfiesRange,
|
|
125
|
+
checkPeerFloors,
|
|
126
|
+
describePeerFloorViolation,
|
|
127
|
+
formatPeerFloorReport
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=chunk-ZSJRDHCN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/peer-floors/check.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\n/**\n * Audit a consumer's installed tree against the peer floors this package\n * declares.\n *\n * A peer floor is not documentation — it encodes a WIRE CONTRACT, and breaking\n * one is invisible to every other gate. `pnpm` only WARNS on an unmet peer when\n * the package is also a direct dependency, and says nothing at all for an unmet\n * OPTIONAL peer, which is how most of the substrate is declared here. So a\n * product can sit below a floor with a clean install, a clean typecheck, a green\n * suite and a successful deploy, and fail only on a live wire call:\n *\n * `@tangle-network/sandbox` 0.15.0 → 0.15.1 changed the sidecar spawn body\n * from `{ command }` to `{ executable, args }`. Below the floor, every\n * `box.exec()` on a live sandbox returns 400 `Unrecognized key: \"command\"`.\n *\n * `@tangle-network/agent-interface` 0.38.0 changed MCP config values from\n * plain strings to tagged public/secret-ref objects. Below the floor, this\n * package fails at MODULE LOAD with \"does not provide an export named\n * defineAgentProfilePublicConfig\" — while `tsc` reports zero errors, because\n * the types resolve and only the runtime export is missing.\n *\n * That second shape is why this exists as its own gate: typecheck cannot see it,\n * and a suite only sees it as dozens of unrelated-looking import failures.\n */\n\n/** Installed, and inside the declared range. */\nexport type PeerFloorVerdict =\n | 'satisfied'\n /** Installed and BELOW the floor — the silent case this module exists for. */\n | 'below-floor'\n /** Not installed and never asked for. A legitimate answer for an optional peer. */\n | 'absent-unused'\n /** Declared by the app, yet no version could be read, so the floor went\n * UNCHECKED. Reported as a failure rather than a pass this did not earn. */\n | 'absent-but-declared'\n\nexport interface PeerFloorRow {\n readonly name: string\n readonly range: string\n readonly installed: string | null\n readonly verdict: PeerFloorVerdict\n}\n\nexport interface PeerFloorReport {\n readonly shellVersion: string\n readonly rows: readonly PeerFloorRow[]\n readonly violations: readonly PeerFloorRow[]\n readonly ok: boolean\n}\n\nexport interface CheckPeerFloorsOptions {\n /** Directory of the app under audit — the one whose `package.json` and\n * installed tree are read. */\n appDir: string\n /** Package whose peer floors are the contract. Defaults to this shell. */\n shell?: string\n /** Only audit peers under this scope. Third-party peers (react, drizzle) are\n * the app's own business, not part of the Tangle wire contract. Pass `''` to\n * audit every peer. */\n scope?: string\n /** Floors to audit against, when the shell is not resolvable from `appDir` —\n * the package auditing ITSELF, which has no copy of itself in its own\n * `node_modules`. Without this a package cannot check that the contract it\n * publishes is one its own dev install satisfies. */\n shellManifest?: { version?: string; peerDependencies?: Record<string, string> }\n /** Directory name to walk for installed packages. Overridable so a test can\n * point at a committed fixture tree — `node_modules` is gitignored\n * everywhere, so a fixture using that name could not be committed, and a\n * calibration proof that is not committed is a proof that stops running. */\n modulesDir?: string\n}\n\n/**\n * Read a package's manifest off disk, walking `modulesDir` up from `fromDir`.\n *\n * Deliberately NOT `require.resolve('<name>/package.json')`: most of these\n * packages omit `./package.json` from their `exports` map, so that throws\n * ERR_PACKAGE_PATH_NOT_EXPORTED — and a try/catch around it reports an INSTALLED\n * package as absent, turning the whole audit into a silent no-op. Walking the\n * tree is exports-map-independent and mirrors Node's own resolution order, so\n * the version reported is the version that would actually load.\n *\n * Returns null only when no directory for the package exists anywhere up the\n * tree, which is the genuine not-installed case.\n */\nfunction readInstalledManifest(\n name: string,\n fromDir: string,\n modulesDir: string,\n): { version?: string; peerDependencies?: Record<string, string> } | null {\n let dir = fromDir\n for (;;) {\n const manifest = join(dir, modulesDir, name, 'package.json')\n if (existsSync(manifest)) {\n return JSON.parse(readFileSync(manifest, 'utf8')) as {\n version?: string\n peerDependencies?: Record<string, string>\n }\n }\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\n/**\n * Minimal range satisfaction for the ranges peer floors actually use:\n * `>=x <y`, `^x.y.z`, `~x.y.z`, `x.y.z`, and `*`/`x`.\n *\n * Hand-rolled rather than taking a `semver` dependency, because this package\n * ships zero runtime dependencies and a checker that forces one on every\n * consumer is a worse trade than 40 lines of comparison. Prerelease versions\n * compare by their release part — a floor is about the wire contract, and a\n * prerelease of a satisfying version speaks it.\n */\nfunction parseVersion(version: string): [number, number, number] {\n const [core] = version.split(/[-+]/)\n const parts = (core ?? '').split('.').map((p) => Number.parseInt(p, 10))\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0]\n}\n\nfunction compare(a: string, b: string): number {\n const va = parseVersion(a)\n const vb = parseVersion(b)\n for (let i = 0; i < 3; i += 1) {\n if (va[i]! !== vb[i]!) return va[i]! < vb[i]! ? -1 : 1\n }\n return 0\n}\n\nfunction satisfiesComparator(version: string, comparator: string): boolean {\n const trimmed = comparator.trim()\n if (!trimmed || trimmed === '*' || trimmed === 'x') return true\n const match = /^(>=|<=|>|<|=|\\^|~)?\\s*v?(.+)$/.exec(trimmed)\n if (!match) return false\n const [, op = '=', target = ''] = match\n const cmp = compare(version, target)\n switch (op) {\n case '>=': return cmp >= 0\n case '<=': return cmp <= 0\n case '>': return cmp > 0\n case '<': return cmp < 0\n case '=': return cmp === 0\n case '~': {\n // ~1.2.3 allows patch bumps; ~1.2 allows minor.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n return cmp >= 0 && vMajor === major && vMinor === minor\n }\n case '^': {\n // A caret on a 0.x version is MINOR-locked: ^0.36.0 can never resolve to\n // 0.38.0. That is the single most common reason a floor cannot be met by\n // reinstalling, so it is modelled exactly rather than approximated.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n if (cmp < 0) return false\n if (major > 0) return vMajor === major\n if (minor > 0) return vMajor === 0 && vMinor === minor\n return vMajor === 0 && vMinor === 0\n }\n default: return false\n }\n}\n\nexport function satisfiesRange(version: string, range: string): boolean {\n // `||` is alternation; whitespace inside an alternative is conjunction.\n return range.split('||').some((alternative) =>\n alternative.trim().split(/\\s+/).filter(Boolean).every((c) => satisfiesComparator(version, c)),\n )\n}\n\n/** Audit one app directory against the shell's declared peer floors. */\nexport function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorReport {\n const {\n appDir,\n shell = '@tangle-network/agent-app',\n scope = '@tangle-network/',\n modulesDir = 'node_modules',\n } = options\n\n const shellManifest = options.shellManifest ?? readInstalledManifest(shell, appDir, modulesDir)\n if (!shellManifest) throw new Error(`${shell} is not installed under ${appDir}`)\n\n const appManifest = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf8')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n optionalDependencies?: Record<string, string>\n }\n const declared = {\n ...appManifest.dependencies,\n ...appManifest.devDependencies,\n ...appManifest.optionalDependencies,\n }\n\n const floors = Object.entries(shellManifest.peerDependencies ?? {})\n .filter(([name]) => name.startsWith(scope))\n\n const rows = floors.map(([name, range]): PeerFloorRow => {\n const installed = readInstalledManifest(name, appDir, modulesDir)?.version ?? null\n if (installed === null) {\n return { name, range, installed, verdict: declared[name] ? 'absent-but-declared' : 'absent-unused' }\n }\n return {\n name,\n range,\n installed,\n verdict: satisfiesRange(installed, range) ? 'satisfied' : 'below-floor',\n }\n })\n\n const violations = rows.filter((row) => row.verdict === 'below-floor' || row.verdict === 'absent-but-declared')\n return {\n shellVersion: shellManifest.version ?? 'unknown',\n rows,\n violations,\n ok: violations.length === 0,\n }\n}\n\n/** The failure message for one violating row. Split out so a caller can raise\n * it from a test and a CLI can print it identically. */\nexport function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell = '@tangle-network/agent-app'): string {\n if (row.verdict === 'below-floor') {\n return `PEER FLOOR VIOLATED: ${shell}@${shellVersion} requires ${row.name}@${row.range}, `\n + `but ${row.installed} is installed. A peer floor encodes a wire contract — bump the `\n + `dependency, do not widen the floor. A caret on a 0.x version is minor-locked `\n + `(^0.36.0 can never resolve to 0.38.0), so reinstalling alone will not fix this: `\n + `change the pin, in EVERY place it appears including pnpm.overrides.`\n }\n return `${row.name} is a declared dependency of this app, but no installed version could be `\n + `read, so its peer floor ${row.range} went UNCHECKED. Failing loudly rather than `\n + `reporting a pass this guard did not earn.`\n}\n\nexport function formatPeerFloorReport(report: PeerFloorReport, shell = '@tangle-network/agent-app'): string {\n const width = Math.max(...report.rows.map((r) => r.name.length), 4)\n const lines = [\n `${shell}@${report.shellVersion} — peer floors`,\n '',\n ...report.rows.map((row) =>\n ` ${row.verdict === 'satisfied' ? 'ok ' : row.verdict.startsWith('absent') ? '-- ' : 'FAIL'} `\n + `${row.name.padEnd(width)} installed ${(row.installed ?? '(none)').padEnd(10)} floor ${row.range}`),\n '',\n report.ok\n ? `all ${report.rows.length} floors satisfied`\n : report.violations.map((row) => describePeerFloorViolation(row, report.shellVersion, shell)).join('\\n\\n'),\n ]\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,10 +6,10 @@ import { a as SceneStore, N as NewSceneDecision, b as SceneDocumentRecord } from
|
|
|
6
6
|
export { c as SceneDecision, d as SceneExportFormat, e as SceneExportRecord, S as SceneStoreScope } from '../store-CqfDtnPQ.js';
|
|
7
7
|
export { C as CHANNEL_PRESETS, a as ChannelPreset, b as ChannelPresetId, c as ChannelScaleResult, E as EXPORT_PRESETS, d as ExportCropRect, e as ExportFormat, f as ExportPreset, S as SIZE_PRESETS, g as SizePreset, h as bleedAwareExportBounds, i as bleedAwareExportRect, j as findPreset, m as matchPreset, r as requireChannelPreset, s as scaleForPreset, k as scalePageForChannelPreset } from '../export-presets-mgVulRaV.js';
|
|
8
8
|
import { a as McpToolDefinition } from '../mcp-rpc-CzU5LWWT.js';
|
|
9
|
-
import { S as ScopedMcpServerEntryOptions, A as AppToolMcpServer } from '../mcp-
|
|
9
|
+
import { S as ScopedMcpServerEntryOptions, A as AppToolMcpServer } from '../mcp-C-jV_Xe9.js';
|
|
10
10
|
import '@tangle-network/agent-interface';
|
|
11
11
|
import '../types-DbU-oO5h.js';
|
|
12
|
-
import '../auth-
|
|
12
|
+
import '../auth-Bulnsz3V.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Pre-write validation for scene operations. Every rule runs against a
|
|
@@ -43,6 +43,10 @@ import {
|
|
|
43
43
|
selectTickStep
|
|
44
44
|
} from "../chunk-KPRBFNGT.js";
|
|
45
45
|
import "../chunk-TZO3SOUL.js";
|
|
46
|
+
import {
|
|
47
|
+
DesignCanvasChromeLazy,
|
|
48
|
+
DesignCanvasLazy
|
|
49
|
+
} from "../chunk-OO4DROKM.js";
|
|
46
50
|
import "../chunk-ZN5J47UX.js";
|
|
47
51
|
import {
|
|
48
52
|
DEFAULT_INSERT_TEMPLATES,
|
|
@@ -88,10 +92,6 @@ import {
|
|
|
88
92
|
bleedAwareExportBounds,
|
|
89
93
|
scaleForPreset
|
|
90
94
|
} from "../chunk-U4BXAZCN.js";
|
|
91
|
-
import {
|
|
92
|
-
DesignCanvasChromeLazy,
|
|
93
|
-
DesignCanvasLazy
|
|
94
|
-
} from "../chunk-DMYCGXBP.js";
|
|
95
95
|
import "../chunk-J25RST7G.js";
|
|
96
96
|
|
|
97
97
|
// src/design-canvas-react/components/CanvasInsertPanel.tsx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentProfileConfigValue } from '@tangle-network/agent-interface';
|
|
2
2
|
import { A as AppToolContext, a as AppToolName, b as AppToolDefinition } from './types-DbU-oO5h.js';
|
|
3
|
-
import { T as ToolHeaderNames } from './auth-
|
|
3
|
+
import { T as ToolHeaderNames } from './auth-Bulnsz3V.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The tagged-configuration contract for every MCP server this package emits.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit a consumer's installed tree against the peer floors this package
|
|
3
|
+
* declares.
|
|
4
|
+
*
|
|
5
|
+
* A peer floor is not documentation — it encodes a WIRE CONTRACT, and breaking
|
|
6
|
+
* one is invisible to every other gate. `pnpm` only WARNS on an unmet peer when
|
|
7
|
+
* the package is also a direct dependency, and says nothing at all for an unmet
|
|
8
|
+
* OPTIONAL peer, which is how most of the substrate is declared here. So a
|
|
9
|
+
* product can sit below a floor with a clean install, a clean typecheck, a green
|
|
10
|
+
* suite and a successful deploy, and fail only on a live wire call:
|
|
11
|
+
*
|
|
12
|
+
* `@tangle-network/sandbox` 0.15.0 → 0.15.1 changed the sidecar spawn body
|
|
13
|
+
* from `{ command }` to `{ executable, args }`. Below the floor, every
|
|
14
|
+
* `box.exec()` on a live sandbox returns 400 `Unrecognized key: "command"`.
|
|
15
|
+
*
|
|
16
|
+
* `@tangle-network/agent-interface` 0.38.0 changed MCP config values from
|
|
17
|
+
* plain strings to tagged public/secret-ref objects. Below the floor, this
|
|
18
|
+
* package fails at MODULE LOAD with "does not provide an export named
|
|
19
|
+
* defineAgentProfilePublicConfig" — while `tsc` reports zero errors, because
|
|
20
|
+
* the types resolve and only the runtime export is missing.
|
|
21
|
+
*
|
|
22
|
+
* That second shape is why this exists as its own gate: typecheck cannot see it,
|
|
23
|
+
* and a suite only sees it as dozens of unrelated-looking import failures.
|
|
24
|
+
*/
|
|
25
|
+
/** Installed, and inside the declared range. */
|
|
26
|
+
type PeerFloorVerdict = 'satisfied'
|
|
27
|
+
/** Installed and BELOW the floor — the silent case this module exists for. */
|
|
28
|
+
| 'below-floor'
|
|
29
|
+
/** Not installed and never asked for. A legitimate answer for an optional peer. */
|
|
30
|
+
| 'absent-unused'
|
|
31
|
+
/** Declared by the app, yet no version could be read, so the floor went
|
|
32
|
+
* UNCHECKED. Reported as a failure rather than a pass this did not earn. */
|
|
33
|
+
| 'absent-but-declared';
|
|
34
|
+
interface PeerFloorRow {
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly range: string;
|
|
37
|
+
readonly installed: string | null;
|
|
38
|
+
readonly verdict: PeerFloorVerdict;
|
|
39
|
+
}
|
|
40
|
+
interface PeerFloorReport {
|
|
41
|
+
readonly shellVersion: string;
|
|
42
|
+
readonly rows: readonly PeerFloorRow[];
|
|
43
|
+
readonly violations: readonly PeerFloorRow[];
|
|
44
|
+
readonly ok: boolean;
|
|
45
|
+
}
|
|
46
|
+
interface CheckPeerFloorsOptions {
|
|
47
|
+
/** Directory of the app under audit — the one whose `package.json` and
|
|
48
|
+
* installed tree are read. */
|
|
49
|
+
appDir: string;
|
|
50
|
+
/** Package whose peer floors are the contract. Defaults to this shell. */
|
|
51
|
+
shell?: string;
|
|
52
|
+
/** Only audit peers under this scope. Third-party peers (react, drizzle) are
|
|
53
|
+
* the app's own business, not part of the Tangle wire contract. Pass `''` to
|
|
54
|
+
* audit every peer. */
|
|
55
|
+
scope?: string;
|
|
56
|
+
/** Floors to audit against, when the shell is not resolvable from `appDir` —
|
|
57
|
+
* the package auditing ITSELF, which has no copy of itself in its own
|
|
58
|
+
* `node_modules`. Without this a package cannot check that the contract it
|
|
59
|
+
* publishes is one its own dev install satisfies. */
|
|
60
|
+
shellManifest?: {
|
|
61
|
+
version?: string;
|
|
62
|
+
peerDependencies?: Record<string, string>;
|
|
63
|
+
};
|
|
64
|
+
/** Directory name to walk for installed packages. Overridable so a test can
|
|
65
|
+
* point at a committed fixture tree — `node_modules` is gitignored
|
|
66
|
+
* everywhere, so a fixture using that name could not be committed, and a
|
|
67
|
+
* calibration proof that is not committed is a proof that stops running. */
|
|
68
|
+
modulesDir?: string;
|
|
69
|
+
}
|
|
70
|
+
declare function satisfiesRange(version: string, range: string): boolean;
|
|
71
|
+
/** Audit one app directory against the shell's declared peer floors. */
|
|
72
|
+
declare function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorReport;
|
|
73
|
+
/** The failure message for one violating row. Split out so a caller can raise
|
|
74
|
+
* it from a test and a CLI can print it identically. */
|
|
75
|
+
declare function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell?: string): string;
|
|
76
|
+
declare function formatPeerFloorReport(report: PeerFloorReport, shell?: string): string;
|
|
77
|
+
|
|
78
|
+
export { type CheckPeerFloorsOptions, type PeerFloorReport, type PeerFloorRow, type PeerFloorVerdict, checkPeerFloors, describePeerFloorViolation, formatPeerFloorReport, satisfiesRange };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkPeerFloors,
|
|
3
|
+
describePeerFloorViolation,
|
|
4
|
+
formatPeerFloorReport,
|
|
5
|
+
satisfiesRange
|
|
6
|
+
} from "../chunk-ZSJRDHCN.js";
|
|
7
|
+
export {
|
|
8
|
+
checkPeerFloors,
|
|
9
|
+
describePeerFloorViolation,
|
|
10
|
+
formatPeerFloorReport,
|
|
11
|
+
satisfiesRange
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
checkPeerFloors,
|
|
4
|
+
formatPeerFloorReport
|
|
5
|
+
} from "../chunk-ZSJRDHCN.js";
|
|
6
|
+
|
|
7
|
+
// src/peer-floors/cli.ts
|
|
8
|
+
var appDir = process.argv[2] ?? process.cwd();
|
|
9
|
+
try {
|
|
10
|
+
const report = checkPeerFloors({ appDir });
|
|
11
|
+
process.stdout.write(`${formatPeerFloorReport(report)}
|
|
12
|
+
`);
|
|
13
|
+
process.exit(report.ok ? 0 : 1);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
process.stderr.write(`agent-app-peer-check failed: ${err instanceof Error ? err.message : String(err)}
|
|
16
|
+
`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/peer-floors/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-peer-check` — fail a consumer's CI when its installed tree sits\n * below a peer floor this package declares.\n *\n * Runs in the CONSUMER's repo, over the consumer's own `node_modules`, because\n * the floors only mean anything against a real install. Add it next to\n * typecheck:\n *\n * \"scripts\": { \"peer-check\": \"agent-app-peer-check\" }\n *\n * Exits 1 on any violation, 0 otherwise. Takes no configuration — the floors\n * come from the installed shell manifest, so the check cannot go stale when the\n * shell adds an engine.\n */\nimport { checkPeerFloors, formatPeerFloorReport } from './check'\n\nconst appDir = process.argv[2] ?? process.cwd()\n\ntry {\n const report = checkPeerFloors({ appDir })\n process.stdout.write(`${formatPeerFloorReport(report)}\\n`)\n process.exit(report.ok ? 0 : 1)\n} catch (err) {\n process.stderr.write(`agent-app-peer-check failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n}\n"],"mappings":";;;;;;;AAiBA,IAAM,SAAS,QAAQ,KAAK,CAAC,KAAK,QAAQ,IAAI;AAE9C,IAAI;AACF,QAAM,SAAS,gBAAgB,EAAE,OAAO,CAAC;AACzC,UAAQ,OAAO,MAAM,GAAG,sBAAsB,MAAM,CAAC;AAAA,CAAI;AACzD,UAAQ,KAAK,OAAO,KAAK,IAAI,CAAC;AAChC,SAAS,KAAK;AACZ,UAAQ,OAAO,MAAM,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACzG,UAAQ,KAAK,CAAC;AAChB;","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createWorkspaceKeyManager
|
|
3
|
-
} from "../chunk-GXE6KHTS.js";
|
|
4
1
|
import {
|
|
5
2
|
createFieldCrypto
|
|
6
3
|
} from "../chunk-TA5Q4I2K.js";
|
|
4
|
+
import {
|
|
5
|
+
createWorkspaceKeyManager
|
|
6
|
+
} from "../chunk-GXE6KHTS.js";
|
|
7
7
|
|
|
8
8
|
// src/preset-cloudflare/workflow-instance.ts
|
|
9
9
|
async function ensureCloudflareWorkflowInstance(binding, input) {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ import * as _tangle_network_agent_runtime_tool_loop from '@tangle-network/agent-
|
|
|
4
4
|
import { ToolLoopMessage } from '@tangle-network/agent-runtime/tool-loop';
|
|
5
5
|
export { RunToolLoopOptions as AppToolLoopOptions, ToolLoopAssistantToolCall as LoopAssistantToolCall, ToolLoopMessage as LoopMessage, ToolLoopCall as LoopToolCall, StreamToolLoopOptions as StreamAppToolLoopOptions, StreamToolLoopYield as StreamLoopYield, ToolLoopEvent, ToolLoopResult, ToolLoopStopReason, runToolLoop as runAppToolLoop, streamToolLoop as streamAppToolLoop } from '@tangle-network/agent-runtime/tool-loop';
|
|
6
6
|
import { CertifiedProfile } from '@tangle-network/agent-runtime/intelligence';
|
|
7
|
-
import { A as AppToolMcpServer } from '../mcp-
|
|
7
|
+
import { A as AppToolMcpServer } from '../mcp-C-jV_Xe9.js';
|
|
8
8
|
import '@tangle-network/agent-interface';
|
|
9
9
|
import '../types-DbU-oO5h.js';
|
|
10
|
-
import '../auth-
|
|
10
|
+
import '../auth-Bulnsz3V.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Events the app's OpenAI-compat stream adapter ({@link toLoopEvents}) yields.
|
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Sandbox } from '@tangle-network/sandbox/core';
|
|
|
2
2
|
import { SandboxInstance, ProvisionEvent, EgressPolicy, StorageConfig, ScopedTokenScope, TurnDriveResult, MintScopedTokenOptions } from '@tangle-network/sandbox';
|
|
3
3
|
export { StorageConfig } from '@tangle-network/sandbox';
|
|
4
4
|
import { ReasoningEffort, AgentProfileMcpServer, AgentProfileFileMount, AgentProfile } from '@tangle-network/agent-interface';
|
|
5
|
-
import { T as ToolHeaderNames } from '../auth-
|
|
5
|
+
import { T as ToolHeaderNames } from '../auth-Bulnsz3V.js';
|
|
6
6
|
import { a as AppToolName, A as AppToolContext } from '../types-DbU-oO5h.js';
|
|
7
7
|
import { Harness } from '../harness/index.js';
|
|
8
8
|
import { a as TangleExecutionEnvironment } from '../model-CdCDfBA9.js';
|
package/dist/sandbox/index.js
CHANGED
|
@@ -85,11 +85,11 @@ import {
|
|
|
85
85
|
workspaceSandboxRecoveryMessage,
|
|
86
86
|
workspaceSandboxRecoveryRecommendedActions,
|
|
87
87
|
writeProfileFilesToBox
|
|
88
|
-
} from "../chunk-
|
|
89
|
-
import "../chunk-LWSJK546.js";
|
|
88
|
+
} from "../chunk-EPOPI77J.js";
|
|
90
89
|
import "../chunk-73F3CKVK.js";
|
|
91
|
-
import "../chunk-
|
|
92
|
-
import "../chunk-
|
|
90
|
+
import "../chunk-LWSJK546.js";
|
|
91
|
+
import "../chunk-C5OIABSB.js";
|
|
92
|
+
import "../chunk-YOFQO4R6.js";
|
|
93
93
|
import "../chunk-YEFFHORB.js";
|
|
94
94
|
import "../chunk-S5SRJJQG.js";
|
|
95
95
|
import "../chunk-JML7WKWU.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { j as SequenceMediaKind, f as SequenceTimeline, k as TimelineInterval, b as SequenceStore } from '../store-B7LLlk9p.js';
|
|
2
2
|
export { M as MIN_SEQUENCE_CLIP_FRAMES, N as NewSequenceClip, l as NewSequenceDecision, m as NewSequenceTrack, g as SequenceClip, a as SequenceClipMedia, n as SequenceClipPatch, o as SequenceDecision, d as SequenceExportFormat, h as SequenceExportRecord, p as SequenceExportStatus, q as SequenceFrameSnapshot, i as SequenceMeta, r as SequenceStatus, S as SequenceStoreScope, e as SequenceTrack, c as SequenceTrackKind, T as TimelineClipBounds, s as assertClipFitsSequence, t as chooseCaptionPlacement, u as clampClipDuration, v as clampClipStart, w as formatSeconds, x as formatTimecode, y as framesToSeconds, z as secondsToFrames, A as snapshotFrame, B as trackIntervals } from '../store-B7LLlk9p.js';
|
|
3
3
|
export { A as AddCaptionOperation, C as CaptionTargetResolution, a as CreateTrackOperation, D as DeleteClipOperation, E as ExtendSequenceOperation, M as MoveClipOperation, P as PlaceClipOperation, Q as QueueExportOperation, S as SEQUENCE_OPERATION_TYPES, b as SequenceApplyResult, c as SequenceOperation, d as SequenceOperationContext, e as SequenceOperationType, f as SequencePlan, g as SetClipDisabledOperation, h as SetClipTextOperation, i as SplitClipOperation, T as TrimClipOperation, j as applySequenceOperation, k as applySequenceOperations, l as assertSequenceMediaUrl, m as captionTrackNameForLanguage, n as lastClipEndFrame, p as parseSequenceOperations, r as resolveCaptionPlacement, o as resolveCaptionTarget, q as resolvePlaceClipTrack, v as validateAddCaption, s as validateCreateTrack, t as validateDeleteClip, u as validateExtendSequence, w as validateMoveClip, x as validatePlaceClip, y as validateQueueExport, z as validateSequenceOperation, B as validateSequenceOperations, F as validateSetClipDisabled, G as validateSetClipText, H as validateSplitClip, I as validateTrimClip } from '../apply-6wlMOLf8.js';
|
|
4
|
-
import { S as ScopedMcpServerEntryOptions, A as AppToolMcpServer } from '../mcp-
|
|
4
|
+
import { S as ScopedMcpServerEntryOptions, A as AppToolMcpServer } from '../mcp-C-jV_Xe9.js';
|
|
5
5
|
export { M as SEQUENCES_MCP_PROTOCOL_VERSIONS } from '../mcp-rpc-CzU5LWWT.js';
|
|
6
6
|
import '@tangle-network/agent-interface';
|
|
7
7
|
import '../types-DbU-oO5h.js';
|
|
8
|
-
import '../auth-
|
|
8
|
+
import '../auth-Bulnsz3V.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Pure interchange-format builders over `SequenceTimeline` — SRT, WebVTT,
|
package/dist/sequences/index.js
CHANGED
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { T as ToolHeaderNames } from '../auth-
|
|
2
|
-
export { A as AuthenticateOptions, D as DEFAULT_HEADER_NAMES, a as ToolAuthResult, b as authenticateToolRequest, r as readToolArgs } from '../auth-
|
|
1
|
+
import { T as ToolHeaderNames } from '../auth-Bulnsz3V.js';
|
|
2
|
+
export { A as AuthenticateOptions, D as DEFAULT_HEADER_NAMES, a as ToolAuthResult, b as authenticateToolRequest, r as readToolArgs } from '../auth-Bulnsz3V.js';
|
|
3
3
|
import { e as AppToolTaxonomy, d as AppToolHandlers, b as AppToolDefinition, A as AppToolContext, c as AppToolProducedEvent, f as AppToolOutcome, a as AppToolName } from '../types-DbU-oO5h.js';
|
|
4
4
|
export { g as APP_TOOL_NAMES, h as AddCitationArgs, i as AddCitationResult, B as BuildAppToolsOptions, O as OpenAIFunctionTool, R as RenderUiArgs, j as RenderUiResult, S as ScheduleFollowupArgs, k as ScheduleFollowupResult, l as SubmitProposalArgs, m as SubmitProposalResult, n as buildAppToolOpenAITools, o as customToolToOpenAI, p as defineAppTool, q as findCustomTool, r as isAppToolName } from '../types-DbU-oO5h.js';
|
|
5
|
-
export { A as AppToolMcpServer, B as BuildHttpMcpServerOptions, a as BuildMcpServerOptions, D as DEFAULT_APP_TOOL_PATHS, S as ScopedMcpServerEntryOptions, b as buildAppToolMcpServer, c as buildHttpMcpServer, d as buildScopedMcpServerEntry, u as unresolvableSurfaceCredential } from '../mcp-
|
|
5
|
+
export { A as AppToolMcpServer, B as BuildHttpMcpServerOptions, a as BuildMcpServerOptions, D as DEFAULT_APP_TOOL_PATHS, S as ScopedMcpServerEntryOptions, b as buildAppToolMcpServer, c as buildHttpMcpServer, d as buildScopedMcpServerEntry, u as unresolvableSurfaceCredential } from '../mcp-C-jV_Xe9.js';
|
|
6
6
|
export { C as CreateMcpToolHandlerOptions, M as MCP_PROTOCOL_VERSIONS, b as McpProtocolVersion, c as McpServerInfo, a as McpToolDefinition, d as createMcpToolHandler } from '../mcp-rpc-CzU5LWWT.js';
|
|
7
7
|
import '@tangle-network/agent-interface';
|
|
8
8
|
|
package/dist/tools/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
restrictTaxonomy,
|
|
10
10
|
verifyCapabilityToken,
|
|
11
11
|
verifyExpiringCapabilityToken
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-C5OIABSB.js";
|
|
13
13
|
import {
|
|
14
14
|
DEFAULT_APP_TOOL_PATHS,
|
|
15
15
|
DEFAULT_HEADER_NAMES,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
createMcpToolHandler,
|
|
22
22
|
readToolArgs,
|
|
23
23
|
unresolvableSurfaceCredential
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-YOFQO4R6.js";
|
|
25
25
|
import {
|
|
26
26
|
APP_TOOL_NAMES,
|
|
27
27
|
ToolInputError,
|
package/dist/web-react/index.js
CHANGED
|
@@ -78,7 +78,14 @@ import {
|
|
|
78
78
|
useSmoothText,
|
|
79
79
|
useThinkingSeconds,
|
|
80
80
|
waterfallLayout
|
|
81
|
-
} from "../chunk-
|
|
81
|
+
} from "../chunk-CKUZVDZ7.js";
|
|
82
|
+
import {
|
|
83
|
+
useComposerAttachments
|
|
84
|
+
} from "../chunk-6MUJROBT.js";
|
|
85
|
+
import {
|
|
86
|
+
tabTerminalConnectionId,
|
|
87
|
+
useSandboxTerminalConnection
|
|
88
|
+
} from "../chunk-BATKJP3P.js";
|
|
82
89
|
import "../chunk-FBVLEGEG.js";
|
|
83
90
|
import "../chunk-GINKOZFD.js";
|
|
84
91
|
import {
|
|
@@ -96,13 +103,6 @@ import {
|
|
|
96
103
|
import {
|
|
97
104
|
parseReviewQueueItem
|
|
98
105
|
} from "../chunk-GEYACSFW.js";
|
|
99
|
-
import {
|
|
100
|
-
useComposerAttachments
|
|
101
|
-
} from "../chunk-6MUJROBT.js";
|
|
102
|
-
import {
|
|
103
|
-
tabTerminalConnectionId,
|
|
104
|
-
useSandboxTerminalConnection
|
|
105
|
-
} from "../chunk-BATKJP3P.js";
|
|
106
106
|
import "../chunk-QY4BRKRJ.js";
|
|
107
107
|
import {
|
|
108
108
|
ATTACHMENT_ACCEPT
|
|
@@ -114,8 +114,7 @@ import {
|
|
|
114
114
|
isChatAttachmentPart,
|
|
115
115
|
mentionInputToPart,
|
|
116
116
|
mentionPartsFromMessageParts
|
|
117
|
-
} from "../chunk-
|
|
118
|
-
import "../chunk-ZVEEWGDK.js";
|
|
117
|
+
} from "../chunk-WUZZVQKR.js";
|
|
119
118
|
import {
|
|
120
119
|
DISPATCH_MAX_MEDIA_PARTS,
|
|
121
120
|
DISPATCH_MAX_PARTS,
|
|
@@ -128,6 +127,7 @@ import {
|
|
|
128
127
|
mediaTypeForMentionPath,
|
|
129
128
|
mentionKindForPath
|
|
130
129
|
} from "../chunk-KWXUBMXU.js";
|
|
130
|
+
import "../chunk-ZVEEWGDK.js";
|
|
131
131
|
import {
|
|
132
132
|
attachmentPartKey
|
|
133
133
|
} from "../chunk-5EPIPT4V.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.45.
|
|
3
|
+
"version": "0.45.9",
|
|
4
4
|
"packageManager": "pnpm@11.17.0",
|
|
5
5
|
"description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
],
|
|
34
34
|
"bin": {
|
|
35
35
|
"agent-app-theme-check": "./dist/theme-contract/cli.js",
|
|
36
|
-
"agent-app-preflight": "./dist/preflight/cli.js"
|
|
36
|
+
"agent-app-preflight": "./dist/preflight/cli.js",
|
|
37
|
+
"agent-app-peer-check": "./dist/peer-floors/cli.js"
|
|
37
38
|
},
|
|
38
39
|
"exports": {
|
|
39
40
|
"./package.json": "./package.json",
|
|
@@ -418,7 +419,12 @@
|
|
|
418
419
|
"import": "./dist/theme-contract/index.js",
|
|
419
420
|
"default": "./dist/theme-contract/index.js"
|
|
420
421
|
},
|
|
421
|
-
"./styles": "./dist/theme/tokens.css"
|
|
422
|
+
"./styles": "./dist/theme/tokens.css",
|
|
423
|
+
"./peer-floors": {
|
|
424
|
+
"types": "./dist/peer-floors/check.d.ts",
|
|
425
|
+
"import": "./dist/peer-floors/check.js",
|
|
426
|
+
"default": "./dist/peer-floors/check.js"
|
|
427
|
+
}
|
|
422
428
|
},
|
|
423
429
|
"scripts": {
|
|
424
430
|
"build": "tsup",
|
package/dist/auth-DJs6lfAs.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { A as AppToolContext } from './types-DbU-oO5h.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Header names carrying the server-set per-turn context + the capability token.
|
|
5
|
-
* Defaults are product-neutral (`X-Agent-App-*`); a product that already ships
|
|
6
|
-
* a header convention (e.g. `X-Acme-User-Id`) passes its own.
|
|
7
|
-
*/
|
|
8
|
-
interface ToolHeaderNames {
|
|
9
|
-
userId: string;
|
|
10
|
-
workspaceId: string;
|
|
11
|
-
threadId: string;
|
|
12
|
-
}
|
|
13
|
-
/** Provide default HTTP header names for user, workspace, and thread identification */
|
|
14
|
-
declare const DEFAULT_HEADER_NAMES: ToolHeaderNames;
|
|
15
|
-
/** Define options to verify bearer tokens and customize authentication header names */
|
|
16
|
-
interface AuthenticateOptions {
|
|
17
|
-
/** Verify the bearer capability token belongs to `userId`. The product's
|
|
18
|
-
* HMAC/JWT impl — the seam that keeps token crypto out of this package. */
|
|
19
|
-
verifyToken: (userId: string, bearer: string) => Promise<boolean>;
|
|
20
|
-
headerNames?: ToolHeaderNames;
|
|
21
|
-
}
|
|
22
|
-
/** Represent the result of tool authentication with success context or failure response */
|
|
23
|
-
type ToolAuthResult = {
|
|
24
|
-
ok: true;
|
|
25
|
-
ctx: AppToolContext;
|
|
26
|
-
} | {
|
|
27
|
-
ok: false;
|
|
28
|
-
response: Response;
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Recover + verify the trusted context for a tool request. The user comes from
|
|
32
|
-
* a server-set header and the bearer token MUST verify against THAT user; the
|
|
33
|
-
* workspace comes from a header too — never from tool args — so the model can
|
|
34
|
-
* neither forge identity nor target another workspace. Fail-closed: any missing
|
|
35
|
-
* credential or a token minted for another user yields a 401/400 Response.
|
|
36
|
-
*/
|
|
37
|
-
declare function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult>;
|
|
38
|
-
/** Read a tool's argument object from the request body, tolerant of MCP host
|
|
39
|
-
* aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */
|
|
40
|
-
declare function readToolArgs<T>(request: Request): Promise<T | null>;
|
|
41
|
-
|
|
42
|
-
export { type AuthenticateOptions as A, DEFAULT_HEADER_NAMES as D, type ToolHeaderNames as T, type ToolAuthResult as a, authenticateToolRequest as b, readToolArgs as r };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/auth.ts","../src/tools/mcp.ts","../src/tools/mcp-rpc.ts"],"sourcesContent":["import type { AppToolContext } from './types'\n\n/**\n * Header names carrying the server-set per-turn context + the capability token.\n * Defaults are product-neutral (`X-Agent-App-*`); a product that already ships\n * a header convention (e.g. `X-Acme-User-Id`) passes its own.\n */\nexport interface ToolHeaderNames {\n userId: string\n workspaceId: string\n threadId: string\n}\n\n/** Provide default HTTP header names for user, workspace, and thread identification */\nexport const DEFAULT_HEADER_NAMES: ToolHeaderNames = {\n userId: 'X-Agent-App-User-Id',\n workspaceId: 'X-Agent-App-Workspace-Id',\n threadId: 'X-Agent-App-Thread-Id',\n}\n\n/** Define options to verify bearer tokens and customize authentication header names */\nexport interface AuthenticateOptions {\n /** Verify the bearer capability token belongs to `userId`. The product's\n * HMAC/JWT impl — the seam that keeps token crypto out of this package. */\n verifyToken: (userId: string, bearer: string) => Promise<boolean>\n headerNames?: ToolHeaderNames\n}\n\n/** Represent the result of tool authentication with success context or failure response */\nexport type ToolAuthResult =\n | { ok: true; ctx: AppToolContext }\n | { ok: false; response: Response }\n\n/**\n * Recover + verify the trusted context for a tool request. The user comes from\n * a server-set header and the bearer token MUST verify against THAT user; the\n * workspace comes from a header too — never from tool args — so the model can\n * neither forge identity nor target another workspace. Fail-closed: any missing\n * credential or a token minted for another user yields a 401/400 Response.\n */\nexport async function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult> {\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n const userId = request.headers.get(h.userId)?.trim()\n const workspaceId = request.headers.get(h.workspaceId)?.trim()\n const threadId = request.headers.get(h.threadId)?.trim() || null\n const bearer = request.headers.get('authorization')?.match(/^Bearer\\s+(.+)$/i)?.[1]\n\n if (!userId || !bearer) {\n return { ok: false, response: Response.json({ error: 'Missing capability credentials' }, { status: 401 }) }\n }\n if (!(await opts.verifyToken(userId, bearer))) {\n return { ok: false, response: Response.json({ error: 'Invalid capability token' }, { status: 401 }) }\n }\n if (!workspaceId) {\n return { ok: false, response: Response.json({ error: 'Missing workspace context' }, { status: 400 }) }\n }\n return { ok: true, ctx: { userId, workspaceId, threadId } }\n}\n\n/** Read a tool's argument object from the request body, tolerant of MCP host\n * aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */\nexport async function readToolArgs<T>(request: Request): Promise<T | null> {\n let body: { args?: T; arguments?: T }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return null\n }\n return (body.args ?? body.arguments ?? (body as T)) as T\n}\n","/**\n * The tagged-configuration contract for every MCP server this package emits.\n *\n * An `AgentProfile` is digested, diffed, stored, and logged, so a credential\n * that rides it as plain text is a leak by construction. `@tangle-network/\n * agent-interface` closed that at **0.38.0**: `args`, `env`, and `headers` on\n * an `AgentProfileMcpServer` no longer take strings. Every value is either\n * deliberately public profile material (`defineAgentProfilePublicConfig`) or an\n * opaque reference to a credential (`defineAgentProfileSecretRef`) resolved\n * privately at materialization, validated by a `z.discriminatedUnion('kind')`.\n *\n * The schema also refuses to let a secret hide as public material: a `public`\n * value under a credential-bearing key name (`Authorization`, `*_TOKEN`,\n * `*_API_KEY`, `*_SECRET`, `Cookie`, …) is rejected with \"credential-bearing\n * config names require a secret-ref\", and any value whose bytes look like a\n * credential (`Bearer …`, `sk-…`, `ghp_…`) is rejected outright. So the\n * capability token this package used to inline as `Bearer <token>` cannot be\n * expressed at all — it must become a reference.\n *\n * **A reference resolves ONLY from an environment variable present on the box,\n * named by `key`.** That is why the builders below take a `tokenEnvKey` (the\n * box-env variable NAME) instead of a token VALUE: agent-app cannot guess the\n * name, and a reference to a key nothing places fails the turn at\n * materialization rather than running credential-less. The box env is what\n * `SandboxRuntimeConfig.env` (and the platform secret store via\n * `SandboxRuntimeConfig.secrets`) writes at sandbox creation, so the key must\n * name a variable one of those places — and it must therefore be a real\n * environment-variable name, which this module enforces.\n *\n * A per-request credential is only referenceable when the value written at box\n * creation is byte-identical to the one every later turn would mint (a\n * deterministic derivation such as an HMAC over the workspace id). A token\n * scoped narrower than the box — per-user, per-document — cannot be referenced\n * at all; {@link unresolvableSurfaceCredential} names that blocker instead of\n * emitting a reference that resolves to nothing.\n */\nimport {\n agentProfileMcpServerSchema,\n defineAgentProfilePublicConfig,\n defineAgentProfileSecretRef,\n type AgentProfileConfigValue,\n} from '@tangle-network/agent-interface'\nimport type { AppToolContext } from './types'\nimport type { AppToolName } from './openai'\nimport type { AppToolDefinition } from './registry'\nimport type { ToolHeaderNames } from './auth'\nimport { DEFAULT_HEADER_NAMES } from './auth'\n\n/** Default route path each app tool is served at. A product mounts its routes\n * at these paths (or supplies its own via {@link BuildMcpServerOptions.paths}). */\nexport const DEFAULT_APP_TOOL_PATHS: Record<AppToolName, string> = {\n submit_proposal: '/api/tools/propose',\n schedule_followup: '/api/tools/followup',\n render_ui: '/api/tools/render-ui',\n add_citation: '/api/tools/citation',\n}\n\n/** The portable MCP server entry the sandbox SDK accepts (transport + url +\n * tagged headers). Assignable to `AgentProfileMcpServer` without a cast —\n * products spread it into their profile's `mcp` map. */\nexport interface AppToolMcpServer {\n transport: 'http'\n url: string\n headers: Record<string, AgentProfileConfigValue>\n enabled: true\n metadata: { description: string }\n}\n\n/** POSIX environment-variable name — the same shape `agent-interface`'s\n * `environmentNameSchema` accepts for an env key. A secret reference resolves\n * from the box environment, so a key outside this shape can never resolve. */\nconst ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/**\n * Reject a secret-reference key that names nothing the box can hold.\n *\n * `agent-interface` accepts any non-credential string as a reference key, so a\n * typo or a token VALUE passed where a key belongs validates against the\n * profile schema and fails much later, inside materialization, as an opaque\n * missing-secret error. Failing here names the parameter.\n */\nfunction assertSecretEnvKey(key: string, label: string): string {\n if (!ENV_NAME_PATTERN.test(key)) {\n throw new Error(\n `${label}: tokenEnvKey must be an environment-variable NAME the sandbox box carries ` +\n `(e.g. 'APP_CAPABILITY_TOKEN'), not a token value — got ${JSON.stringify(key)}. ` +\n 'A profile may only REFERENCE a credential; the value is placed on the box by ' +\n 'SandboxRuntimeConfig.env or the platform secret store.',\n )\n }\n return key\n}\n\n/**\n * Validate one emitted entry against the REAL `agentProfileMcpServerSchema`.\n *\n * The contract's rules (which key names demand a reference, which byte patterns\n * read as a credential) live in `agent-interface`. Re-implementing them here\n * would drift the moment that package moves — which it does: 0.36.0 → 0.40.0 in\n * three days. Running the shipped validator instead means a product that passes\n * a credential-bearing custom header name, a relative base URL, or a URL with\n * embedded credentials fails at the builder with the contract's own message.\n *\n * It is also the loud failure for a version skew: if the resolved\n * `@tangle-network/agent-interface` predates 0.38.0, its schema rejects the\n * tagged shape this package now emits, and that surfaces here instead of as a\n * sandbox provisioning error.\n */\nfunction assertProfileMcpServer<T extends AppToolMcpServer>(server: T, label: string): T {\n const result = agentProfileMcpServerSchema.safeParse(server)\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)\n .join('; ')\n throw new Error(\n `${label} produced an MCP server the AgentProfile contract rejects: ${issues}. ` +\n 'Requires @tangle-network/agent-interface >= 0.38.0 (tagged MCP config values).',\n )\n }\n return server\n}\n\n/**\n * Refuse to mount a surface whose credential is scoped narrower than the box.\n *\n * A per-user or per-resource capability token is minted per request. The box\n * environment is written once at sandbox creation and shared by every turn and\n * every member of the workspace, so such a token can neither be placed there\n * ahead of time nor referenced from a per-turn profile. Widening the channel to\n * a workspace-bound token is not a substitute when the route authenticates the\n * CALLER: the agent can read its own box env, so it could forge that identity.\n *\n * Mounting the surface anyway would emit a plain-string `Authorization` header\n * (rejected by the schema) or a reference to a key nothing places (rejected at\n * materialization). Throwing here names the actual blocker. Exported because\n * every product with per-document MCP surfaces hits it and was writing this\n * message itself.\n */\nexport function unresolvableSurfaceCredential(surface: string): never {\n throw new Error(\n `The ${surface} MCP surface cannot be mounted: its capability token is scoped to a single ` +\n 'user and resource, and an AgentProfile may only reference a credential the sandbox can ' +\n 'resolve from the box environment, which is workspace-wide and fixed at sandbox creation. ' +\n 'Mounting it needs a per-session secret channel on the sandbox API, or a route that ' +\n 'authenticates the workspace rather than the caller.',\n )\n}\n\n/** Define configuration options for building an HTTP MCP server including path, baseUrl, token env key, context, and description */\nexport interface BuildHttpMcpServerOptions {\n /** Route path on the app the sandbox POSTs to (e.g. `/api/tools/propose`). */\n path: string\n /** App base URL the sandbox reaches back to (no trailing slash required). */\n baseUrl: string\n /**\n * NAME of the box-environment variable holding the capability token — never\n * the token itself. The emitted `Authorization` header is a `secret-ref` to\n * this key with `format: 'bearer'`, so the sandbox resolves the value\n * privately and the profile carries only the name.\n *\n * The key MUST name a variable the box actually carries (placed by\n * `SandboxRuntimeConfig.env` at creation, or injected from the platform\n * secret store via `SandboxRuntimeConfig.secrets`), and the value written\n * there must be the token this route will accept for every turn — which in\n * practice means a deterministic derivation (e.g. an HMAC over the workspace\n * id), not a freshly-random per-request mint. A token scoped narrower than\n * the box is not referenceable: see {@link unresolvableSurfaceCredential}.\n */\n tokenEnvKey: string\n ctx: AppToolContext\n /** Tool description the model sees. */\n description: string\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build ONE HTTP MCP server entry — the generic agent→app bridge. The\n * capability token (as a secret reference) + the user/workspace/thread ids ride\n * in server-set headers (never tool args), so the model can't forge identity or\n * target another workspace. Workspace/thread headers are omitted when their\n * `ctx` value is empty/null (e.g. an integration-invoke bridge that's\n * user-scoped only). Used directly for non-app-tool bridges\n * (integration_invoke) and via {@link buildAppToolMcpServer} for the four app\n * tools.\n */\nexport function buildHttpMcpServer(opts: BuildHttpMcpServerOptions): AppToolMcpServer {\n const base = opts.baseUrl.replace(/\\/+$/, '')\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n return assertProfileMcpServer(\n {\n transport: 'http',\n url: `${base}${opts.path}`,\n headers: {\n Authorization: defineAgentProfileSecretRef(\n assertSecretEnvKey(opts.tokenEnvKey, 'buildHttpMcpServer'),\n 'bearer',\n ),\n [h.userId]: defineAgentProfilePublicConfig(opts.ctx.userId),\n ...(opts.ctx.workspaceId\n ? { [h.workspaceId]: defineAgentProfilePublicConfig(opts.ctx.workspaceId) }\n : {}),\n ...(opts.ctx.threadId\n ? { [h.threadId]: defineAgentProfilePublicConfig(opts.ctx.threadId) }\n : {}),\n 'Content-Type': defineAgentProfilePublicConfig('application/json'),\n },\n enabled: true,\n metadata: { description: opts.description },\n },\n 'buildHttpMcpServer',\n )\n}\n\n/** Options for a per-document/scoped MCP channel entry (design-canvas,\n * sequences, …). The capability token + path scope ONE resource; the document\n * id lives in the path, never a tool argument. */\nexport interface ScopedMcpServerEntryOptions {\n /** App base URL the sandbox reaches back to (trailing slash tolerated). */\n baseUrl: string\n /** Product route serving the resource's MCP handler — id is part of the path. */\n path: string\n /**\n * NAME of the box-environment variable holding this channel's capability\n * token — never the token itself. See\n * {@link BuildHttpMcpServerOptions.tokenEnvKey}.\n *\n * A per-(user, resource) token cannot satisfy this: the box environment is\n * workspace-wide and fixed at sandbox creation. A product whose channel needs\n * one calls {@link unresolvableSurfaceCredential} rather than mounting an\n * entry that cannot resolve.\n */\n tokenEnvKey: string\n /** Override the channel's default tool-server description. */\n description?: string\n /** Identity headers for products whose route recovers the user via\n * `authenticateToolRequest`. Omit when the bearer token is self-contained. */\n ctx?: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build the `AgentProfileMcpServer`-shaped entry for a scoped, per-resource MCP\n * channel. The shared mechanism behind the per-domain entry builders\n * (`buildDesignCanvasMcpServerEntry`, `buildSequencesMcpServerEntry`): same\n * token/path guards, same description default, same ctx-vs-self-contained-token\n * branching. The domain is two parameters — `label` (for guard messages) and\n * `defaultDescription` — never baked.\n *\n * The no-`ctx` branch is a GENUINE behavioral path, not a shortcut: it emits a\n * self-contained-token entry with ONLY `Authorization` + `Content-Type`.\n * Routing it through {@link buildHttpMcpServer} would unconditionally write a\n * `userId` identity header (here `undefined`), so it stays a distinct branch.\n */\nexport function buildScopedMcpServerEntry(\n opts: ScopedMcpServerEntryOptions & { label: string; defaultDescription: string },\n): AppToolMcpServer {\n if (opts.tokenEnvKey.trim().length === 0) {\n throw new Error(`${opts.label} requires a capability token env key — omit the MCP server when none is available`)\n }\n if (!opts.path.startsWith('/')) {\n throw new Error(`${opts.label} path must start with \"/\" (got \"${opts.path}\")`)\n }\n const description = opts.description ?? opts.defaultDescription\n\n if (opts.ctx) {\n return buildHttpMcpServer({\n path: opts.path,\n baseUrl: opts.baseUrl,\n tokenEnvKey: opts.tokenEnvKey,\n ctx: opts.ctx,\n description,\n headerNames: opts.headerNames ?? DEFAULT_HEADER_NAMES,\n })\n }\n\n return assertProfileMcpServer(\n {\n transport: 'http',\n url: `${opts.baseUrl.replace(/\\/+$/, '')}${opts.path}`,\n headers: {\n Authorization: defineAgentProfileSecretRef(\n assertSecretEnvKey(opts.tokenEnvKey, opts.label),\n 'bearer',\n ),\n 'Content-Type': defineAgentProfilePublicConfig('application/json'),\n },\n enabled: true,\n metadata: { description },\n },\n opts.label,\n )\n}\n\n/** Define configuration options required to build an MCP server including tool, baseUrl, token, and context */\nexport interface BuildMcpServerOptions {\n /** A built-in app tool name, or a product-registered {@link AppToolDefinition}.\n * A custom tool supplies its route via `AppToolDefinition.path` (or `paths`). */\n tool: AppToolName | AppToolDefinition\n baseUrl: string\n /** NAME of the box-environment variable holding the capability token — see\n * {@link BuildHttpMcpServerOptions.tokenEnvKey}. */\n tokenEnvKey: string\n ctx: AppToolContext\n description: string\n headerNames?: ToolHeaderNames\n paths?: Partial<Record<string, string>>\n}\n\n/** Build one app-tool MCP server entry — a thin wrapper over\n * {@link buildHttpMcpServer} that resolves the tool's route path. Built-ins map\n * through {@link DEFAULT_APP_TOOL_PATHS}; a custom tool uses its own `path`\n * (or a `paths` override). */\nexport function buildAppToolMcpServer(opts: BuildMcpServerOptions): AppToolMcpServer {\n const path =\n typeof opts.tool === 'string'\n ? opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool]\n : opts.paths?.[opts.tool.name] ?? opts.tool.path\n if (!path) {\n const name = typeof opts.tool === 'string' ? opts.tool : opts.tool.name\n throw new Error(`buildAppToolMcpServer: tool \"${name}\" has no route path — set AppToolDefinition.path or pass it via opts.paths`)\n }\n return buildHttpMcpServer({\n path,\n baseUrl: opts.baseUrl,\n tokenEnvKey: opts.tokenEnvKey,\n ctx: opts.ctx,\n description: opts.description,\n headerNames: opts.headerNames,\n })\n}\n","/**\n * Generic streamable-HTTP JSON-RPC 2.0 envelope for a tools-only MCP server.\n * Stateless, Workers-compatible: no session table, no SSE — every request gets\n * a single `application/json` response, which the streamable-HTTP transport\n * explicitly permits for tools-only servers.\n *\n * Protocol surface:\n * initialize → echo client's protocolVersion if supported, else latest\n * ping → empty result {}\n * notifications/* (no `id`) → 202 with no body\n * tools/list → tool manifest\n * tools/call → run + surface execution failures as isError text results\n * anything else → -32601\n *\n * Execution failures (argument shape, validation, store throws) become `isError`\n * tool results carrying the thrown message verbatim — the model reads WHY and\n * retries. Protocol misuse becomes a JSON-RPC error object.\n */\n\nexport const MCP_PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'] as const\n/** Resolve a valid protocol version from the predefined MCP_PROTOCOL_VERSIONS array */\nexport type McpProtocolVersion = (typeof MCP_PROTOCOL_VERSIONS)[number]\n\nconst LATEST_PROTOCOL_VERSION: McpProtocolVersion = MCP_PROTOCOL_VERSIONS[0]\n\n/** Describe the structure of server information including name and version */\nexport interface McpServerInfo {\n name: string\n version: string\n}\n\n/** One tool entry in the registry the handler owns. */\nexport interface McpToolDefinition<TEnv = Record<string, never>> {\n name: string\n description: string\n /** JSON Schema for the `params.arguments` object. */\n inputSchema: Record<string, unknown>\n /** Receive validated (Record) args + the env the handler threaded; throw to\n * surface an isError result — never throw for protocol/framing issues. */\n run(args: Record<string, unknown>, env: TEnv): Promise<unknown>\n}\n\n/** Define options for creating a handler that manages MCP tools with environment support */\nexport interface CreateMcpToolHandlerOptions<TEnv = Record<string, never>> {\n serverInfo: McpServerInfo\n /** Full tool list; order IS the tools/list order. */\n tools: McpToolDefinition<TEnv>[]\n /** Per-request environment threaded into every `run` call. If your tools are\n * stateless (or carry state through closure) pass an empty builder:\n * `() => ({} as TEnv)`. */\n buildEnv(request: Request): TEnv | Promise<TEnv>\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype JsonRpcId = string | number | null\n\ninterface ToolCallContent {\n content: Array<{ type: 'text'; text: string }>\n isError?: true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction rpcResult(id: JsonRpcId, result: unknown): Response {\n return Response.json({ jsonrpc: '2.0', id, result })\n}\n\nfunction rpcError(id: JsonRpcId, code: number, message: string, status = 200): Response {\n return Response.json({ jsonrpc: '2.0', id, error: { code, message } }, { status })\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Build a request handler for a tools-only MCP server. The returned function\n * accepts a standard `Request` and resolves to a `Response` — mount it on any\n * Cloudflare Worker route or Remix `loader`.\n *\n * The handler calls `buildEnv` exactly ONCE per `tools/call` request (after\n * the tool is found, before `run`) — non-`tools/call` paths skip it entirely\n * so metadata requests do not pay env-build cost.\n */\nexport function createMcpToolHandler<TEnv = Record<string, never>>(\n opts: CreateMcpToolHandlerOptions<TEnv>,\n): (request: Request) => Promise<Response> {\n const toolMap = new Map<string, McpToolDefinition<TEnv>>()\n for (const tool of opts.tools) {\n if (toolMap.has(tool.name)) throw new Error(`duplicate MCP tool name: ${tool.name}`)\n toolMap.set(tool.name, tool)\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') {\n return new Response('MCP server accepts JSON-RPC 2.0 over POST only', {\n status: 405,\n headers: { Allow: 'POST' },\n })\n }\n\n let body: unknown\n try {\n body = await request.json()\n } catch {\n return rpcError(null, -32700, 'Parse error: request body is not valid JSON', 400)\n }\n\n if (Array.isArray(body)) {\n return rpcError(null, -32600, 'Invalid request: JSON-RPC batching is not supported', 400)\n }\n if (!isRecord(body) || body.jsonrpc !== '2.0' || typeof body.method !== 'string') {\n return rpcError(\n null,\n -32600,\n 'Invalid request: expected a JSON-RPC 2.0 object with jsonrpc \"2.0\" and a string method',\n 400,\n )\n }\n\n const method = body.method\n const params = isRecord(body.params) ? body.params : {}\n\n // Notifications have no `id` — acknowledge without a JSON-RPC body.\n if (!('id' in body) || body.id === undefined) {\n return new Response(null, { status: 202 })\n }\n const id = body.id as JsonRpcId\n\n switch (method) {\n case 'initialize': {\n const requested = typeof params.protocolVersion === 'string' ? params.protocolVersion : undefined\n const protocolVersion =\n requested !== undefined && (MCP_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION\n return rpcResult(id, {\n protocolVersion,\n capabilities: { tools: { listChanged: false } },\n serverInfo: opts.serverInfo,\n })\n }\n\n case 'ping':\n return rpcResult(id, {})\n\n case 'tools/list':\n return rpcResult(id, {\n tools: opts.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n })\n\n case 'tools/call': {\n const name = params.name\n if (typeof name !== 'string' || name.length === 0) {\n return rpcError(id, -32602, 'tools/call requires params.name (string)')\n }\n const tool = toolMap.get(name)\n if (!tool) {\n return rpcError(\n id,\n -32602,\n `Unknown tool: ${name}. Available tools: ${opts.tools.map((t) => t.name).join(', ')}`,\n )\n }\n if (params.arguments !== undefined && !isRecord(params.arguments)) {\n return rpcError(id, -32602, 'tools/call params.arguments must be an object when provided')\n }\n const args = isRecord(params.arguments) ? params.arguments : {}\n let env: TEnv\n try {\n env = await opts.buildEnv(request)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed to build env: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n try {\n const result = await tool.run(args, env)\n const payload: ToolCallContent = { content: [{ type: 'text', text: JSON.stringify(result) }] }\n return rpcResult(id, payload)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n }\n\n default:\n return rpcError(id, -32601, `Method not found: ${method}`)\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|