@agent-native/core 0.157.8 → 0.157.10

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 (154) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/actions/purge-first-party-analytics-postgres.ts +26 -8
  3. package/corpus/templates/analytics/scripts/first-party-analytics-postgres-retention-dry-run.sql +261 -0
  4. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +3 -1
  5. package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +75 -31
  6. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +4 -1
  7. package/corpus/templates/analytics/server/plugins/db.ts +139 -0
  8. package/corpus/templates/slides/AGENTS.md +14 -10
  9. package/corpus/templates/slides/actions/export-pptx.ts +1311 -121
  10. package/corpus/templates/slides/actions/import-file.ts +28 -1
  11. package/corpus/templates/slides/actions/import-pptx.ts +69 -42
  12. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +222 -29
  13. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +71 -0
  14. package/corpus/templates/slides/app/global.css +19 -1
  15. package/corpus/templates/slides/app/lib/export-google-slides-client.ts +44 -5
  16. package/corpus/templates/slides/app/lib/export-pdf-client.ts +13 -6
  17. package/corpus/templates/slides/app/lib/export-pptx-client.ts +601 -30
  18. package/corpus/templates/slides/app/pages/DeckEditor.tsx +18 -1
  19. package/corpus/templates/slides/server/handlers/import/html-converter.ts +1240 -22
  20. package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +329 -64
  21. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +24 -0
  22. package/corpus/templates/slides/server/lib/source-import.ts +10 -1
  23. package/corpus/templates/slides/shared/aspect-ratios.ts +13 -1
  24. package/dist/agent/harness/migrations.d.ts +4 -0
  25. package/dist/agent/harness/migrations.js +60 -0
  26. package/dist/agent/production-agent.d.ts +2 -0
  27. package/dist/agent/production-agent.js +15 -0
  28. package/dist/agent/run-loop-with-resume.d.ts +1 -0
  29. package/dist/agent/run-loop-with-resume.js +44 -12
  30. package/dist/agent/run-migrations.d.ts +8 -0
  31. package/dist/agent/run-migrations.js +61 -0
  32. package/dist/automations/service.d.ts +6 -0
  33. package/dist/automations/service.js +35 -0
  34. package/dist/chat-threads/migrations.d.ts +1 -0
  35. package/dist/chat-threads/migrations.js +1 -0
  36. package/dist/chat-threads/schema-migrations.d.ts +8 -0
  37. package/dist/chat-threads/schema-migrations.js +60 -0
  38. package/dist/cli/code-agent-connector.d.ts +4 -1
  39. package/dist/cli/code-agent-connector.js +154 -23
  40. package/dist/cli/code-agent-executor.js +255 -13
  41. package/dist/cli/code-agent-runs.d.ts +1 -0
  42. package/dist/cli/code-agent-runs.js +2 -1
  43. package/dist/cli/portal-workspace.d.ts +49 -0
  44. package/dist/cli/portal-workspace.js +320 -0
  45. package/dist/client/AssistantChat.d.ts +1 -1
  46. package/dist/client/AssistantChat.js +43 -61
  47. package/dist/client/ConnectBuilderCard.js +33 -5
  48. package/dist/client/agent-chat-adapter.js +4 -0
  49. package/dist/client/analytics-platform.d.ts +2 -0
  50. package/dist/client/analytics-platform.js +12 -0
  51. package/dist/client/analytics.d.ts +3 -0
  52. package/dist/client/analytics.js +10 -1
  53. package/dist/client/chat/index.d.ts +1 -0
  54. package/dist/client/chat/index.js +1 -0
  55. package/dist/client/chat/message-components.d.ts +2 -0
  56. package/dist/client/chat/message-components.js +11 -1
  57. package/dist/client/chat/run-recovery.d.ts +2 -1
  58. package/dist/client/chat/run-recovery.js +2 -2
  59. package/dist/client/chat-first/apps-rail.d.ts +1 -1
  60. package/dist/client/chat-first/apps-rail.js +11 -11
  61. package/dist/client/chat-first/surface-tabs.d.ts +1 -1
  62. package/dist/client/chat-first/surface-tabs.js +38 -36
  63. package/dist/client/chat-first/types.d.ts +5 -0
  64. package/dist/client/chat-first.d.ts +1 -1
  65. package/dist/client/chat-first.js +4 -4
  66. package/dist/client/desktop-local-code-change.d.ts +10 -0
  67. package/dist/client/desktop-local-code-change.js +16 -0
  68. package/dist/client/index.d.ts +1 -0
  69. package/dist/client/index.js +1 -0
  70. package/dist/client/observability/ThumbsFeedback.js +53 -26
  71. package/dist/client/observability/useObservability.d.ts +1 -1
  72. package/dist/client/observability/useObservability.js +6 -3
  73. package/dist/client/terminal/AgentTerminal.d.ts +9 -1
  74. package/dist/client/terminal/AgentTerminal.js +38 -3
  75. package/dist/client/terminal/index.d.ts +1 -1
  76. package/dist/client/terminal/index.js +1 -1
  77. package/dist/client/track.js +9 -1
  78. package/dist/client/use-action.js +3 -0
  79. package/dist/collab/awareness.d.ts +2 -2
  80. package/dist/deploy/build.js +1 -1
  81. package/dist/feature-flags/a2a-action-route.js +4 -2
  82. package/dist/feature-flags/permissions.d.ts +2 -0
  83. package/dist/feature-flags/permissions.js +6 -1
  84. package/dist/ingestion/pptx.d.ts +92 -1
  85. package/dist/ingestion/pptx.js +1180 -115
  86. package/dist/integrations/index.d.ts +3 -3
  87. package/dist/integrations/index.js +2 -2
  88. package/dist/integrations/plugin.js +95 -6
  89. package/dist/integrations/remote-commands-store.d.ts +5 -0
  90. package/dist/integrations/remote-commands-store.js +63 -22
  91. package/dist/integrations/remote-devices-store.d.ts +2 -1
  92. package/dist/integrations/remote-devices-store.js +46 -0
  93. package/dist/integrations/remote-types.d.ts +20 -0
  94. package/dist/jobs/actions/list-recurring-jobs.d.ts +3 -0
  95. package/dist/jobs/actions/list-recurring-jobs.js +5 -1
  96. package/dist/jobs/frontmatter.d.ts +16 -0
  97. package/dist/jobs/frontmatter.js +53 -0
  98. package/dist/jobs/remote-execution.d.ts +42 -0
  99. package/dist/jobs/remote-execution.js +287 -0
  100. package/dist/jobs/scheduler.js +102 -3
  101. package/dist/jobs/tools.js +50 -3
  102. package/dist/localization/core-messages/ar-SA.js +4 -0
  103. package/dist/localization/core-messages/de-DE.js +4 -0
  104. package/dist/localization/core-messages/en-US.d.ts +4 -0
  105. package/dist/localization/core-messages/en-US.js +4 -0
  106. package/dist/localization/core-messages/es-ES.js +4 -0
  107. package/dist/localization/core-messages/fr-FR.js +4 -0
  108. package/dist/localization/core-messages/hi-IN.js +4 -0
  109. package/dist/localization/core-messages/ja-JP.js +4 -0
  110. package/dist/localization/core-messages/ko-KR.js +4 -0
  111. package/dist/localization/core-messages/pt-BR.js +4 -0
  112. package/dist/localization/core-messages/zh-CN.js +4 -0
  113. package/dist/localization/core-messages/zh-TW.js +4 -0
  114. package/dist/localization/core-messages.d.ts +4 -0
  115. package/dist/notifications/routes.d.ts +3 -3
  116. package/dist/observability/feedback.js +40 -16
  117. package/dist/observability/routes.d.ts +6 -6
  118. package/dist/observability/routes.js +15 -3
  119. package/dist/observability/store.js +2 -0
  120. package/dist/observability/traces.js +5 -1
  121. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  122. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  123. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  124. package/dist/resources/handlers.d.ts +1 -1
  125. package/dist/secrets/routes.d.ts +9 -9
  126. package/dist/server/action-routes.d.ts +7 -5
  127. package/dist/server/action-routes.js +13 -6
  128. package/dist/server/agent-chat-plugin.js +6 -0
  129. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  130. package/dist/server/agent-run-context.d.ts +1 -0
  131. package/dist/server/agent-run-context.js +9 -0
  132. package/dist/server/better-auth-instance.js +4 -0
  133. package/dist/server/core-routes-plugin.js +8 -1
  134. package/dist/server/realtime-voice.js +2 -1
  135. package/dist/server/release-migrations.js +16 -0
  136. package/dist/server/request-context.d.ts +2 -0
  137. package/dist/server/transcribe-voice.d.ts +1 -1
  138. package/dist/shared/analytics-platform.d.ts +6 -0
  139. package/dist/shared/analytics-platform.js +14 -0
  140. package/dist/shared/mcp-embed-headers.d.ts +1 -1
  141. package/dist/shared/mcp-embed-headers.js +1 -1
  142. package/dist/styles/agent-native.css +83 -103
  143. package/dist/terminal/cli-registry.js +5 -0
  144. package/dist/tracking/registry.js +9 -1
  145. package/dist/triggers/actions/list-automations.d.ts +3 -0
  146. package/dist/triggers/actions/list-automations.js +3 -0
  147. package/dist/triggers/actions/manage-automation.d.ts +9 -0
  148. package/dist/triggers/actions/manage-automation.js +14 -2
  149. package/dist/triggers/actions.js +82 -7
  150. package/dist/usage/migrations.d.ts +4 -0
  151. package/dist/usage/migrations.js +45 -0
  152. package/docs/content/template-content-developers.mdx +48 -0
  153. package/docs/content/toolkit-ui.mdx +57 -0
  154. package/package.json +3 -3
