@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.
Files changed (51) hide show
  1. package/dist/action.d.ts +1 -0
  2. package/dist/action.js +4 -2
  3. package/dist/cli/agent.js +2 -11
  4. package/dist/client/use-db-sync.d.ts +13 -0
  5. package/dist/client/use-db-sync.js +22 -1
  6. package/dist/collab/client.js +36 -3
  7. package/dist/collab/routes.d.ts +7 -2
  8. package/dist/collab/routes.js +15 -1
  9. package/dist/collab/struct-routes.d.ts +1 -1
  10. package/dist/deploy/build.js +15 -8
  11. package/dist/deploy/workspace-deploy.js +88 -13
  12. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  13. package/dist/mcp/actions/create-org-service-token.js +1 -0
  14. package/dist/mcp/build-server.js +12 -9
  15. package/dist/mcp-client/oauth-routes.js +2 -1
  16. package/dist/notifications/routes.d.ts +1 -1
  17. package/dist/observability/routes.d.ts +6 -6
  18. package/dist/progress/routes.d.ts +1 -1
  19. package/dist/provider-api/actions/custom-provider-registration.d.ts +3 -3
  20. package/dist/scripts/dev/index.js +2 -8
  21. package/dist/scripts/parse-args.d.ts +7 -0
  22. package/dist/scripts/parse-args.js +76 -0
  23. package/dist/scripts/utils.d.ts +1 -1
  24. package/dist/scripts/utils.js +1 -1
  25. package/dist/secrets/routes.d.ts +11 -11
  26. package/dist/server/action-discovery.js +4 -42
  27. package/dist/server/agent-chat/script-entries.js +3 -8
  28. package/dist/server/agent-chat-plugin.js +8 -42
  29. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  30. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  31. package/dist/server/auth.js +5 -2
  32. package/dist/server/google-oauth.js +8 -4
  33. package/dist/server/identity-sso.js +2 -1
  34. package/dist/server/index.d.ts +1 -0
  35. package/dist/server/index.js +1 -0
  36. package/dist/server/poll.d.ts +9 -0
  37. package/dist/server/poll.js +86 -7
  38. package/dist/server/query-echo-safe-redirect.d.ts +10 -0
  39. package/dist/server/query-echo-safe-redirect.js +102 -0
  40. package/dist/server/workspace-provider-oauth.js +2 -1
  41. package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -0
  42. package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -0
  43. package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -0
  44. package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -0
  45. package/dist/triggers/actions/manage-automation.d.ts +7 -7
  46. package/docs/content/external-agents-catalog.mdx +19 -0
  47. package/package.json +4 -4
  48. package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -0
  49. package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -0
  50. package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -0
  51. 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
- const cliArgs = [];
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
  }
@@ -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`).then(async (res) => {
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 res = await fetch(agentNativePath(`/_agent-native/poll?since=${this.pollVersion}`));
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++;
@@ -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;
@@ -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) => {
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- ok?: undefined;
3
2
  error: string;
3
+ ok?: undefined;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -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
- ...(uiActionContext
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 = actionIsUiOnly
1006
- ? await runWithGeneratedRequestContext(uiActionContext, runAction)
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 orgDirectoryUrl = getAppConfig().workspace.orgDirectoryUrl?.trim();
68
- if (!orgDirectoryUrl && !workspaceApps.some((app) => app.isDispatch)) {
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(orgDirectoryUrl ?? null)} ||
75
- processRef.env.WORKSPACE_GATEWAY_URL ||
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 = process.env.VITE_WORKSPACE_GATEWAY_URL || workspaceBaseUrl();
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;
@@ -54,6 +54,7 @@ export default defineAction({
54
54
  purpose: purposeSchema.optional(),
55
55
  allowedActions: allowedActionsSchema.nullable().optional(),
56
56
  }),
57
+ requiresAuth: true,
57
58
  toolCallable: false,
58
59
  audit: orgAdminAudit({
59
60
  targetType: "service-principal",
@@ -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 = directoryCatalog
1941
- ? { title, ...entry.mcpAnnotations }
1942
- : {
1943
- title,
1944
- readOnlyHint: entry.readOnly === true,
1945
- destructiveHint: entry.publicAgent?.isConsequential === true ||
1946
- entry.needsApproval !== undefined,
1947
- openWorldHint: false,
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));
@@ -16,6 +16,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  } | {
17
17
  count?: undefined;
18
18
  updated?: undefined;
19
- error?: undefined;
20
19
  ok: boolean;
20
+ error?: undefined;
21
21
  }>>;
@@ -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
  }>>;
@@ -2,6 +2,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
2
2
  error: string;
3
3
  ok?: undefined;
4
4
  } | {
5
- error?: undefined;
6
5
  ok: boolean;
6
+ error?: undefined;
7
7
  }>>;
@@ -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 {};