@agent-native/core 0.172.4 → 0.172.6

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 (30) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/factory/AGENTS.md +5 -3
  3. package/corpus/templates/factory/actions/babysit-pull-request.ts +6 -0
  4. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -2
  5. package/corpus/templates/factory/actions/save-factory-automation.ts +0 -5
  6. package/corpus/templates/factory/changelog/2026-08-24-slack-checking-works-for-teammate-created-factories.md +6 -0
  7. package/corpus/templates/factory/changelog/2026-08-24-teammates-can-edit-and-run-factory-jobs.md +6 -0
  8. package/corpus/templates/factory/server/lib/factory-scope.ts +8 -0
  9. package/corpus/templates/factory/server/lib/require-factory-automation.ts +1 -9
  10. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +2 -1
  11. package/dist/automations/service.d.ts +6 -0
  12. package/dist/automations/service.js +20 -0
  13. package/dist/client/settings/SettingsPanel.js +80 -33
  14. package/dist/collab/awareness.d.ts +2 -2
  15. package/dist/jobs/run-now.js +2 -2
  16. package/dist/observability/routes.d.ts +3 -3
  17. package/dist/progress/routes.d.ts +1 -1
  18. package/dist/resources/handlers.d.ts +1 -1
  19. package/dist/server/realtime-token.d.ts +1 -1
  20. package/dist/server/transcribe-voice.d.ts +1 -1
  21. package/dist/vite/client.js +5 -2
  22. package/docs/content/docs-components.mdx +20 -1
  23. package/docs/content/template-calendar-agent.mdx +63 -26
  24. package/docs/content/template-calendar-developers.mdx +165 -40
  25. package/docs/content/template-calendar-features.mdx +276 -0
  26. package/docs/content/template-calendar-integrations.mdx +78 -0
  27. package/docs/content/template-calendar.mdx +56 -123
  28. package/package.json +3 -3
  29. package/docs/content/template-calendar-booking-links.mdx +0 -73
  30. package/docs/content/template-calendar-scheduling.mdx +0 -128
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 8592
34
+ - template files: 8594
@@ -76,9 +76,11 @@ decisions, feedback, agent runs, and provider audit records.
76
76
 
77
77
  Rules start in shadow mode; hard guards apply. Organization automations use
78
78
  stored prompts; external mutations require durable, idempotent runs and
79
- provider confirmation. Use the visual editor for graph changes and agent chat
80
- for proposals; persist complete graphs with `save-factory-graph`. Change rules
81
- through triage actions, never graph JSON.
79
+ provider confirmation. Poll and Builder/PR dispatch run only as this factory's
80
+ scheduled job, not chat and not a workspace-owner email match; teammates may
81
+ edit and Run now Factory jobs. Use the visual editor for graph changes and
82
+ agent chat for proposals; persist complete graphs with `save-factory-graph`.
83
+ Change rules through triage actions, never graph JSON.
82
84
 
83
85
  ## Source Changes
84
86
 
@@ -2,6 +2,7 @@ import { defineAction } from "@agent-native/core/action";
2
2
  import { z } from "zod";
3
3
 
4
4
  import { resolveConnectorSecret } from "../server/connectors/credentials.js";