@@ -0,0 +1,16 @@
1
+ export const DESKTOP_LOCAL_CODE_CHANGE_EVENT = "agent-native:desktop-local-code-change";
2
+ /**
3
+ * Ask an embedding desktop shell to prepare a local code-change workspace.
4
+ * The optional target keeps bubbling events scoped to the shell that owns the
5
+ * chat card while preserving a window fallback for standalone consumers.
6
+ */
7
+ export function requestDesktopLocalCodeChange(prompt, target = typeof window === "undefined" ? null : window) {
8
+ const trimmed = prompt.trim();
9
+ if (!trimmed || !target)
10
+ return false;
11
+ target.dispatchEvent(new CustomEvent(DESKTOP_LOCAL_CODE_CHANGE_EVENT, {
12
+ bubbles: true,
13
+ detail: { prompt: trimmed },
14
+ }));
15
+ return true;
16
+ }
@@ -3,6 +3,7 @@
3
3
  * Compatibility aggregation only; new code must not import this barrel.
4
4
  */
5
5
  export * from "./agent-chat/index.js";
6
+ export * from "./desktop-local-code-change.js";
6
7
  export * from "./hooks/index.js";
7
8
  export * from "./navigation/index.js";
8
9
  export * from "./host/index.js";
@@ -3,6 +3,7 @@
3
3
  * Compatibility aggregation only; new code must not import this barrel.
