@agent-native/core 0.204.0-nightly-20261008011018 → 0.204.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action.d.ts +1 -0
- package/dist/action.js +4 -2
- package/dist/cli/agent.js +2 -11
- package/dist/client/use-db-sync.d.ts +13 -0
- package/dist/client/use-db-sync.js +22 -1
- package/dist/collab/client.js +36 -3
- package/dist/collab/routes.d.ts +7 -2
- package/dist/collab/routes.js +15 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +15 -8
- package/dist/deploy/workspace-deploy.js +88 -13
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/mcp/actions/create-org-service-token.js +1 -0
- package/dist/mcp/build-server.js +12 -9
- package/dist/mcp-client/oauth-routes.js +2 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +3 -3
- package/dist/scripts/dev/index.js +2 -8
- package/dist/scripts/parse-args.d.ts +7 -0
- package/dist/scripts/parse-args.js +76 -0
- package/dist/scripts/utils.d.ts +1 -1
- package/dist/scripts/utils.js +1 -1
- package/dist/secrets/routes.d.ts +11 -11
- package/dist/server/action-discovery.js +4 -42
- package/dist/server/agent-chat/script-entries.js +3 -8
- package/dist/server/agent-chat-plugin.js +8 -42
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/auth.js +5 -2
- package/dist/server/google-oauth.js +8 -4
- package/dist/server/identity-sso.js +2 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/poll.d.ts +9 -0
- package/dist/server/poll.js +86 -7
- package/dist/server/query-echo-safe-redirect.d.ts +10 -0
- package/dist/server/query-echo-safe-redirect.js +102 -0
- package/dist/server/workspace-provider-oauth.js +2 -1
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -0
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -0
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -0
- package/dist/triggers/actions/manage-automation.d.ts +7 -7
- package/docs/content/external-agents-catalog.mdx +19 -0
- package/package.json +4 -4
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -0
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -0
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -0
package/dist/action.d.ts
CHANGED
|
@@ -230,6 +230,7 @@ export interface ActionMcpToolAnnotations {
|
|
|
230
230
|
readOnlyHint: boolean;
|
|
231
231
|
destructiveHint: boolean;
|
|
232
232
|
openWorldHint: boolean;
|
|
233
|
+
idempotentHint?: boolean;
|
|
233
234
|
}
|
|
234
235
|
interface DefineActionWithSchema<TSchema extends StandardSchemaV1, TReturn = any, TOutputSchema extends StandardSchemaV1 | undefined = undefined> {
|
|
235
236
|
title?: string;
|
package/dist/action.js
CHANGED
|
@@ -150,10 +150,12 @@ export function defineAction(options) {
|
|
|
150
150
|
!Array.isArray(options.mcpAnnotations) &&
|
|
151
151
|
typeof options.mcpAnnotations.readOnlyHint === "boolean" &&
|
|
152
152
|
typeof options.mcpAnnotations.destructiveHint === "boolean" &&
|
|
153
|
-
typeof options.mcpAnnotations.openWorldHint === "boolean"
|
|
153
|
+
typeof options.mcpAnnotations.openWorldHint === "boolean" &&
|
|
154
|
+
(options.mcpAnnotations.idempotentHint === undefined ||
|
|
155
|
+
typeof options.mcpAnnotations.idempotentHint === "boolean")
|
|
154
156
|
? options.mcpAnnotations
|
|
155
157
|
: (() => {
|
|
156
|
-
throw new TypeError("mcpAnnotations must define boolean readOnlyHint, destructiveHint, and openWorldHint values.");
|
|
158
|
+
throw new TypeError("mcpAnnotations must define boolean readOnlyHint, destructiveHint, and openWorldHint values; idempotentHint is an optional boolean.");
|
|
157
159
|
})();
|
|
158
160
|
const deferLoading = typeof options.deferLoading === "boolean"
|
|
159
161
|
? options.deferLoading
|
package/dist/cli/agent.js
CHANGED
|
@@ -8,7 +8,7 @@ import { getAppConfig } from "../app-config/index.js";
|
|
|
8
8
|
import { createGitHubRepoToolEntries } from "../provider-api/github-repo.js";
|
|
9
9
|
import { loadCliBootstrap } from "../scripts/cli-bootstrap.js";
|
|
10
10
|
import { resolveDevUserEmail } from "../scripts/dev-session.js";
|
|
11
|
-
import { loadEnv } from "../scripts/utils.js";
|
|
11
|
+
import { loadEnv, serializeCliArgs } from "../scripts/utils.js";
|
|
12
12
|
import { autoDiscoverActions } from "../server/action-discovery.js";
|
|
13
13
|
import { captureCliOutput } from "../server/cli-capture.js";
|
|
14
14
|
import { getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
@@ -213,16 +213,7 @@ function buildHeadlessSystemPrompt(actionNames) {
|
|
|
213
213
|
.join("\n\n");
|
|
214
214
|
}
|
|
215
215
|
function cliArgsFromToolArgs(args) {
|
|
216
|
-
|
|
217
|
-
for (const [key, value] of Object.entries(args)) {
|
|
218
|
-
if (value === undefined)
|
|
219
|
-
continue;
|
|
220
|
-
const normalized = value != null && typeof value === "object"
|
|
221
|
-
? JSON.stringify(value)
|
|
222
|
-
: String(value);
|
|
223
|
-
cliArgs.push(`--${key}`, normalized);
|
|
224
|
-
}
|
|
225
|
-
return cliArgs;
|
|
216
|
+
return serializeCliArgs(Object.fromEntries(Object.entries(args).filter(([, value]) => value !== undefined)));
|
|
226
217
|
}
|
|
227
218
|
export async function createHeadlessBuiltinActions() {
|
|
228
219
|
const docsSearch = await import("../scripts/docs/search.js");
|
|
@@ -21,6 +21,19 @@ export declare function registerCollabActivityResource(resource: {
|
|
|
21
21
|
resourceType: string;
|
|
22
22
|
resourceId: string;
|
|
23
23
|
}): () => void;
|
|
24
|
+
type CollabActivityEvent = {
|
|
25
|
+
source?: string;
|
|
26
|
+
resourceType?: string;
|
|
27
|
+
resourceId?: string;
|
|
28
|
+
requestSource?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* For a collab connection's own ~12 s poll. A viewer on a screen nobody else
|
|
32
|
+
* is on has no presence to notice, but that poll still carries the design's
|
|
33
|
+
* resource-scoped events from the other screens, and the shared transport is
|
|
34
|
+
* asleep on the 1-5 minute idle cadence until something wakes it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function noteCollabPollActivity(events: readonly CollabActivityEvent[]): void;
|
|
24
37
|
/**
|
|
25
38
|
* Declare that another person is working on the same resource as this tab.
|
|
26
39
|
* While any lease is held, the shared transport polls every 2.5 s whenever no
|
|
@@ -72,11 +72,20 @@ function collabBoostWanted() {
|
|
|
72
72
|
}
|
|
73
73
|
return ((collabBoostLeases > 0 && collabBoostFresh()) || hasRecentResourceActivity);
|
|
74
74
|
}
|
|
75
|
+
// The server mirrors every saved file into its Yjs doc under the "agent"
|
|
76
|
+
// source, so a lone editor's own save comes back as a collab event that is not
|
|
77
|
+
// from anyone else. Only a Yjs update a browser tab posted names its sender.
|
|
78
|
+
function isHumanCollabUpdate(event) {
|
|
79
|
+
return (event.source === "collab" &&
|
|
80
|
+
typeof event.requestSource === "string" &&
|
|
81
|
+
event.requestSource !== "" &&
|
|
82
|
+
event.requestSource !== "agent");
|
|
83
|
+
}
|
|
75
84
|
function noteCollaboratorActivity(events) {
|
|
76
85
|
const ownSource = getBrowserTabId();
|
|
77
86
|
const until = Date.now() + COLLAB_ACTIVITY_WINDOW_MS;
|
|
78
87
|
for (const event of events) {
|
|
79
|
-
if (event.source !== "action" ||
|
|
88
|
+
if ((event.source !== "action" && !isHumanCollabUpdate(event)) ||
|
|
80
89
|
typeof event.resourceType !== "string" ||
|
|
81
90
|
event.resourceType === "" ||
|
|
82
91
|
typeof event.resourceId !== "string" ||
|
|
@@ -89,6 +98,18 @@ function noteCollaboratorActivity(events) {
|
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* For a collab connection's own ~12 s poll. A viewer on a screen nobody else
|
|
103
|
+
* is on has no presence to notice, but that poll still carries the design's
|
|
104
|
+
* resource-scoped events from the other screens, and the shared transport is
|
|
105
|
+
* asleep on the 1-5 minute idle cadence until something wakes it.
|
|
106
|
+
*/
|
|
107
|
+
export function noteCollabPollActivity(events) {
|
|
108
|
+
const wasWanted = collabBoostWanted();
|
|
109
|
+
noteCollaboratorActivity(events);
|
|
110
|
+
if (!wasWanted && collabBoostWanted())
|
|
111
|
+
notifyCollabBoostChange();
|
|
112
|
+
}
|
|
92
113
|
function collabBoostFresh() {
|
|
93
114
|
return Date.now() - collabBoostActivityAt <= COLLAB_BOOST_IDLE_CEILING_MS;
|
|
94
115
|
}
|
package/dist/collab/client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Awareness } from "y-protocols/awareness";
|
|
|
3
3
|
import * as Y from "yjs";
|
|
4
4
|
import { agentNativePath } from "../client/api-path.js";
|
|
5
5
|
import { useAvatarUrl } from "../client/use-avatar.js";
|
|
6
|
-
import { acquireCollabPollBoost, registerCollabActivityResource, subscribeSyncEvents, } from "../client/use-db-sync.js";
|
|
6
|
+
import { acquireCollabPollBoost, noteCollabPollActivity, registerCollabActivityResource, subscribeSyncEvents, } from "../client/use-db-sync.js";
|
|
7
7
|
import { REALTIME_CAP_NO_AWARENESS, REALTIME_CAP_POLL_LIVE, } from "../realtime-protocol.js";
|
|
8
8
|
import { dedupeCollabUsersByEmail } from "./types.js";
|
|
9
9
|
export { dedupeCollabUsersByEmail, emailToColor, emailToName, } from "./types.js";
|
|
@@ -151,6 +151,8 @@ class CollabDocConnection {
|
|
|
151
151
|
pollCycleCount = 0;
|
|
152
152
|
pollVersion = 0;
|
|
153
153
|
lastPolledVersion = 0;
|
|
154
|
+
pollCursor = null;
|
|
155
|
+
pollActivityBaselineReady = false;
|
|
154
156
|
stateVectorFetch = null;
|
|
155
157
|
stateVectorAbortControllers = new Set();
|
|
156
158
|
sseActive = false;
|
|
@@ -415,7 +417,9 @@ class CollabDocConnection {
|
|
|
415
417
|
});
|
|
416
418
|
}
|
|
417
419
|
fetchInitialState() {
|
|
418
|
-
fetch(`${this.baseUrl}/${this.docId}/state
|
|
420
|
+
fetch(`${this.baseUrl}/${this.docId}/state`, {
|
|
421
|
+
headers: { "X-Agent-Native-Poll-Baseline": "1" },
|
|
422
|
+
}).then(async (res) => {
|
|
419
423
|
if (this.disposed)
|
|
420
424
|
return;
|
|
421
425
|
if (res.status === 404 || res.status === 403) {
|
|
@@ -433,6 +437,17 @@ class CollabDocConnection {
|
|
|
433
437
|
this.markInitializationFailed("invalid-payload");
|
|
434
438
|
return;
|
|
435
439
|
}
|
|
440
|
+
const baseline = data.activityBaseline;
|
|
441
|
+
if (baseline?.status === "ready" &&
|
|
442
|
+
Number.isSafeInteger(baseline.version) &&
|
|
443
|
+
baseline.version >= 0 &&
|
|
444
|
+
typeof baseline.cursor === "string" &&
|
|
445
|
+
baseline.cursor.length > 0) {
|
|
446
|
+
this.pollVersion = baseline.version;
|
|
447
|
+
this.lastPolledVersion = baseline.version;
|
|
448
|
+
this.pollCursor = baseline.cursor;
|
|
449
|
+
this.pollActivityBaselineReady = true;
|
|
450
|
+
}
|
|
436
451
|
if (data.state) {
|
|
437
452
|
try {
|
|
438
453
|
const binary = base64ToUint8Array(data.state);
|
|
@@ -807,12 +822,16 @@ class CollabDocConnection {
|
|
|
807
822
|
return;
|
|
808
823
|
this.flushPendingUpdates();
|
|
809
824
|
try {
|
|
810
|
-
const
|
|
825
|
+
const pollUrl = this.pollCursor
|
|
826
|
+
? `/_agent-native/poll?cursor=${encodeURIComponent(this.pollCursor)}`
|
|
827
|
+
: `/_agent-native/poll?since=${this.pollVersion}`;
|
|
828
|
+
const res = await fetch(agentNativePath(pollUrl));
|
|
811
829
|
if (!res.ok)
|
|
812
830
|
throw new Error("HTTP " + res.status);
|
|
813
831
|
const data = await res.json();
|
|
814
832
|
if (!this.syncActive || this.disposed)
|
|
815
833
|
return;
|
|
834
|
+
const hadActivityBaseline = this.pollActivityBaselineReady;
|
|
816
835
|
const { version, events } = data;
|
|
817
836
|
const versionGap = version - this.lastPolledVersion;
|
|
818
837
|
const hadGap = versionGap > POLL_RING_BUFFER_SIZE;
|
|
@@ -832,6 +851,20 @@ class CollabDocConnection {
|
|
|
832
851
|
}
|
|
833
852
|
}
|
|
834
853
|
}
|
|
854
|
+
if (hadActivityBaseline) {
|
|
855
|
+
noteCollabPollActivity(events);
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
const reconciliation = await this.fetchStateVector();
|
|
859
|
+
if (reconciliation.status !== "synced") {
|
|
860
|
+
throw reconciliation.status === "failed"
|
|
861
|
+
? reconciliation.error
|
|
862
|
+
: new Error("Could not reconcile state without an activity baseline");
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
this.pollActivityBaselineReady = true;
|
|
866
|
+
if (typeof data.cursor === "string")
|
|
867
|
+
this.pollCursor = data.cursor;
|
|
835
868
|
this.pollVersion = version;
|
|
836
869
|
this.lastPolledVersion = version;
|
|
837
870
|
this.pollCycleCount++;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
export declare const getCollabState: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
docId?: undefined;
|
|
4
|
-
state?: undefined;
|
|
5
3
|
} | {
|
|
6
4
|
error?: undefined;
|
|
7
5
|
docId: string;
|
|
8
6
|
state: string;
|
|
7
|
+
activityBaseline?: {
|
|
8
|
+
status: "ready";
|
|
9
|
+
version: number;
|
|
10
|
+
cursor: string;
|
|
11
|
+
} | {
|
|
12
|
+
status: "unavailable";
|
|
13
|
+
};
|
|
9
14
|
}>>;
|
|
10
15
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
16
|
ok?: undefined;
|
package/dist/collab/routes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineEventHandler, setResponseStatus, setResponseHeader, getRouterParam, getQuery, } from "h3";
|
|
1
|
+
import { defineEventHandler, setResponseStatus, setResponseHeader, getRouterParam, getQuery, getRequestHeader, } from "h3";
|
|
2
2
|
import { readBody } from "../server/h3-helpers.js";
|
|
3
3
|
import { uint8ArrayToBase64, base64ToUint8Array } from "./storage.js";
|
|
4
4
|
import * as manager from "./ydoc-manager.js";
|
|
@@ -25,6 +25,19 @@ export const getCollabState = defineEventHandler(async (event) => {
|
|
|
25
25
|
}
|
|
26
26
|
const query = getQuery(event);
|
|
27
27
|
const encodedStateVector = typeof query.stateVector === "string" ? query.stateVector : null;
|
|
28
|
+
let activityBaseline;
|
|
29
|
+
if (getRequestHeader(event, "x-agent-native-poll-baseline") === "1") {
|
|
30
|
+
try {
|
|
31
|
+
const { getCurrentPollBaseline } = await import("../server/poll.js");
|
|
32
|
+
activityBaseline = {
|
|
33
|
+
status: "ready",
|
|
34
|
+
...(await getCurrentPollBaseline()),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
activityBaseline = { status: "unavailable" };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
28
41
|
let state;
|
|
29
42
|
if (encodedStateVector) {
|
|
30
43
|
try {
|
|
@@ -41,6 +54,7 @@ export const getCollabState = defineEventHandler(async (event) => {
|
|
|
41
54
|
return {
|
|
42
55
|
docId,
|
|
43
56
|
state: uint8ArrayToBase64(state),
|
|
57
|
+
...(activityBaseline ? { activityBaseline } : {}),
|
|
44
58
|
};
|
|
45
59
|
});
|
|
46
60
|
export const postCollabUpdate = defineEventHandler(async (event) => {
|
package/dist/deploy/build.js
CHANGED
|
@@ -984,6 +984,18 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
984
984
|
{ status: 405, headers: { "Content-Type": "application/json" } }
|
|
985
985
|
);
|
|
986
986
|
}
|
|
987
|
+
const actionSession = ${varName}.requiresAuth === true
|
|
988
|
+
? await getGeneratedSession(event)
|
|
989
|
+
: undefined;
|
|
990
|
+
const actionContext = uiActionContext ?? (actionSession?.email
|
|
991
|
+
? { userEmail: actionSession.email, orgId: actionSession.orgId ?? null }
|
|
992
|
+
: undefined);
|
|
993
|
+
if (${varName}.requiresAuth === true && !actionContext?.userEmail) {
|
|
994
|
+
return new Response(
|
|
995
|
+
JSON.stringify({ error: "Unauthorized" }),
|
|
996
|
+
{ status: 401, headers: { "Content-Type": "application/json" } },
|
|
997
|
+
);
|
|
998
|
+
}
|
|
987
999
|
const params = ${a.method === "get" ? "parseActionSearchParams(event.url.searchParams)" : "(await readBody(event)) ?? {}"};
|
|
988
1000
|
try {
|
|
989
1001
|
const caller =
|
|
@@ -994,16 +1006,11 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
994
1006
|
caller,
|
|
995
1007
|
requestHeaders: event.req.headers,
|
|
996
1008
|
actionName: ${JSON.stringify(a.name)},
|
|
997
|
-
...(
|
|
998
|
-
? {
|
|
999
|
-
userEmail: uiActionContext.userEmail,
|
|
1000
|
-
orgId: uiActionContext.orgId ?? null,
|
|
1001
|
-
}
|
|
1002
|
-
: {}),
|
|
1009
|
+
...(actionContext ?? {}),
|
|
1003
1010
|
};
|
|
1004
1011
|
const runAction = () => ${varName}.run(params, actionRunContext);
|
|
1005
|
-
const result =
|
|
1006
|
-
? await runWithGeneratedRequestContext(
|
|
1012
|
+
const result = actionContext
|
|
1013
|
+
? await runWithGeneratedRequestContext(actionContext, runAction)
|
|
1007
1014
|
: await runAction();
|
|
1008
1015
|
if (typeof result === "string") { try { return JSON.parse(result); } catch { return result; } }
|
|
1009
1016
|
return result;
|
|
@@ -64,19 +64,97 @@ function builtinAgentsEnvSnippet() {
|
|
|
64
64
|
`;
|
|
65
65
|
}
|
|
66
66
|
function workspaceDirectoryEnvSnippet(workspaceApps) {
|
|
67
|
-
const
|
|
68
|
-
|
|
67
|
+
const configuredOrgDirectoryUrl = getAppConfig().workspace.orgDirectoryUrl?.trim();
|
|
68
|
+
const dispatchApp = workspaceApps.find((app) => app.isDispatch);
|
|
69
|
+
if (!configuredOrgDirectoryUrl && !dispatchApp) {
|
|
69
70
|
return builtinAgentsEnvSnippet();
|
|
70
71
|
}
|
|
72
|
+
const runtimeDirectoryResolver = dispatchApp
|
|
73
|
+
? `
|
|
74
|
+
function logInvalidDirectoryBase() {
|
|
75
|
+
const logKey = Symbol.for("agent-native.workspace.invalid-directory-base");
|
|
76
|
+
if (globalThis[logKey]) return;
|
|
77
|
+
globalThis[logKey] = true;
|
|
78
|
+
console.error("[workspace] Invalid organization directory base URL");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolveRuntimeDirectoryUrl() {
|
|
82
|
+
const isVercelProduction =
|
|
83
|
+
processRef.env.VERCEL_ENV?.trim().toLowerCase() === "production";
|
|
84
|
+
const vercelCandidates = processRef.env.VERCEL
|
|
85
|
+
? (isVercelProduction
|
|
86
|
+
? [
|
|
87
|
+
processRef.env.VERCEL_PROJECT_PRODUCTION_URL,
|
|
88
|
+
processRef.env.VERCEL_URL,
|
|
89
|
+
processRef.env.VERCEL_BRANCH_URL,
|
|
90
|
+
]
|
|
91
|
+
: [processRef.env.VERCEL_URL, processRef.env.VERCEL_BRANCH_URL]
|
|
92
|
+
)
|
|
93
|
+
.filter(Boolean)
|
|
94
|
+
.map((candidate) =>
|
|
95
|
+
/^https?:\\/\\//i.test(candidate)
|
|
96
|
+
? candidate
|
|
97
|
+
: "https://" + candidate,
|
|
98
|
+
)
|
|
99
|
+
: [];
|
|
100
|
+
const candidates = [
|
|
101
|
+
processRef.env.APP_URL,
|
|
102
|
+
processRef.env.URL,
|
|
103
|
+
processRef.env.DEPLOY_URL,
|
|
104
|
+
processRef.env.BETTER_AUTH_URL,
|
|
105
|
+
...vercelCandidates,
|
|
106
|
+
processRef.env.WORKSPACE_GATEWAY_URL,
|
|
107
|
+
processRef.env.VITE_WORKSPACE_GATEWAY_URL,
|
|
108
|
+
].filter(Boolean);
|
|
109
|
+
let loopbackUrl;
|
|
110
|
+
for (const candidate of candidates) {
|
|
111
|
+
let baseUrl;
|
|
112
|
+
try {
|
|
113
|
+
baseUrl = new URL(candidate);
|
|
114
|
+
} catch {
|
|
115
|
+
logInvalidDirectoryBase();
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
|
|
119
|
+
logInvalidDirectoryBase();
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const directoryUrl = new URL(${JSON.stringify(dispatchApp.path)}, baseUrl)
|
|
123
|
+
.toString()
|
|
124
|
+
.replace(/\\/$/, "");
|
|
125
|
+
const hostname = baseUrl.hostname.toLowerCase().replace(/\\.$/, "");
|
|
126
|
+
const mappedIpv4 = hostname.match(
|
|
127
|
+
/^\\[::ffff:([0-9a-f]{1,4}):[0-9a-f]{1,4}\\]$/,
|
|
128
|
+
);
|
|
129
|
+
const isMappedIpv4Loopback =
|
|
130
|
+
mappedIpv4 !== null &&
|
|
131
|
+
(Number.parseInt(mappedIpv4[1], 16) >> 8) === 0x7f;
|
|
132
|
+
if (
|
|
133
|
+
hostname === "localhost" ||
|
|
134
|
+
hostname.endsWith(".localhost") ||
|
|
135
|
+
/^127(?:\\.\\d{1,3}){3}$/.test(hostname) ||
|
|
136
|
+
/^0(?:\\.\\d{1,3}){3}$/.test(hostname) ||
|
|
137
|
+
hostname === "[::1]" ||
|
|
138
|
+
hostname === "::1" ||
|
|
139
|
+
hostname === "[::]" ||
|
|
140
|
+
hostname === "::" ||
|
|
141
|
+
isMappedIpv4Loopback
|
|
142
|
+
) {
|
|
143
|
+
loopbackUrl ??= directoryUrl;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
return directoryUrl;
|
|
147
|
+
}
|
|
148
|
+
return loopbackUrl ?? null;
|
|
149
|
+
}
|
|
150
|
+
`
|
|
151
|
+
: "";
|
|
71
152
|
return `${builtinAgentsEnvSnippet()}
|
|
153
|
+
${runtimeDirectoryResolver}
|
|
72
154
|
const directoryOrigin =
|
|
73
155
|
processRef.env.AGENT_NATIVE_ORG_DIRECTORY_URL ||
|
|
74
|
-
${JSON.stringify(
|
|
75
|
-
|
|
76
|
-
processRef.env.APP_URL ||
|
|
77
|
-
processRef.env.URL ||
|
|
78
|
-
processRef.env.DEPLOY_URL ||
|
|
79
|
-
processRef.env.BETTER_AUTH_URL;
|
|
156
|
+
${JSON.stringify(configuredOrgDirectoryUrl ?? null)} ||
|
|
157
|
+
${dispatchApp ? "resolveRuntimeDirectoryUrl()" : "null"};
|
|
80
158
|
if (directoryOrigin) {
|
|
81
159
|
processRef.env.AGENT_NATIVE_ORG_DIRECTORY_URL = directoryOrigin;
|
|
82
160
|
}
|
|
@@ -167,11 +245,8 @@ function buildOneApp(workspaceRoot, appsDir, app, preset, execFile, workspaceApp
|
|
|
167
245
|
const appDir = path.join(appsDir, app);
|
|
168
246
|
const workspaceAppAudience = workspaceAppAudienceForApp(workspaceApps, app);
|
|
169
247
|
const workspaceAppRouteAccess = workspaceAppRouteAccessForApp(workspaceApps, app);
|
|
170
|
-
const workspaceGatewayUrl =
|
|
171
|
-
const orgDirectoryUrl = getAppConfig().workspace.orgDirectoryUrl?.trim()
|
|
172
|
-
(workspaceApps.some((entry) => entry.isDispatch)
|
|
173
|
-
? workspaceGatewayUrl
|
|
174
|
-
: null);
|
|
248
|
+
const workspaceGatewayUrl = workspaceBaseUrl();
|
|
249
|
+
const orgDirectoryUrl = getAppConfig().workspace.orgDirectoryUrl?.trim();
|
|
175
250
|
const workspaceOAuthUrl = workspaceOAuthOrigin(workspaceGatewayUrl);
|
|
176
251
|
const frameworkRoutePrefix = workspaceFrameworkRoutePrefixEnv();
|
|
177
252
|
const env = {
|
|
@@ -11,9 +11,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
11
11
|
enabled?: undefined;
|
|
12
12
|
nextRun?: undefined;
|
|
13
13
|
} | {
|
|
14
|
+
deleted?: undefined;
|
|
14
15
|
name: string;
|
|
15
16
|
enabled: boolean;
|
|
16
17
|
nextRun: string;
|
|
17
|
-
deleted?: undefined;
|
|
18
18
|
}>;
|
|
19
19
|
export default _default;
|
package/dist/mcp/build-server.js
CHANGED
|
@@ -1937,15 +1937,18 @@ export async function createMCPServerForRequest(config, identity, requestMeta) {
|
|
|
1937
1937
|
entry.tool.description ??
|
|
1938
1938
|
name;
|
|
1939
1939
|
const title = agentNativeToolTitle(name, entry.tool.title);
|
|
1940
|
-
const annotations =
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1940
|
+
const annotations = {
|
|
1941
|
+
title,
|
|
1942
|
+
...(entry.mcpAnnotations ??
|
|
1943
|
+
(directoryCatalog
|
|
1944
|
+
? undefined
|
|
1945
|
+
: {
|
|
1946
|
+
readOnlyHint: entry.readOnly === true,
|
|
1947
|
+
destructiveHint: entry.publicAgent?.isConsequential === true ||
|
|
1948
|
+
entry.needsApproval !== undefined,
|
|
1949
|
+
openWorldHint: false,
|
|
1950
|
+
})),
|
|
1951
|
+
};
|
|
1949
1952
|
if (directoryCatalog) {
|
|
1950
1953
|
delete annotations["agent-native/producesOpenLink"];
|
|
1951
1954
|
}
|
|
@@ -5,6 +5,7 @@ import { CredentialStoreUnavailableError, resolveSecretPairs, } from "../server/
|
|
|
5
5
|
import { getH3App } from "../server/framework-request-handler.js";
|
|
6
6
|
import { canonicalFrameworkPathname } from "../server/framework-route-prefix.js";
|
|
7
7
|
import { getAppBasePath, getAppUrl, encodeOAuthState, oauthErrorPage, resolveOAuthRedirectUri, } from "../server/google-oauth.js";
|
|
8
|
+
import { queryEchoSafeRedirect } from "../server/query-echo-safe-redirect.js";
|
|
8
9
|
import { runWithRequestContext } from "../server/request-context.js";
|
|
9
10
|
import { isWorkspaceOAuthCallbackRelayEnabled } from "../server/workspace-oauth.js";
|
|
10
11
|
import { MCP_OAUTH_FLOW_TTL_SECONDS } from "../shared/mcp-oauth-flow-ttl.js";
|
|
@@ -491,7 +492,7 @@ async function handleMcpOAuthCallback(event, options) {
|
|
|
491
492
|
console.warn("[mcp-client/oauth] saved server did not reconnect:", error);
|
|
492
493
|
}
|
|
493
494
|
const returnPath = resolveMcpOAuthReturnPath(connected, flow);
|
|
494
|
-
return redirectWithStagedCookies(event, getAppUrl(event, stripMcpOAuthAppBasePath(returnPath, getAppBasePath())));
|
|
495
|
+
return queryEchoSafeRedirect(event, redirectWithStagedCookies(event, getAppUrl(event, stripMcpOAuthAppBasePath(returnPath, getAppBasePath()))));
|
|
495
496
|
}
|
|
496
497
|
export function setMcpOAuthFlowCookie(event, flow, secure) {
|
|
497
498
|
const encrypted = encryptSecretValue(JSON.stringify(flow));
|
|
@@ -27,38 +27,38 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
27
27
|
thumbsUpRate: number;
|
|
28
28
|
avgEvalScore: number;
|
|
29
29
|
} | {
|
|
30
|
-
ok?: undefined;
|
|
31
30
|
error: string;
|
|
32
31
|
message: string;
|
|
33
32
|
summary?: undefined;
|
|
34
33
|
spans?: undefined;
|
|
35
34
|
id?: undefined;
|
|
36
|
-
} | {
|
|
37
|
-
error?: undefined;
|
|
38
35
|
ok?: undefined;
|
|
36
|
+
} | {
|
|
39
37
|
message?: undefined;
|
|
40
38
|
summary: import("./types.js").TraceSummary;
|
|
41
39
|
spans: import("./types.js").TraceSpan[];
|
|
42
40
|
id?: undefined;
|
|
43
|
-
} | {
|
|
44
41
|
error?: undefined;
|
|
45
42
|
ok?: undefined;
|
|
43
|
+
} | {
|
|
46
44
|
message?: undefined;
|
|
47
45
|
summary?: undefined;
|
|
48
46
|
spans?: undefined;
|
|
49
47
|
id: string;
|
|
50
|
-
|
|
48
|
+
error?: undefined;
|
|
51
49
|
ok?: undefined;
|
|
50
|
+
} | {
|
|
52
51
|
message?: undefined;
|
|
53
52
|
summary?: undefined;
|
|
54
53
|
spans?: undefined;
|
|
55
54
|
id?: undefined;
|
|
56
55
|
error: any;
|
|
56
|
+
ok?: undefined;
|
|
57
57
|
} | {
|
|
58
|
-
error?: undefined;
|
|
59
58
|
message?: undefined;
|
|
60
59
|
summary?: undefined;
|
|
61
60
|
spans?: undefined;
|
|
62
61
|
id?: undefined;
|
|
62
|
+
error?: undefined;
|
|
63
63
|
ok: boolean;
|
|
64
64
|
}>>;
|
|
@@ -75,8 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
message?: undefined;
|
|
79
78
|
deleted?: undefined;
|
|
79
|
+
message?: undefined;
|
|
80
80
|
found?: undefined;
|
|
81
81
|
providers: {
|
|
82
82
|
id: string;
|
|
@@ -93,8 +93,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
93
93
|
id?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
message?: undefined;
|
|
97
96
|
deleted?: undefined;
|
|
97
|
+
message?: undefined;
|
|
98
98
|
providers?: undefined;
|
|
99
99
|
count?: undefined;
|
|
100
100
|
found: boolean;
|
|
@@ -103,8 +103,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
103
103
|
id?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
message?: undefined;
|
|
107
106
|
deleted?: undefined;
|
|
107
|
+
message?: undefined;
|
|
108
108
|
providers?: undefined;
|
|
109
109
|
count?: undefined;
|
|
110
110
|
provider?: undefined;
|
|
@@ -2,6 +2,7 @@ import { createCodingToolRegistry } from "../../coding-tools/index.js";
|
|
|
2
2
|
import { getRequestRunContext } from "../../server/request-context.js";
|
|
3
3
|
import { normalizeDatabaseToolsMode, } from "../db/tool-mode.js";
|
|
4
4
|
import { dbExecToolParameters } from "../db/tool-schemas.js";
|
|
5
|
+
import { serializeCliArgs } from "../parse-args.js";
|
|
5
6
|
import { tool as listFilesTool, run as listFilesRun } from "./list-files.js";
|
|
6
7
|
import { tool as readFileTool, run as readFileRun } from "./read-file.js";
|
|
7
8
|
import { tool as searchFilesTool, run as searchFilesRun, } from "./search-files.js";
|
|
@@ -12,14 +13,7 @@ function wrapCliScript(tool, cliDefault, opts) {
|
|
|
12
13
|
tool,
|
|
13
14
|
...(opts?.readOnly ? { readOnly: true } : {}),
|
|
14
15
|
run: async (args) => {
|
|
15
|
-
const cliArgs =
|
|
16
|
-
for (const [k, v] of Object.entries(args)) {
|
|
17
|
-
const raw = v;
|
|
18
|
-
const value = raw != null && typeof raw === "object"
|
|
19
|
-
? JSON.stringify(raw)
|
|
20
|
-
: String(raw);
|
|
21
|
-
cliArgs.push(`--${k}`, value);
|
|
22
|
-
}
|
|
16
|
+
const cliArgs = serializeCliArgs(args);
|
|
23
17
|
const logs = [];
|
|
24
18
|
const origLog = console.log;
|
|
25
19
|
console.log = (...a) => {
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export declare function parseArgs(args: string[]): Record<string, string>;
|
|
2
|
+
export declare function serializeCliArgs(args: Record<string, unknown>): string[];
|
|
3
|
+
type NormalizeShellArgsOptions = {
|
|
4
|
+
backslashEscapes?: boolean;
|
|
5
|
+
splitAllWhitespace?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function normalizeShellArgs(input: string, options?: NormalizeShellArgsOptions): string[];
|
|
2
8
|
export declare function camelCaseArgs(args: Record<string, string>): Record<string, string>;
|
|
9
|
+
export {};
|