5
+ import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
5
6
  import {
6
7
  requireWorkspaceMember,
7
8
  workspaceMemberIdentityFromContext,
@@ -106,6 +107,11 @@ export function createBabysitPullRequestAction(
106
107
  const { userEmail, orgId } = await requireWorkspaceMember(
107
108
  workspaceMemberIdentityFromContext(context),
108
109
  );
110
+ await requireFactoryAutomation(
111
+ context,
112
+ { userEmail, orgId },
113
+ "prBabysit",
114
+ );
109
115
  const { comments, truncated } = await fetchComments({
110
116
  repo: input.repo,
111
117
  pullRequestNumber: input.pullRequestNumber,
@@ -47,7 +47,7 @@ export default defineAction({
47
47
  factoryId,
48
48
  );
49
49
  return Promise.all(
50
- scoped.map(async ({ resource, name, meta, body, canUpdate }) => {
50
+ scoped.map(async ({ resource, name, meta, body }) => {
51
51
  const runs = await listAutomationRuns({
52
52
  owners: [resource.owner],
53
53
  automation: automationRunHistoryKey(resource.path),
@@ -72,7 +72,7 @@ export default defineAction({
72
72
  Number.isFinite(resource.updatedAt) && resource.updatedAt > 0
73
73
  ? new Date(resource.updatedAt).toISOString()
74
74
  : null,
75
- canUpdate,
75
+ canUpdate: true,
76
76
  runs: runs.filter((run) => run.path === resource.path),
77
77
  };
78
78
  }),
@@ -76,11 +76,6 @@ export default defineAction({
76
76
  "Factory automation id and name do not refer to the same automation.",
77
77
  );
78
78
  }
79
- if (!definition.canUpdate) {
80
- throw new Error(
81
- "Only the automation's creator or an organization admin can update it.",
82
- );
83
- }
84
79
  if (definition.meta.triggerType === "schedule" && !isValidCron(schedule)) {
85
80
  throw new Error(`Invalid cron expression "${schedule}".`);
86
81
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-24
4
+ ---
5
+
6
+ Slack checking now works for factories created by someone other than the deploy owner.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-24
4
+ ---
5
+
6
+ Workspace teammates can edit and run Factory jobs, not only the person who created them.
@@ -352,6 +352,14 @@ export function resolveAutomationDisplayName(
352
352
  return readAutomationDisplayName(content) ?? automationName;
353
353
  }
354
354
 
355
+ export function assignCreatedByIfMissing(
356
+ content: string,
357
+ createdBy: string,
358
+ ): string {
359
+ if (readFrontmatterField(content, "createdBy")) return content;
360
+ return setAutomationFrontmatterField(content, "createdBy", createdBy);
361
+ }
362
+
355
363
  export function setAutomationFrontmatterField(
356
364
  content: string,
357
365
  key: string,
@@ -25,12 +25,6 @@ const FACTORY_AUTOMATION_NAMES = {
25
25
 
26
26
  export type FactoryAutomationRole = keyof typeof FACTORY_AUTOMATION_NAMES;
27
27
 
28
- function workspaceOwnerEmail(): string | undefined {
29
- const email = process.env.WORKSPACE_OWNER_EMAIL?.trim().toLowerCase(); // guard:allow-env-credential - deployment owner identity, not a user credential
30
- if (!email || /[\r\n]/.test(email)) return undefined;
31
- return email;
32
- }
33
-
34
28
  export async function requireFactoryAutomation(
35
29
  context: ActionRunContext | undefined,
36
30
  identity: Pick<WorkspaceMemberIdentity, "userEmail" | "orgId">,
@@ -61,15 +55,13 @@ export async function requireFactoryAutomation(
61
55
  "organization",
62
56
  )
63
57
  ).find((entry) => entry.resource.id === lineage.triggerId);
64
- const ownerEmail = workspaceOwnerEmail();
65
58
  if (
66
59
  !definition ||
67
60
  definition.name !== lineage.triggerName ||
68
61
  definition.meta.domain !== "factory" ||
69
62
  definition.meta.orgId !== identity.orgId ||
70
63
  definition.meta.runAs !== "creator" ||
71
- !ownerEmail ||
72
- definition.meta.createdBy?.trim().toLowerCase() !== ownerEmail
64
+ !definition.meta.createdBy?.trim()
73
65
  ) {
74
66
  throw new Error(
75
67
  "The action was not invoked by a governed Factory automation.",
@@ -21,6 +21,7 @@ import { triageConfig } from "../db/schema.js";
21
21
  import { repairFactoryAutomationsFromConfig } from "../lib/factory-automation-repair.js";
22
22
  import {
23
23
  DEFAULT_FACTORY_ID,
24
+ assignCreatedByIfMissing,
24
25
  factoryAutomationJobPath,
25
26
  factoryConfigRowId,
26
27
  patchAutomationResource,
@@ -541,7 +542,7 @@ export async function ensureFactoryAutomations(
541
542
  repaired = setFrontmatterField(repaired, "appId", "factory");
542
543
  repaired = setFrontmatterField(repaired, "orgId", orgId);
543
544
  repaired = setFrontmatterField(repaired, "factoryId", factoryId);
544
- repaired = setFrontmatterField(repaired, "createdBy", ownerEmail);
545
+ repaired = assignCreatedByIfMissing(repaired, ownerEmail);
545
546
  repaired = setFrontmatterField(repaired, "runAs", "creator");
546
547
  if (!frontmatterField(repaired, "model")) {
547
548
  repaired = setFrontmatterField(repaired, "model", seed.model);
@@ -67,6 +67,12 @@ export interface UpdateAutomationInput {
67
67
  * automation classifier.
68
68
  */
69
69
  export declare function canUpdateAutomationResource(actorInput: AutomationActor, resource: Resource): Promise<boolean>;
70
+ /**
71
+ * Factory is a shared team workspace: any current org member may queue Run now
72
+ * for that app's Factory-domain org jobs. Mail/CRM and other automations stay
73
+ * on creator-or-admin `canUpdate`.
74
+ */
75
+ export declare function canQueueAutomationRunNow(actorInput: AutomationActor, resource: Resource, scope: AutomationScope): Promise<boolean>;
70
76
  export declare function listAutomationDefinitions(actorInput: AutomationActor, scope: AutomationScope): Promise<AutomationDefinition[]>;
71
77
  export declare function defineAutomation(actorInput: AutomationActor, input: DefineAutomationInput): Promise<DefinedAutomation>;
72
78
  export declare function updateAutomation(actorInput: AutomationActor, input: UpdateAutomationInput): Promise<AutomationDefinition>;
@@ -108,6 +108,26 @@ export async function canUpdateAutomationResource(actorInput, resource) {
108
108
  return false;
109
109
  return (await mutationAccess(actor, resource, meta)).canUpdate;
110
110
  }
111
+ /**
112
+ * Factory is a shared team workspace: any current org member may queue Run now
113
+ * for that app's Factory-domain org jobs. Mail/CRM and other automations stay
114
+ * on creator-or-admin `canUpdate`.
115
+ */
116
+ export async function canQueueAutomationRunNow(actorInput, resource, scope) {
117
+ const { meta } = parseJobResource(resource.content);
118
+ const actor = normalizeActor(actorInput);
119
+ if (!jobBelongsToApp(meta, actor.appId))
120
+ return false;
121
+ const access = await mutationAccess(actor, resource, meta);
122
+ if (access.canUpdate)
123
+ return true;
124
+ const resourceOrgId = organizationIdFromResourceOwner(resource.owner);
125
+ return (scope === "organization" &&
126
+ Boolean(resourceOrgId) &&
127
+ actor.orgId === resourceOrgId &&
128
+ actor.appId === "factory" &&
129
+ meta.domain === "factory");
130
+ }
111
131
  function assertExplicitAutomation(resource) {
112
132
  const parsed = parseJobResource(resource.content);
113
133
  if (parsed.classification.kind !== "automation") {
@@ -12,6 +12,7 @@ import { AgentWorkspaceContent } from "../agent-page/AgentWorkspaceContent.js";
12
12
  import { AGENT_PROVIDER_CATALOG, getAgentProviderOption, providerIdForEngine, } from "../agent-provider-catalog.js";
13
13
  import { agentNativePath } from "../api-path.js";
14
14
  import { BuilderBMark } from "../builder-mark.js";
15
+ import { fetchAgentEngineStatus, fetchEnvironmentStatus, } from "../client-status-requests.js";
15
16
  import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
16
17
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
17
18
  import { useT } from "../i18n.js";
@@ -332,7 +333,7 @@ const PROVIDER_DOCS = {
332
333
  "ai-sdk:mistral": "https://console.mistral.ai/api-keys/",
333
334
  "ai-sdk:cohere": "https://dashboard.cohere.com/api-keys",
334
335
  };
335
- function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, orgName, envManaged, credentialSource, grouped = false, open, onToggle, }) {
336
+ function LLMSectionInner({ builderFlow, builderLoading, builderStatusAvailable, connectUrl, connected, orgName, envManaged, credentialSource, grouped = false, open, onToggle, }) {
336
337
  const isPage = useSettingsSurface() === "page";
337
338
  const t = useT();
338
339
  const [envKeys, setEnvKeys] = useState([]);
@@ -354,24 +355,40 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
354
355
  const [testResult, setTestResult] = useState(null);
355
356
  const [settingsStatus, setSettingsStatus] = useState(null);
356
357
  const [disconnectError, setDisconnectError] = useState(null);
357
- const [envLoaded, setEnvLoaded] = useState(false);
358
+ const [envProbeAvailable, setEnvProbeAvailable] = useState(false);
358
359
  const [enginesLoaded, setEnginesLoaded] = useState(false);
359
- const [statusLoaded, setStatusLoaded] = useState(false);
360
- const initialLoading = !envLoaded || !enginesLoaded || !statusLoaded || !!builderLoading;
361
- useEffect(() => {
362
- fetch(agentNativePath("/_agent-native/env-status"))
363
- .then((r) => (r.ok ? r.json() : []))
364
- .then(setEnvKeys)
365
- .catch(() => { })
366
- .finally(() => setEnvLoaded(true));
367
- }, [saved]);
360
+ const [statusProbeAvailable, setStatusProbeAvailable] = useState(false);
361
+ const probeGenerationRef = useRef({ env: 0, status: 0 });
362
+ const initialLoading = !enginesLoaded || !!builderLoading;
363
+ const refreshEnvKeys = useCallback(() => {
364
+ const generation = ++probeGenerationRef.current.env;
365
+ setEnvProbeAvailable(false);
366
+ setEnvKeys([]);
367
+ void fetchEnvironmentStatus().then((result) => {
368
+ if (generation !== probeGenerationRef.current.env)
369
+ return;
370
+ if (result.state !== "available" || !Array.isArray(result.value)) {
371
+ return;
372
+ }
373
+ setEnvKeys(result.value);
374
+ setEnvProbeAvailable(true);
375
+ });
376
+ }, []);
368
377
  const notifyConfigChanged = useCallback(() => {
369
378
  window.dispatchEvent(new CustomEvent("agent-engine:configured-changed"));
370
379
  }, []);
371
380
  const refreshSettingsStatus = useCallback(() => {
372
- fetch(agentNativePath("/_agent-native/agent-engine/status"))
373
- .then((r) => (r.ok ? r.json() : null))
374
- .then((data) => {
381
+ const generation = ++probeGenerationRef.current.status;
382
+ setStatusProbeAvailable(false);
383
+ setSettingsStatus(null);
384
+ setBaseUrlConfigured(false);
385
+ void fetchAgentEngineStatus()
386
+ .then((result) => {
387
+ if (generation !== probeGenerationRef.current.status)
388
+ return;
389
+ if (result.state !== "available")
390
+ return;
391
+ const data = result.value;
375
392
  setBaseUrlConfigured(Boolean(data?.openAiBaseUrlConfigured));
376
393
  if (data?.configured &&
377
394
  typeof data.engine === "string" &&
@@ -387,13 +404,34 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
387
404
  else {
388
405
  setSettingsStatus(null);
389
406
  }
407
+ setStatusProbeAvailable(true);
390
408
  })
391
- .catch(() => { })
392
- .finally(() => setStatusLoaded(true));
409
+ .catch(() => { });
393
410
  }, []);
411
+ useEffect(() => {
412
+ refreshEnvKeys();
413
+ }, [refreshEnvKeys]);
394
414
  useEffect(() => {
395
415
  refreshSettingsStatus();
396
416
  }, [refreshSettingsStatus]);
417
+ useEffect(() => {
418
+ const refresh = () => {
419
+ refreshEnvKeys();
420
+ refreshSettingsStatus();
421
+ };
422
+ window.addEventListener("agent-engine:configured-changed", refresh);
423
+ window.addEventListener("focus", refresh);
424
+ const onVisibilityChange = () => {
425
+ if (document.visibilityState === "visible")
426
+ refresh();
427
+ };
428
+ document.addEventListener("visibilitychange", onVisibilityChange);
429
+ return () => {
430
+ window.removeEventListener("agent-engine:configured-changed", refresh);
431
+ window.removeEventListener("focus", refresh);
432
+ document.removeEventListener("visibilitychange", onVisibilityChange);
433
+ };
434
+ }, [refreshEnvKeys, refreshSettingsStatus]);
397
435
  useEffect(() => {
398
436
  callAction("manage-agent-engine", { action: "list" })
399
437
  .then((data) => {
@@ -441,14 +479,21 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
441
479
  }
442
480
  return configured;
443
481
  }, [envKeys, settingsStatus]);
444
- const builderConnected = connected || builderFlow.configured;
445
- const anyKeyConfigured = builderConnected ||
446
- (selectedEnginePackageInstalled &&
447
- (envConfigured || settingsConfigured || configuredProviderIds.size > 0));
482
+ const builderConnected = builderStatusAvailable && (connected || builderFlow.configured);
483
+ const configurationKnown = envProbeAvailable && statusProbeAvailable;
484
+ const builderEngineSelected = selectedEngine === "builder";
485
+ const selectedConfigurationKnown = builderEngineSelected
486
+ ? builderStatusAvailable
487
+ : configurationKnown;
488
+ const anyKeyConfigured = (builderEngineSelected && builderConnected) ||
489
+ (!builderEngineSelected &&
490
+ configurationKnown &&
491
+ selectedEnginePackageInstalled &&
492
+ (envConfigured || settingsConfigured));
448
493
  const sourceBadge = computeSourceBadge({
449
- settingsConfigured,
450
- settingsStatus,
451
- envConfigured,
494
+ settingsConfigured: configurationKnown && settingsConfigured,
495
+ settingsStatus: configurationKnown ? settingsStatus : null,
496
+ envConfigured: configurationKnown && envConfigured,
452
497
  envVar,
453
498
  builderConnected,
454
499
  });
@@ -479,7 +524,6 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
479
524
  setBaseUrlConfigured(true);
480
525
  if (clearBaseUrl)
481
526
  setBaseUrlConfigured(false);
482
- refreshSettingsStatus();
483
527
  notifyConfigChanged();
484
528
  setTimeout(() => setSaved(false), 2000);
485
529
  }
@@ -496,7 +540,6 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
496
540
  if (res.ok) {
497
541
  setTestResult(null);
498
542
  setApplyNote(false);
499
- refreshSettingsStatus();
500
543
  notifyConfigChanged();
501
544
  return;
502
545
  }
@@ -560,7 +603,6 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
560
603
  setCurrentEngine(selectedEngine);
561
604
  setCurrentModel(selectedModel);
562
605
  setApplyNote(true);
563
- refreshSettingsStatus();
564
606
  notifyConfigChanged();
565
607
  setTimeout(() => setApplyNote(false), 4000);
566
608
  }
@@ -568,7 +610,9 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
568
610
  setApplyError(err instanceof Error ? err.message : String(err));
569
611
  }
570
612
  };
571
- return (_jsx(SettingsSection, { id: settingsSectionDomId("llm"), icon: _jsx(IconBrain, { size: 14 }), title: "LLM", required: true, connected: initialLoading ? undefined : anyKeyConfigured, subtitle: isPage
613
+ return (_jsx(SettingsSection, { id: settingsSectionDomId("llm"), icon: _jsx(IconBrain, { size: 14 }), title: "LLM", required: true, connected: initialLoading || !selectedConfigurationKnown
614
+ ? undefined
615
+ : anyKeyConfigured, subtitle: isPage
572
616
  ? undefined
573
617
  : t("agentPanel.builderOrOwnKeys", {
574
618
  defaultValue: "Choose Builder.io or custom keys.",
@@ -576,11 +620,11 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
576
620
  ? "flex items-center justify-between gap-4 px-5 py-4 sm:px-6"
577
621
  : "flex items-center justify-between gap-2"), children: [isPage && (_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "AI provider" }), _jsx("p", { className: "mt-1 text-sm leading-6 text-muted-foreground", children: t("agentPanel.builderOrOwnKeys", {
578
622
  defaultValue: "Choose Builder.io or custom keys.",
579
- }) })] })), _jsxs("div", { className: cn("flex flex-wrap items-center justify-end gap-2"), children: [!anyKeyConfigured && (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "llm_settings", trackingFlow: "connect_llm", label: "Connect Builder.io", compact: true })), _jsx(ManualSetupCard, { id: "llm-manual-setup", title: "Custom keys", hint: manualSetupHint, sourceBadge: builderConnected ? undefined : sourceBadge, bare: isPage, popover: true, popoverLabel: settingsConfigured
623
+ }) })] })), _jsxs("div", { className: cn("flex flex-wrap items-center justify-end gap-2"), children: [selectedConfigurationKnown && !anyKeyConfigured && (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: builderConnected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "llm_settings", trackingFlow: "connect_llm", label: "Connect Builder.io", compact: true })), _jsx(ManualSetupCard, { id: "llm-manual-setup", title: "Custom keys", hint: manualSetupHint, sourceBadge: builderConnected ? undefined : sourceBadge, bare: isPage, popover: true, popoverLabel: settingsConfigured
580
624
  ? "Manage"
581
625
  : t("agentPanel.addOwnKeys", {
582
626
  defaultValue: "Custom keys",
583
- }), summaryContent: anyKeyConfigured ? (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "llm_settings", trackingFlow: "connect_llm", label: "Connect Builder.io" })) : undefined, children: _jsxs("div", { className: "space-y-2 mb-1", children: [_jsx(AgentProviderPicker, { value: selectedProvider, configuredProviders: configuredProviderIds, layout: isPage ? "page" : "compact", onChange: (provider) => {
627
+ }), summaryContent: selectedConfigurationKnown && anyKeyConfigured ? (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: builderConnected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "llm_settings", trackingFlow: "connect_llm", label: "Connect Builder.io" })) : undefined, children: _jsxs("div", { className: "space-y-2 mb-1", children: [_jsx(AgentProviderPicker, { value: selectedProvider, configuredProviders: configurationKnown ? configuredProviderIds : undefined, layout: isPage ? "page" : "compact", onChange: (provider) => {
584
628
  const option = getAgentProviderOption(provider);
585
629
  setSelectedEngine(option.engine);
586
630
  setSelectedModel(option.defaultModel);
@@ -611,7 +655,9 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
611
655
  : `${envVar} configured`] })) : envVar ? (_jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { type: "password", value: apiKey, onChange: (e) => setApiKey(e.target.value), onKeyDown: (e) => {
612
656
  if (e.key === "Enter")
613
657
  handleSave();
614
- }, placeholder: PROVIDER_ENV_PLACEHOLDERS[envVar] ?? "...", className: cn(textInputClass(isPage), "flex-1"), style: isPage ? CONTROL_STYLE_PAGE : undefined }), _jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleSave, disabled: !providerSettingsChanged || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") })] })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { intent: "neutral", emphasis: "outline", onClick: handleTest, disabled: testing, className: pillButtonClass(isPage, "outline"), children: testing ? (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" }), "Testing\u2026"] })) : ("Test") }), PROVIDER_DOCS[selectedEngine] ? (_jsxs("a", { href: PROVIDER_DOCS[selectedEngine], target: "_blank", rel: "noopener noreferrer", className: cn(pillButtonClass(isPage, "outline"), "no-underline"), children: ["Get an API key", _jsx(IconExternalLink, { size: isPage ? 14 : 10 })] })) : null, engineChanged && (_jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleApply, className: pillButtonClass(isPage, "solid"), children: "Apply" })), settingsStatus != null && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { intent: "danger", emphasis: "outline", onClick: handleDisconnect, className: cn(pillButtonClass(isPage, "outline"), "ms-auto text-muted-foreground hover:bg-destructive/10 hover:text-destructive hover:border-destructive/40"), children: "Disconnect" }) }), _jsx(TooltipContent, { children: "Clear the saved engine \u2014 the app will fall back to the default until you re-apply." })] }))] }), testResult && testResult.ok && (_jsxs("p", { className: cn("flex items-center gap-1 text-primary", isPage ? "text-xs" : "text-[10px]"), children: [_jsx(IconCheck, { size: isPage ? 14 : 10 }), "Test passed \u2014 ", testResult.latencyMs, "ms"] })), testResult && testResult.ok === false && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Test failed: ", testResult.error] })), disconnectError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Disconnect failed: ", disconnectError] })), applyError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Apply failed: ", applyError] })), applyNote && (_jsx("p", { className: cn("text-muted-foreground", isPage ? "text-xs" : "text-[10px]"), children: "Changes take effect on next conversation" }))] }) })] })] })) }));
658
+ }, placeholder: PROVIDER_ENV_PLACEHOLDERS[envVar] ?? "...", className: cn(textInputClass(isPage), "flex-1"), style: isPage ? CONTROL_STYLE_PAGE : undefined }), _jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleSave, disabled: !providerSettingsChanged || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") })] })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { intent: "neutral", emphasis: "outline", onClick: handleTest, disabled: testing ||
659
+ !selectedConfigurationKnown ||
660
+ !anyKeyConfigured, className: pillButtonClass(isPage, "outline"), children: testing ? (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" }), "Testing\u2026"] })) : ("Test") }), PROVIDER_DOCS[selectedEngine] ? (_jsxs("a", { href: PROVIDER_DOCS[selectedEngine], target: "_blank", rel: "noopener noreferrer", className: cn(pillButtonClass(isPage, "outline"), "no-underline"), children: ["Get an API key", _jsx(IconExternalLink, { size: isPage ? 14 : 10 })] })) : null, engineChanged && (_jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleApply, className: pillButtonClass(isPage, "solid"), children: "Apply" })), settingsStatus != null && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { intent: "danger", emphasis: "outline", onClick: handleDisconnect, className: cn(pillButtonClass(isPage, "outline"), "ms-auto text-muted-foreground hover:bg-destructive/10 hover:text-destructive hover:border-destructive/40"), children: "Disconnect" }) }), _jsx(TooltipContent, { children: "Clear the saved engine \u2014 the app will fall back to the default until you re-apply." })] }))] }), testResult && testResult.ok && (_jsxs("p", { className: cn("flex items-center gap-1 text-primary", isPage ? "text-xs" : "text-[10px]"), children: [_jsx(IconCheck, { size: isPage ? 14 : 10 }), "Test passed \u2014 ", testResult.latencyMs, "ms"] })), testResult && testResult.ok === false && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Test failed: ", testResult.error] })), disconnectError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Disconnect failed: ", disconnectError] })), applyError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Apply failed: ", applyError] })), applyNote && (_jsx("p", { className: cn("text-muted-foreground", isPage ? "text-xs" : "text-[10px]"), children: "Changes take effect on next conversation" }))] }) })] })] })) }));
615
661
  }