4
4
  */
5
5
  export * from "./agent-chat/index.js";
6
+ export * from "./desktop-local-code-change.js";
6
7
  export * from "./hooks/index.js";
7
8
  export * from "./navigation/index.js";
8
9
  export * from "./host/index.js";
@@ -1,24 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "@agent-native/toolkit/ui/button";
3
+ import { Textarea } from "@agent-native/toolkit/ui/textarea";
2
4
  import * as PopoverPrimitive from "@radix-ui/react-popover";
3
5
  import { IconThumbUp, IconThumbDown } from "@tabler/icons-react";
4
- import { useState, useCallback } from "react";
6
+ import { useState, useCallback, useId, useRef } from "react";
5
7
  import { agentNativePath } from "../api-path.js";
6
8
  import { useT } from "../i18n.js";
7
9
  import { cn } from "../utils.js";
8
- const THUMBS_DOWN_CATEGORIES = [
9
- { value: "Inaccurate", key: "agentChat.feedback.inaccurate" },
10
- { value: "Not helpful", key: "agentChat.feedback.notHelpful" },
11
- { value: "Wrong tool", key: "agentChat.feedback.wrongTool" },
12
- { value: "Too slow", key: "agentChat.feedback.tooSlow" },
13
- ];
14
10
  export function ThumbsFeedback({ threadId, runId, messageSeq, className, }) {
15
11
  const t = useT();
16
12
  const [selection, setSelection] = useState(null);
17
- const [categoryOpen, setCategoryOpen] = useState(false);
18
- const [submittedCategory, setSubmittedCategory] = useState(null);
13
+ const [popoverOpen, setPopoverOpen] = useState(false);
14
+ const [textFeedback, setTextFeedback] = useState("");
15
+ const feedbackInputId = useId();
16
+ const feedbackInputRef = useRef(null);
19
17
  const sendFeedback = useCallback(async (feedbackType, value) => {
20
18
  try {
21
- await fetch(agentNativePath("/_agent-native/observability/feedback"), {
19
+ const response = await fetch(agentNativePath("/_agent-native/observability/feedback"), {
22
20
  method: "POST",
23
21
  headers: { "Content-Type": "application/json" },
24
22
  body: JSON.stringify({
@@ -29,38 +27,67 @@ export function ThumbsFeedback({ threadId, runId, messageSeq, className, }) {
29
27
  value: value ?? "",
30
28
  }),
31
29
  });
30
+ if (!response.ok) {
31
+ throw new Error(`Feedback submission failed (${response.status})`);
32
+ }
33
+ return true;
32
34
  }
33
35
  catch {
34
- // Fire-and-forget; don't block the UI on feedback submission failures
36
+ // coercion-ok: callers receive false and restore the retryable UI state.
37
+ return false;
35
38
  }
36
39
  }, [threadId, runId, messageSeq]);
37
40
  const handleThumbsUp = useCallback(() => {
38
41
  if (selection === "up")
39
42
  return;
40
43
  setSelection("up");
41
- setCategoryOpen(false);
42
- setSubmittedCategory(null);
43
- sendFeedback("thumbs_up");
44
+ setPopoverOpen(false);
45
+ void sendFeedback("thumbs_up").then((submitted) => {
46
+ if (!submitted)
47
+ setSelection(null);
48
+ });
44
49
  }, [selection, sendFeedback]);
45
50
  const handleThumbsDown = useCallback(() => {
46
51
  if (selection === "down") {
47
- setCategoryOpen((prev) => !prev);
52
+ setPopoverOpen((prev) => !prev);
48
53
  return;
49
54
  }
50
55
  setSelection("down");
51
- setCategoryOpen(true);
52
- sendFeedback("thumbs_down");
56
+ setPopoverOpen(true);
57
+ void sendFeedback("thumbs_down").then((submitted) => {
58
+ if (!submitted)
59
+ setSelection(null);
60
+ });
53
61
  }, [selection, sendFeedback]);
54
- const handleCategory = useCallback((category) => {
55
- setSubmittedCategory(category);
56
- setCategoryOpen(false);
57
- sendFeedback("category", category);
58
- }, [sendFeedback]);
62
+ const handleTextFeedback = useCallback(() => {
63
+ const value = textFeedback.trim();
64
+ if (!value)
65
+ return;
66
+ void sendFeedback("text", value).then((submitted) => {
67
+ if (!submitted)
68
+ return;
69
+ setTextFeedback("");
70
+ setPopoverOpen(false);
71
+ });
72
+ }, [sendFeedback, textFeedback]);
59
73
  return (_jsxs("div", { className: cn("inline-flex items-center gap-0.5", className), children: [_jsx("button", { type: "button", "aria-label": t("agentChat.feedback.thumbsUp"), onClick: handleThumbsUp, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "up"
60
74
  ? "text-foreground"
61
- : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbUp, { size: 16, stroke: selection === "up" ? 2.5 : 1.5, fill: selection === "up" ? "currentColor" : "none" }) }), _jsxs(PopoverPrimitive.Root, { open: categoryOpen, onOpenChange: setCategoryOpen, children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": t("agentChat.feedback.thumbsDown"), onClick: handleThumbsDown, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "down"
75
+ : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbUp, { size: 16, stroke: selection === "up" ? 2.5 : 1.5, fill: selection === "up" ? "currentColor" : "none" }) }), _jsxs(PopoverPrimitive.Root, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": t("agentChat.feedback.thumbsDown"), onClick: handleThumbsDown, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "down"
62
76
  ? "text-foreground"
63
- : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbDown, { size: 16, stroke: selection === "down" ? 2.5 : 1.5, fill: selection === "down" ? "currentColor" : "none" }) }) }), _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: "bottom", align: "start", sideOffset: 4, collisionPadding: 8, className: "z-[300] overflow-hidden rounded-lg border border-border bg-popover p-1 shadow-lg outline-none", children: _jsx("div", { className: "flex flex-col gap-0.5", children: THUMBS_DOWN_CATEGORIES.map((category) => (_jsx("button", { type: "button", onClick: () => handleCategory(category.value), className: cn("rounded-md px-3 py-1.5 text-start text-xs", submittedCategory === category.value
64
- ? "bg-accent text-foreground font-medium"
65
- : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), children: t(category.key) }, category.value))) }) }) })] })] }));
77
+ : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbDown, { size: 16, stroke: selection === "down" ? 2.5 : 1.5, fill: selection === "down" ? "currentColor" : "none" }) }) }), _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: "bottom", align: "start", sideOffset: 4, collisionPadding: 8, onOpenAutoFocus: (event) => {
78
+ event.preventDefault();
79
+ feedbackInputRef.current?.focus();
80
+ }, className: "z-[300] w-[min(320px,calc(100vw-24px))] overflow-hidden rounded-lg border border-border bg-popover p-3 text-popover-foreground shadow-lg outline-none origin-[var(--radix-popover-content-transform-origin)]", children: _jsxs("form", { className: "flex flex-col gap-2.5", onSubmit: (event) => {
81
+ event.preventDefault();
82
+ handleTextFeedback();
83
+ }, children: [_jsx("label", { htmlFor: feedbackInputId, className: "text-xs font-medium text-foreground", children: t("agentChat.feedback.whatWentWrong") }), _jsx(Textarea, { id: feedbackInputId, ref: feedbackInputRef, autoFocus: true, value: textFeedback, onChange: (event) => setTextFeedback(event.target.value), onKeyDown: (event) => {
84
+ if ((event.metaKey || event.ctrlKey) &&
85
+ event.key === "Enter") {
86
+ event.preventDefault();
87
+ handleTextFeedback();
88
+ }
89
+ }, placeholder: t("agentChat.feedback.placeholder"), rows: 3, maxLength: 2000, className: "min-h-20 resize-none px-2.5 py-2 text-xs" }), _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-[11px] text-muted-foreground/75", children: t("agentChat.feedback.keyboardHint").replace("{{shortcut}}", typeof navigator !== "undefined" &&
90
+ /Mac|iPhone|iPad/.test(navigator.userAgent)
91
+ ? "⌘"
92
+ : "Ctrl") }), _jsx(Button, { type: "submit", size: "sm", disabled: !textFeedback.trim(), className: "h-7 px-2.5 text-xs", children: t("agentChat.feedback.submit") })] })] }) }) })] })] }));
66
93
  }