616
662
  function friendlyAppName(appId) {
617
663
  return appId
@@ -1056,10 +1102,11 @@ function CapabilityStatusStrip({ isDevMode, builderConnected, builderLoading, bu
1056
1102
  return (_jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-2.5 py-2", children: [_jsx("div", { className: "mb-1.5 text-[10px] font-medium text-muted-foreground", children: "Available now" }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(CapabilityStatusRow, { label: "App", value: "Chat + actions", active: true }), _jsx(CapabilityStatusRow, { label: "Code", value: codeLabel, active: codeAvailable }), _jsx(CapabilityStatusRow, { label: "Builder", active: builderConnected, value: builderLoading ? (_jsx(Skeleton, { className: "h-3 w-16" })) : builderConnected ? ("Connected") : (_jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: onOpenLlm, className: "rounded border border-border px-1.5 py-0.5 text-[10px] text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground", children: "Connect" })) })] })] }));
1057
1103
  }
1058
1104
  function SettingsPanelContent({ isDevMode, initialSection, sectionRequestKey, sections = ALL_SETTINGS_SECTIONS, showCapabilityStrip = true, className, surface = "sidebar", builderConnectionOwnedExternally = false, agentAdditionalContent, }) {
1059
- const { status: builder, loading: builderLoading } = useBuilderStatus({
1105
+ const { status: builder, loading: builderLoading, stale: builderStatusStale, } = useBuilderStatus({
1060
1106
  enabled: !builderConnectionOwnedExternally,
1061
1107
  });
1062
1108
  const connected = builder?.configured ?? false;
1109
+ const builderStatusAvailable = !builderLoading && !builderStatusStale && builder != null;
1063
1110
  const connectUrl = builder?.connectUrl;
1064
1111
  const orgName = builder?.orgName;
1065
1112
  const envManaged = !!builder?.envManaged;
@@ -1088,7 +1135,7 @@ function SettingsPanelContent({ isDevMode, initialSection, sectionRequestKey, se
1088
1135
  const isPage = surface === "page";
1089
1136
  const isWorkspacePage = isPage && sections.includes("hosting");
1090
1137
  return (_jsx(SettingsSurfaceProvider, { surface: surface, children: _jsxs("div", { className: cn(isPage ? "space-y-8" : "flex-1 min-h-0 overflow-y-auto p-3 space-y-2", className), style: isPage ? undefined : { overflowY: "auto" }, children: [showCapabilityStrip && (_jsx(CapabilityStatusStrip, { isDevMode: isDevMode, builderConnected: connected, builderLoading: builderLoading, builderBranchesAvailable: builderBranchesAvailable, onOpenLlm: () => openSettingsSection("llm", true) })), isPage &&
1091
- ["llm", "app-models", "limits", "voice"].some((section) => shouldShowSection(section)) && (_jsxs(SettingsGroup, { title: "Agent", children: [shouldShowSection("llm") && (_jsx(LLMSectionInner, { builderFlow: builderFlow, builderLoading: builderLoading, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, grouped: true, open: openSection === "llm", onToggle: () => toggle("llm") })), shouldShowSection("app-models") && (_jsx(AppModelDefaultsSectionInner, { grouped: true, open: openSection === "app-models", onToggle: () => toggle("app-models") })), shouldShowSection("limits") && (_jsx(AgentLimitsSectionInner, { grouped: true, open: openSection === "limits", onToggle: () => toggle("limits") })), shouldShowSection("voice") && (_jsx(SettingsSection, { id: settingsSectionDomId("voice"), icon: _jsx(IconMicrophone, { size: 14 }), title: "Voice Transcription", subtitle: "Choose how voice input is transcribed.", grouped: true, flat: true, open: openSection === "voice", onToggle: () => toggle("voice"), children: _jsx(VoiceTranscriptionSection, { compact: true }) }))] })), isPage && agentAdditionalContent ? (_jsx(SettingsGroup, { title: "Notifications", children: agentAdditionalContent })) : null, isPage &&
1138
+ ["llm", "app-models", "limits", "voice"].some((section) => shouldShowSection(section)) && (_jsxs(SettingsGroup, { title: "Agent", children: [shouldShowSection("llm") && (_jsx(LLMSectionInner, { builderFlow: builderFlow, builderLoading: builderLoading, builderStatusAvailable: builderStatusAvailable, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, grouped: true, open: openSection === "llm", onToggle: () => toggle("llm") })), shouldShowSection("app-models") && (_jsx(AppModelDefaultsSectionInner, { grouped: true, open: openSection === "app-models", onToggle: () => toggle("app-models") })), shouldShowSection("limits") && (_jsx(AgentLimitsSectionInner, { grouped: true, open: openSection === "limits", onToggle: () => toggle("limits") })), shouldShowSection("voice") && (_jsx(SettingsSection, { id: settingsSectionDomId("voice"), icon: _jsx(IconMicrophone, { size: 14 }), title: "Voice Transcription", subtitle: "Choose how voice input is transcribed.", grouped: true, flat: true, open: openSection === "voice", onToggle: () => toggle("voice"), children: _jsx(VoiceTranscriptionSection, { compact: true }) }))] })), isPage && agentAdditionalContent ? (_jsx(SettingsGroup, { title: "Notifications", children: agentAdditionalContent })) : null, isPage &&
1092
1139
  ["automations", "background"].some((section) => shouldShowSection(section)) && (_jsxs(SettingsGroup, { title: "Agent workflows", children: [shouldShowSection("automations") && (_jsx(SettingsSection, { id: settingsSectionDomId("automations"), icon: _jsx(IconBolt, { size: 14 }), title: "Automations", subtitle: "Scheduled and event-triggered agent tasks.", grouped: true, flat: true, open: openSection === "automations", onToggle: () => toggle("automations"), children: _jsx(SettingsRow, { label: "Automations", description: "Schedule agent tasks or run them from events.", control: _jsxs("a", { href: "/settings/agent/automations", className: "inline-flex items-center gap-1 rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground no-underline transition-colors hover:bg-accent/40", children: ["Open automations", _jsx(IconExternalLink, { size: 14 })] }) }) })), shouldShowSection("background") && (_jsx(SettingsSection, { id: settingsSectionDomId("background"), icon: _jsx(IconGitBranch, { size: 14 }), title: "Background Agent", subtitle: "Make code changes from production mode via Builder.", grouped: true, flat: true, connected: connected, open: openSection === "background", onToggle: () => toggle("background"), children: _jsx(SettingsRow, { label: "Background agent", description: "Make code changes from production mode via Builder.", control: _jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "background_agent_settings", trackingFlow: "background_agent", compact: true }) }) }))] })), isWorkspacePage && (_jsxs(SettingsGroup, { title: "Workspace", children: [shouldShowSection("demo-mode") && (_jsx(SettingsRow, { id: settingsSectionDomId("demo-mode"), label: "Demo mode", description: "Use sample data in this browser for presentations.", control: _jsx(DemoModeSection, { compact: true }) })), shouldShowSection("hosting") && (_jsx(SettingsRow, { id: settingsSectionDomId("hosting"), label: "Hosting", description: "Deploy the app to the cloud.", control: _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [!connected && (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "hosting_settings", trackingFlow: "hosting", compact: true })), _jsx(ManualSetupCard, { title: "Set up manually", hint: "Deploy manually to Netlify, Vercel, Cloudflare, or any Nitro-supported target.", docsUrl: docsUrl("deployment", {
1093
1140
  campaign: "onboarding",
1094
1141
  content: "deployment_settings",
@@ -1101,7 +1148,7 @@ function SettingsPanelContent({ isDevMode, initialSection, sectionRequestKey, se
1101
1148
  }), dim: connected, bare: true, popover: true, popoverLabel: "Manage", summaryContent: connected ? (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "file_upload_settings", trackingFlow: "file_upload" })) : undefined, children: _jsx(FileStorageSettingsForm, {}) })] }) })), shouldShowSection("auth") && (_jsx(SettingsRow, { id: settingsSectionDomId("auth"), label: "Authentication", description: "Set up sign-in and access control.", control: _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [!connected && (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "auth_settings", trackingFlow: "auth", compact: true })), _jsx(ManualSetupCard, { title: "Set up manually", hint: "Configure Better Auth and optional Google or GitHub providers.", docsUrl: docsUrl("authentication", {
1102
1149
  campaign: "onboarding",
1103
1150
  content: "authentication_settings",
1104
- }), dim: connected, bare: true, popover: true, popoverLabel: "Manage", summaryContent: connected ? (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "auth_settings", trackingFlow: "auth" })) : undefined })] }) }))] })), !isPage && shouldShowSection("llm") && (_jsx(LLMSectionInner, { builderFlow: builderFlow, builderLoading: builderLoading, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, open: openSection === "llm", onToggle: () => toggle("llm") })), !isPage && shouldShowSection("app-models") && (_jsx(AppModelDefaultsSectionInner, { open: openSection === "app-models", onToggle: () => toggle("app-models") })), !isPage && shouldShowSection("limits") && (_jsx(AgentLimitsSectionInner, { open: openSection === "limits", onToggle: () => toggle("limits") })), !isPage && shouldShowSection("voice") && (_jsx(SettingsSection, { id: settingsSectionDomId("voice"), icon: _jsx(IconMicrophone, { size: 14 }), title: "Voice Transcription", subtitle: "How the composer microphone turns your voice into text.", flat: true, open: openSection === "voice", onToggle: () => toggle("voice"), children: _jsx(VoiceTranscriptionSection, {}) })), !isPage && shouldShowSection("demo-mode") && (_jsx(SettingsSection, { id: settingsSectionDomId("demo-mode"), icon: _jsx(IconEyeOff, { size: 14 }), title: "Demo mode", subtitle: "Replace displayed emails with realistic fake data in this browser and reshape supported charts for presentations. Backend, agent integrations, and agent results stay real and access-scoped.", flat: true, open: openSection === "demo-mode", onToggle: () => toggle("demo-mode"), children: _jsx(DemoModeSection, {}) })), !isPage && shouldShowSection("automations") && (_jsx(SettingsSection, { id: settingsSectionDomId("automations"), icon: _jsx(IconBolt, { size: 14 }), title: "Automations", subtitle: "Scheduled and event-triggered agent tasks.", flat: true, open: openSection === "automations", onToggle: () => toggle("automations"), children: _jsx(AutomationsSection, {}) })), shouldShowSection("secrets") && (_jsx(SettingsSection, { id: settingsSectionDomId("secrets"), icon: _jsx(IconKey, { size: 14 }), title: "API keys", subtitle: "Service credentials and automation keys.", flat: true, open: openSection === "secrets", onToggle: () => toggle("secrets"), children: _jsx(SecretsSection, { focusKey: focusSecretKey }) })), !isPage && shouldShowSection("hosting") && (_jsx(SettingsSection, { id: settingsSectionDomId("hosting"), icon: _jsx(IconCloud, { size: 14 }), title: "Hosting", subtitle: "Deploy your app to the cloud.", flat: true, connected: connected, open: openSection === "hosting", onToggle: () => toggle("hosting"), children: _jsxs("div", { className: "space-y-2", children: [_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "hosting_settings", trackingFlow: "hosting" }), _jsx(ManualSetupCard, { hint: "Deploy manually to Netlify, Vercel, Cloudflare, or any Nitro-supported target.", docsUrl: docsUrl("deployment", {
1151
+ }), dim: connected, bare: true, popover: true, popoverLabel: "Manage", summaryContent: connected ? (_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "auth_settings", trackingFlow: "auth" })) : undefined })] }) }))] })), !isPage && shouldShowSection("llm") && (_jsx(LLMSectionInner, { builderFlow: builderFlow, builderLoading: builderLoading, builderStatusAvailable: builderStatusAvailable, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, open: openSection === "llm", onToggle: () => toggle("llm") })), !isPage && shouldShowSection("app-models") && (_jsx(AppModelDefaultsSectionInner, { open: openSection === "app-models", onToggle: () => toggle("app-models") })), !isPage && shouldShowSection("limits") && (_jsx(AgentLimitsSectionInner, { open: openSection === "limits", onToggle: () => toggle("limits") })), !isPage && shouldShowSection("voice") && (_jsx(SettingsSection, { id: settingsSectionDomId("voice"), icon: _jsx(IconMicrophone, { size: 14 }), title: "Voice Transcription", subtitle: "How the composer microphone turns your voice into text.", flat: true, open: openSection === "voice", onToggle: () => toggle("voice"), children: _jsx(VoiceTranscriptionSection, {}) })), !isPage && shouldShowSection("demo-mode") && (_jsx(SettingsSection, { id: settingsSectionDomId("demo-mode"), icon: _jsx(IconEyeOff, { size: 14 }), title: "Demo mode", subtitle: "Replace displayed emails with realistic fake data in this browser and reshape supported charts for presentations. Backend, agent integrations, and agent results stay real and access-scoped.", flat: true, open: openSection === "demo-mode", onToggle: () => toggle("demo-mode"), children: _jsx(DemoModeSection, {}) })), !isPage && shouldShowSection("automations") && (_jsx(SettingsSection, { id: settingsSectionDomId("automations"), icon: _jsx(IconBolt, { size: 14 }), title: "Automations", subtitle: "Scheduled and event-triggered agent tasks.", flat: true, open: openSection === "automations", onToggle: () => toggle("automations"), children: _jsx(AutomationsSection, {}) })), shouldShowSection("secrets") && (_jsx(SettingsSection, { id: settingsSectionDomId("secrets"), icon: _jsx(IconKey, { size: 14 }), title: "API keys", subtitle: "Service credentials and automation keys.", flat: true, open: openSection === "secrets", onToggle: () => toggle("secrets"), children: _jsx(SecretsSection, { focusKey: focusSecretKey }) })), !isPage && shouldShowSection("hosting") && (_jsx(SettingsSection, { id: settingsSectionDomId("hosting"), icon: _jsx(IconCloud, { size: 14 }), title: "Hosting", subtitle: "Deploy your app to the cloud.", flat: true, connected: connected, open: openSection === "hosting", onToggle: () => toggle("hosting"), children: _jsxs("div", { className: "space-y-2", children: [_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "hosting_settings", trackingFlow: "hosting" }), _jsx(ManualSetupCard, { hint: "Deploy manually to Netlify, Vercel, Cloudflare, or any Nitro-supported target.", docsUrl: docsUrl("deployment", {
1105
1152
  campaign: "onboarding",
1106
1153
  content: "deployment_settings",
1107
1154
  }), dim: connected })] }) })), !isPage && shouldShowSection("database") && (_jsx(SettingsSection, { id: settingsSectionDomId("database"), icon: _jsx(IconDatabase, { size: 14 }), title: "Database", subtitle: "Connect a cloud database for persistent storage.", flat: true, connected: connected, open: openSection === "database", onToggle: () => toggle("database"), children: _jsxs("div", { className: "space-y-2", children: [_jsx(UseBuilderCard, { builderFlow: builderFlow, connectUrl: connectUrl, connected: connected, orgName: orgName, envManaged: envManaged, credentialSource: credentialSource, trackingSource: "database_settings", trackingFlow: "database" }), _jsx(ManualSetupCard, { hint: "Set DATABASE_URL in your .env to connect Neon, Supabase, Turso, any Postgres/SQLite database, or local PGlite with pglite:./data/pglite.", docsUrl: docsUrl("database", {
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
@@ -1,5 +1,5 @@
1
1
  import { AGENT_CHAT_BACKGROUND_RUN_FIELD, dispatchPathTargetsNetlifyBackgroundFunction, resolveAgentChatProcessRunDispatchPath, } from "../agent/durable-background.js";
2
- import { canUpdateAutomationResource, } from "../automations/service.js";
2
+ import { canQueueAutomationRunNow, } from "../automations/service.js";
3
3
  import { isLocalDatabase } from "../db/client.js";
4
4
  import { organizationResourceOwner, resourceGetByPath, } from "../resources/store.js";
5
5
  import { fireInternalDispatch } from "../server/self-dispatch.js";
@@ -77,7 +77,7 @@ export async function queueAutomationRunNow(input) {
77
77
  statusCode: 404,
78
78
  });
79
79
  }
80
- if (!(await canUpdateAutomationResource(input, resource))) {
80
+ if (!(await canQueueAutomationRunNow(input, resource, input.scope))) {
81
81
  throw Object.assign(new Error("Only the automation's creator or an organization admin can run it."), { statusCode: 403 });
82
82
  }
83
83
  const { body } = parseJobResource(resource.content);
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- error?: undefined;
45
44
  summary: import("./types.js").TraceSummary;
46
45
  spans: import("./types.js").TraceSpan[];
47
46
  id?: undefined;
47
+ error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
- error?: undefined;
51
50
  summary?: undefined;
52
51
  spans?: undefined;
53
52
  id: string;
53
+ error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
64
  id?: undefined;
65
+ error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- error?: undefined;
19
18
  ok: boolean;
19
+ error?: undefined;
20
20
  }>>;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- ok?: undefined;
52
51
  error: string;
52
+ ok?: undefined;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
- error?: undefined;
30
29
  token: string;
31
30
  expiresAt: string;
32
31
  ttlSeconds: number;
32
+ error?: undefined;
33
33
  }>>;
@@ -20,6 +20,6 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- error?: undefined;
24
23
  text: string;
24
+ error?: undefined;
25
25
  }>>;
@@ -1680,6 +1680,10 @@ function virtualModuleIdFromRuntimeUrl(runtimeUrl) {
1680
1680
  }
1681
1681
  async function loadMountedEmbedRuntimeModule(server, runtimeUrl) {
1682
1682
  const virtualId = virtualModuleIdFromRuntimeUrl(runtimeUrl);
1683
+ // transform import to encode virtual modules in vite as these imports don't work in the browser
1684
+ const result = await server.transformRequest(virtualId ?? runtimeUrl);
1685
+ if (typeof result?.code === "string")
1686
+ return result.code;
1683
1687
  if (virtualId) {
1684
1688
  const loaded = await server.pluginContainer?.load?.(virtualId);
1685
1689
  if (typeof loaded === "string")
@@ -1687,8 +1691,7 @@ async function loadMountedEmbedRuntimeModule(server, runtimeUrl) {
1687
1691
  if (loaded && typeof loaded.code === "string")
1688
1692
  return loaded.code;
1689
1693
  }
1690
- const result = await server.transformRequest(runtimeUrl);
1691
- return result?.code ?? null;
1694
+ return null;
1692
1695
  }
1693
1696
  function serveMountedEmbedRuntimeModule(server, req, res, base) {
1694
1697
  if (req.method !== "GET" && req.method !== "HEAD")