@@ -57,7 +57,7 @@ export interface FeedbackEntry {
57
57
  userId: string | null;
58
58
  createdAt: number;
59
59
  }
60
- export declare function useFeedbackList(sinceDays?: number, limit?: number): import("@tanstack/react-query").UseQueryResult<NoInfer<FeedbackEntry[]>, Error>;
60
+ export declare function useFeedbackList(sinceDays?: number, limit?: number, feedbackType?: FeedbackEntry["feedbackType"]): import("@tanstack/react-query").UseQueryResult<NoInfer<FeedbackEntry[]>, Error>;
61
61
  export interface FeedbackStats {
62
62
  total: number;
63
63
  thumbsUp: number;
@@ -31,11 +31,14 @@ export function useTraceDetail(runId) {
31
31
  enabled: !!runId,
32
32
  });
33
33
  }
34
- export function useFeedbackList(sinceDays = 7, limit = 100) {
34
+ export function useFeedbackList(sinceDays = 7, limit = 100, feedbackType) {
35
35
  const sinceMs = Date.now() - sinceDays * 86_400_000;
36
+ const typeQuery = feedbackType
37
+ ? `&feedbackType=${encodeURIComponent(feedbackType)}`
38
+ : "";
36
39
  return useQuery({
37
- queryKey: ["observability", "feedback", sinceDays, limit],
38
- queryFn: () => fetchJson(`${BASE}/feedback?since=${sinceMs}&limit=${limit}`),
40
+ queryKey: ["observability", "feedback", sinceDays, limit, feedbackType],
41
+ queryFn: () => fetchJson(`${BASE}/feedback?since=${sinceMs}&limit=${limit}${typeQuery}`),
39
42
  refetchInterval: 30_000,
40
43
  });
41
44
  }
@@ -30,6 +30,14 @@ export interface AgentTerminalProps {
30
30
  onConnectionChange?: (connected: boolean) => void;
31
31
  /** Callback when agent running state changes */
32
32
  onAgentRunningChange?: (running: boolean) => void;
33
+ /** Queue a prompt for the CLI once the PTY WebSocket is ready. */
34
+ submitRequest?: AgentTerminalSubmitRequest;
35
+ /** Called after a queued prompt is written to the PTY. */
36
+ onPromptSubmitted?: (request: AgentTerminalSubmitRequest) => void;
37
+ }
38
+ export interface AgentTerminalSubmitRequest {
39
+ id: string | number;
40
+ text: string;
33
41
  }
34
42
  export declare function formatWebSocketHostname(hostname: string): string;
35
- export declare function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame, theme, fontSize, className, style, onConnectionChange, onAgentRunningChange, }: AgentTerminalProps): import("react").JSX.Element | null;
43
+ export declare function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame, theme, fontSize, className, style, onConnectionChange, onAgentRunningChange, submitRequest, onPromptSubmitted, }: AgentTerminalProps): import("react").JSX.Element | null;
@@ -33,7 +33,7 @@ function injectXtermCss() {
33
33
  .xterm .composition-view { display: none; position: absolute; white-space: nowrap; z-index: 1; }
34
34
  .xterm .composition-view.active { display: block; }
35
35
  .xterm .xterm-viewport {
36
- background-color: #000; overflow-y: scroll;
36
+ background-color: var(--agent-terminal-background); overflow-y: scroll;
37
37
  cursor: default; position: absolute; right: 0; left: 0; top: 0; bottom: 0;
38
38
  }
39
39
  .xterm .xterm-screen { position: relative; }
@@ -85,8 +85,12 @@ export function formatWebSocketHostname(hostname) {
85
85
  ? `[${hostname}]`
86
86
  : hostname;
87
87
  }
88
- export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame = true, theme, fontSize = 12, className, style, onConnectionChange, onAgentRunningChange, }) {
88
+ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame = true, theme, fontSize = 12, className, style, onConnectionChange, onAgentRunningChange, submitRequest, onPromptSubmitted, }) {
89
89
  const termRef = useRef(null);
90
+ const submitPromptRef = useRef(null);
91
+ const pendingSubmitRequestRef = useRef(null);
92
+ const onPromptSubmittedRef = useRef(onPromptSubmitted);
93
+ onPromptSubmittedRef.current = onPromptSubmitted;
90
94
  const [connected, setConnected] = useState(false);
91
95
  const [error, setError] = useState(null);
92
96
  const [inFrame, setInFrame] = useState(false);
@@ -226,6 +230,22 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
226
230
  let agentRunning = false;
227
231
  let idleTimer = null;
228
232
  let connectionId = 0;
233
+ function submitPrompt(request) {
234
+ const text = request.text.trim();
235
+ if (!text)
236
+ return;
237
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
238
+ pendingSubmitRequestRef.current = request;
239
+ return;
240
+ }
241
+ ws.send(text + "\r");
242
+ agentRunning = true;
243
+ notifyAgentRunning(true);
244
+ if (pendingSubmitRequestRef.current?.id === request.id) {
245
+ pendingSubmitRequestRef.current = null;
246
+ }
247
+ onPromptSubmittedRef.current?.(request);
248
+ }
229
249
  function sendResize() {
230
250
  if (ws && ws.readyState === WebSocket.OPEN && term) {
231
251
  ws.send(JSON.stringify({
@@ -258,6 +278,9 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
258
278
  cols: term.cols,
259
279
  rows: term.rows,
260
280
  }));
281
+ const pendingRequest = pendingSubmitRequestRef.current;
282
+ if (pendingRequest)
283
+ submitPrompt(pendingRequest);
261
284
  };
262
285
  socket.onmessage = (event) => {
263
286
  const data = event.data instanceof ArrayBuffer
@@ -328,6 +351,10 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
328
351
  };
329
352
  window.addEventListener("message", messageHandler);
330
353
  cleanupMessageHandler = () => window.removeEventListener("message", messageHandler);
354
+ submitPromptRef.current = submitPrompt;
355
+ const initialRequest = pendingSubmitRequestRef.current;
356
+ if (initialRequest)
357
+ submitPrompt(initialRequest);
331
358
  connect(fullWsUrl);
332
359
  // Store cleanup references
333
360
  return () => {
@@ -340,6 +367,7 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
340
367
  ws.close();
341
368
  ws = null;
342
369
  }
370
+ submitPromptRef.current = null;
343
371
  };
344
372
  }
345
373
  let cleanup;
@@ -353,6 +381,12 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
353
381
  };
354
382
  // eslint-disable-next-line react-hooks/exhaustive-deps
355
383
  }, [hideInFrame, inFrame, command, flags, wsUrlProp]);
384
+ useEffect(() => {
385
+ if (!submitRequest)
386
+ return;
387
+ pendingSubmitRequestRef.current = submitRequest;
388
+ submitPromptRef.current?.(submitRequest);
389
+ }, [submitRequest?.id, submitRequest?.text]);
356
390
  if (hideInFrame && inFrame) {
357
391
  return null;
358
392
  }
@@ -361,6 +395,7 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
361
395
  ...style,
362
396
  background: terminalBackground,
363
397
  backgroundColor: terminalBackground,
398
+ "--agent-terminal-background": terminalBackground,
364
399
  };
365
400
  return (_jsx("div", { ref: termRef, className: className, style: {
366
401
  width: "100%",
@@ -374,7 +409,7 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
374
409
  display: "flex",
375
410
  alignItems: "center",
376
411
  justifyContent: "center",
377
- backgroundColor: "#111",
412
+ backgroundColor: terminalBackground,
378
413
  color: "#ff7b72",
379
414
  fontSize: "13px",
380
415
  fontFamily: "monospace",
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Embeddable agent CLI terminal component.
5
5
  */
6
- export { AgentTerminal, type AgentTerminalProps } from "./AgentTerminal.js";
6
+ export { AgentTerminal, type AgentTerminalProps, type AgentTerminalSubmitRequest, } from "./AgentTerminal.js";
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Embeddable agent CLI terminal component.
5
5
  */
6
- export { AgentTerminal } from "./AgentTerminal.js";
6
+ export { AgentTerminal, } from "./AgentTerminal.js";
@@ -1,3 +1,5 @@
1
+ import { ANALYTICS_CLIENT_PLATFORM_HEADER, ANALYTICS_CLIENT_PLATFORM_PROPERTY, } from "../shared/analytics-platform.js";
2
+ import { getAnalyticsClientPlatform } from "./analytics-platform.js";
1
3
  import { getOrCreateAnalyticsSessionId } from "./analytics-session.js";
2
4
  import { agentNativePath } from "./api-path.js";
3
5
  /**
@@ -28,9 +30,14 @@ export function track(name, properties) {
28
30
  return Promise.resolve();
29
31
  if (typeof name !== "string" || !name.trim())
30
32
  return Promise.resolve();
33
+ const clientPlatform = getAnalyticsClientPlatform();
34
+ const trackedProperties = {
35
+ ...(properties ?? {}),
36
+ [ANALYTICS_CLIENT_PLATFORM_PROPERTY]: clientPlatform,
37
+ };
31
38
  let body;
32
39
  try {
33
- body = JSON.stringify(properties === undefined ? { name } : { name, properties });
40
+ body = JSON.stringify({ name, properties: trackedProperties });
34
41
  }
35
42
  catch {
36
43
  // Non-serializable properties — drop rather than throw into the caller.
@@ -45,6 +52,7 @@ export function track(name, properties) {
45
52
  // middleware trusts it as a first-party marker. Matches the convention
46
53
  // used by other client writes (application-state, guided-questions).
47
54
  "X-Agent-Native-CSRF": "1",
55
+ [ANALYTICS_CLIENT_PLATFORM_HEADER]: clientPlatform,
48
56
  // Same session the action client and agent chat send, so a client event
49
57
  // and the server events from the same visit share one session.
50
58
  ...(browserSessionId
@@ -22,6 +22,8 @@
22
22
  * compatibility.
23
23
  */
24
24
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
25
+ import { ANALYTICS_CLIENT_PLATFORM_HEADER } from "../shared/analytics-platform.js";
26
+ import { getAnalyticsClientPlatform } from "./analytics-platform.js";
25
27
  import { getOrCreateAnalyticsSessionId } from "./analytics-session.js";
26
28
  import { trackEvent } from "./analytics.js";
27
29
  import { agentNativePath } from "./api-path.js";
@@ -203,6 +205,7 @@ async function performActionFetch(name, method, params, options) {
203
205
  if (browserSessionId) {
204
206
  headers["X-Agent-Native-Session-Id"] = browserSessionId;
205
207
  }
208
+ headers[ANALYTICS_CLIENT_PLATFORM_HEADER] = getAnalyticsClientPlatform();
206
209
  const init = {
207
210
  method,
208
211
  headers,
@@ -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;
65
66
  states: {
66
67
  clientId: number;
67
68
  state: string;
68
69
  }[];
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;
80
81
  users: {
81
82
  clientId: number;
82
83
  lastSeen: number;
83
84
  }[];
84
- error?: undefined;
85
85
  }>>;
@@ -1245,7 +1245,7 @@ async function getHandler() {
1245
1245
  headers: {
1246
1246
  "Access-Control-Allow-Origin": "*",
1247
1247
  "Access-Control-Allow-Methods": "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS",
1248
- "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-Agent-Native-Embed-Target",
1248
+ "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Session-Id,X-Agent-Native-Client-Platform,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-Agent-Native-Embed-Target",
1249
1249
  },
1250
1250
  });
1251
1251
  }
@@ -3,6 +3,7 @@ import * as jose from "jose";
3
3
  import { verifyA2ATokenWithClaims } from "../a2a-claims.js";
4
4
  import { resolveOrgByDomain } from "../org/context.js";
5
5
  import { consumeOneTimeJti } from "../server/identity-sso-store.js";
6
+ import { isFeatureFlagAdminEmail } from "./permissions.js";
6
7
  const FLAG_ACTION_SCOPES = {
7
8
  "list-feature-flags": "flags:read",
8
9
  "set-feature-flag": "flags:write",
@@ -40,15 +41,16 @@ export function createFeatureFlagA2AActionRouteAuth(actionName) {
40
41
  throw new Error("Invalid feature flag delegation");
41
42
  }
42
43
  const localOrg = await resolveOrgByDomain(claims.orgDomain);
43
- if (!localOrg)
44
+ if (!localOrg && !isFeatureFlagAdminEmail(claims.email)) {
44
45
  throw new Error("Invalid feature flag delegation");
46
+ }
45
47
  if (actionName === "set-feature-flag" &&
46
48
  (await consumeOneTimeJti(claims.jti))) {
47
49
  throw new Error("Invalid feature flag delegation");
48
50
  }
49
51
  return {
50
52
  owner: claims.email,
51
- orgId: localOrg.orgId,
53
+ orgId: localOrg?.orgId ?? null,
52
54
  anonymous: false,
53
55
  delegationJti: claims.jti,
54
56
  delegationIssuer: claims.issuer,
@@ -2,6 +2,8 @@ export declare class FeatureFlagPermissionError extends Error {
2
2
  statusCode: number;
3
3
  constructor(message: string, statusCode: number);
4
4
  }
5
+ /** Return whether an email is explicitly allowed to manage no-org flags. */
6
+ export declare function isFeatureFlagAdminEmail(email: string | undefined): boolean;
5
7
  /** Require an org admin/owner, or an explicit production no-org allowlist entry. */
6
8
  export declare function requireFeatureFlagManager(scope: {
7
9
  userEmail?: string;
@@ -13,6 +13,11 @@ function productionAdminAllowlist() {
13
13
  .map((email) => email.trim().toLowerCase())
14
14
  .filter(Boolean));
15
15
  }
16
+ /** Return whether an email is explicitly allowed to manage no-org flags. */
17
+ export function isFeatureFlagAdminEmail(email) {
18
+ const normalized = email?.trim().toLowerCase();
19
+ return Boolean(normalized && productionAdminAllowlist().has(normalized));
20
+ }
16
21
  /** Require an org admin/owner, or an explicit production no-org allowlist entry. */
17
22
  export async function requireFeatureFlagManager(scope) {
18
23
  const email = scope.userEmail?.trim().toLowerCase();
@@ -29,7 +34,7 @@ export async function requireFeatureFlagManager(scope) {
29
34
  }
30
35
  if (process.env.NODE_ENV !== "production")
31
36
  return { email, orgId: null };
32
- if (!productionAdminAllowlist().has(email)) {
37
+ if (!isFeatureFlagAdminEmail(email)) {
33
38
  throw new FeatureFlagPermissionError("Feature flag management without an organization requires an explicit admin allowlist entry.", 403);
34
39
  }
35
40
  return { email, orgId: null };
@@ -21,21 +21,35 @@ export interface ParsedPptxParagraph {
21
21
  lineSpacing?: number;
22
22
  spaceBeforePt?: number;
23
23
  spaceAfterPt?: number;
24
+ /** `a:pPr/@_rtl` — the paragraph's base writing direction is right-to-left. Only set when the source states it; absent means inherit (LTR). */
25
+ rtl?: boolean;
24
26
  }
25
27
  export interface ParsedPptxElement {
26
28
  id: string;
27
29
  name?: string;
28
30
  placeholderType?: string;
29
- kind: "text" | "image" | "shape";
31
+ kind: "text" | "image" | "shape" | "table";
30
32
  x: number;
31
33
  y: number;
32
34
  width: number;
33
35
  height: number;
34
36
  rotation?: number;
37
+ /** `a:xfrm/@_flipH` — the shape's geometry is mirrored across its own vertical axis before rotation. */
38
+ flipH?: boolean;
39
+ /** `a:xfrm/@_flipV` — the shape's geometry is mirrored across its own horizontal axis before rotation. */
40
+ flipV?: boolean;
35
41
  shapeType?: string;
42
+ /** `a:prstGeom/a:avLst` adjustment values keyed by guide name (`adj`, `adj1`, ...), in the preset's own units. Absent when the deck accepts the preset's defaults. */
43
+ shapeAdjustments?: Record<string, number>;
44
+ /** `a:custGeom`'s authored outline, when the shape declares one instead of a preset. */
45
+ geometry?: ParsedPptxGeometry;
36
46
  fill?: string;
37
47
  lineColor?: string;
38
48
  lineWidth?: number;
49
+ /** `a:ln/a:headEnd` — the decoration drawn where the line starts. */
50
+ lineHeadEnd?: ParsedPptxLineEnd;
51
+ /** `a:ln/a:tailEnd` — the decoration drawn where the line ends. */
52
+ lineTailEnd?: ParsedPptxLineEnd;
39
53
  padding?: {
40
54
  left: number;
41
55
  right: number;
@@ -45,6 +59,79 @@ export interface ParsedPptxElement {
45
59
  verticalAlign?: "top" | "middle" | "bottom";
46
60
  paragraphs?: ParsedPptxParagraph[];
47
61
  image?: ParsedPptxImage;
62
+ table?: ParsedPptxTable;
63
+ }
64
+ /**
65
+ * One end of a line or connector — the round dots a chevron timeline's
66
+ * connectors terminate in (`<a:headEnd type="oval"/>`), an arrowhead, a
67
+ * diamond. Recorded whatever the type, including the ones a consumer cannot
68
+ * draw, so an end a renderer skips stays distinguishable from a line the
69
+ * source drew bare and an export can still round-trip it.
70
+ */
71
+ export interface ParsedPptxLineEnd {
72
+ /** `@_type`: `none`, `triangle`, `stealth`, `diamond`, `oval`, or `arrow`. */
73
+ type: string;
74
+ /** `@_w`/`@_len` — the end's size across and along the line, as `sm`/`med`/`lg` multiples of the line's own width, not absolute units. Absent means the OOXML default (`med`). */
75
+ w?: string;
76
+ len?: string;
77
+ }
78
+ /** A single `a:path` command, in the path's own `w`/`h` coordinate space. `arcTo` keeps OOXML's radii-and-angles form because converting it needs the current point, which only a consumer walking the whole command list knows. */
79
+ export type ParsedPptxPathCommand = {
80
+ kind: "moveTo" | "lnTo" | "quadBezTo" | "cubicBezTo";
81
+ points: {
82
+ x: number;
83
+ y: number;
84
+ }[];
85
+ } | {
86
+ kind: "arcTo";
87
+ /** Ellipse radii in path units. */
88
+ wR: number;
89
+ hR: number;
90
+ /** Start angle and swing, in 60000ths of a degree, clockwise from the +x axis. */
91
+ stAng: number;
92
+ swAng: number;
93
+ } | {
94
+ kind: "close";
95
+ };
96
+ /** One `a:custGeom/a:pathLst/a:path`. `w`/`h` define the coordinate space its points are expressed in; the shape's own box is what they scale onto. */
97
+ export interface ParsedPptxPath {
98
+ w: number;
99
+ h: number;
100
+ commands: ParsedPptxPathCommand[];
101
+ }
102
+ export interface ParsedPptxGeometry {
103
+ kind: "custom";
104
+ paths: ParsedPptxPath[];
105
+ }
106
+ /** A `p:graphicFrame`'s `a:tbl` flattened into a simple row/cell grid. `hMerge`/`vMerge` continuation cells are omitted — their content is already represented once, by the spanning cell's `colSpan`/`rowSpan`. */
107
+ export interface ParsedPptxTable {
108
+ rows: ParsedPptxTableCell[][];
109
+ /** Authored `a:tblGrid/a:gridCol/@_w` values, in EMUs, when present. */
110
+ columnWidthsEmu?: number[];
111
+ /** Authored `a:tr/@_h` values, in EMUs, when present. */
112
+ rowHeightsEmu?: number[];
113
+ }
114
+ export interface ParsedPptxTableCell {
115
+ paragraphs: ParsedPptxParagraph[];
116
+ colSpan?: number;
117
+ rowSpan?: number;
118
+ fill?: string;
119
+ /** Resolved cell edges. A side is present only when the cell's own `a:tcPr/a:lnL|R|T|B` or the deck table style's `a:tcBdr` draws a line there — a cell the source leaves borderless stays borderless. */
120
+ borders?: ParsedPptxTableCellBorders;
121
+ }
122
+ export interface ParsedPptxTableCellBorders {
123
+ left?: ParsedPptxTableBorder;
124
+ right?: ParsedPptxTableBorder;
125
+ top?: ParsedPptxTableBorder;
126
+ bottom?: ParsedPptxTableBorder;
127
+ }
128
+ /** One resolved table cell edge, from an `a:ln`. */
129
+ export interface ParsedPptxTableBorder {
130
+ color: string;
131
+ /** `a:ln/@_w`, in EMU. Absent when the line declares no width. */
132
+ widthEmu?: number;
133
+ /** `a:prstDash/@_val`, collapsed onto the CSS border styles that can draw it. Absent for a solid line. */
134
+ dash?: "dashed" | "dotted";
48
135
  }
49
136
  export type ParsedPptxTransition = "instant" | "none" | "fade" | "slide" | "zoom";
50
137
  export interface ParsedPptxImage {
@@ -75,6 +162,8 @@ export interface ParsedPptxSlide {
75
162
  layoutHint?: string;
76
163
  transition?: ParsedPptxTransition;
77
164
  splitByParagraph?: boolean;
165
+ /** Count of this slide's `graphicFrame` shapes that could not be converted into a `"table"` element (charts, SmartArt, embedded OLE objects, or a malformed/empty `a:tbl`) — a fidelity signal for `buildSourceImportMetadata`, the same way `imagesSkipped` already works. */
166
+ tablesDegraded?: number;
78
167
  }
79
168
  export interface ParsedPptxGrid {
80
169
  color: string;
@@ -95,6 +184,8 @@ export interface ParsedPptxPresentation {
95
184
  colors: string[];
96
185
  fonts: string[];
97
186
  };
187
+ /** Slides the source deck marked `show="0"` and this import deliberately left out — the only legitimate reason `slides.length` is short of the deck's `p:sldId` count, so callers can say so instead of reporting a silently shorter deck. */
188
+ hiddenSlideCount?: number;
98
189
  }
99
190
  export declare function parsePptxPresentation(fileBuffer: Uint8Array): Promise<ParsedPptxPresentation>;
100
191
  export declare function parsePptxSlideMetadata(value: unknown): ParsedPptxSlideMetadata;