@agent-native/core 0.189.0 → 0.190.0-nightly-20260925211446
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +11 -22
- package/corpus/templates/analytics/actions/list-data-dictionary.ts +7 -9
- package/corpus/templates/analytics/actions/search-analytics-query-catalog.ts +1 -1
- package/corpus/templates/analytics/app/components/AnalyticsReviewArtifactPreview.tsx +201 -0
- package/corpus/templates/analytics/app/i18n/en-US.ts +2 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +50 -3
- package/corpus/templates/analytics/changelog/2026-09-25-first-run-onboarding-records-setup-choices-and-builder-conne.md +6 -0
- package/corpus/templates/analytics/changelog/2026-09-25-human-review-previews-analytics-dashboards-as-real-charts.md +6 -0
- package/corpus/templates/analytics/changelog/2026-09-25-org-admins-can-review-agent-runs-from-settings.md +6 -0
- package/corpus/templates/analytics/changelog/2026-09-25-proactive-query-context.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +98 -2
- package/corpus/templates/analytics/server/lib/analytics-agent-context.ts +557 -0
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +217 -46
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +2 -2
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +39 -5
- package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +4 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +268 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +44 -9
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/calendar/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/actions/get-event-rules-status.ts +47 -0
- package/corpus/templates/calendar/actions/list-events.ts +50 -4
- package/corpus/templates/calendar/actions/undo-calendar-event-rule.ts +229 -0
- package/corpus/templates/calendar/actions/update-settings.ts +8 -0
- package/corpus/templates/calendar/app/i18n/en-US.ts +27 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +196 -1
- package/corpus/templates/calendar/changelog/2026-09-25-calendar-feeds-with-the-same-url-keep-their-own-names-and-co.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-calendar-invitation-rules-surface-expired-connections-and-un.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-restore-locally-hidden-events-from-activity-after-disconnect.md +6 -0
- package/corpus/templates/calendar/server/lib/calendar-settings.ts +44 -10
- package/corpus/templates/calendar/server/lib/google-api.ts +15 -1
- package/corpus/templates/calendar/server/lib/google-calendar.ts +1 -1
- package/corpus/templates/calendar/server/plugins/event-rules.ts +628 -0
- package/corpus/templates/calendar/shared/api.ts +13 -0
- package/corpus/templates/calendar/shared/settings.ts +71 -1
- package/corpus/templates/clips/actions/create-recording.ts +83 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +610 -110
- package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +7 -0
- package/corpus/templates/clips/actions/lib/loom-import-job.ts +15 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +126 -26
- package/corpus/templates/clips/app/hooks/use-drop-video-upload.ts +75 -15
- package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +5 -1
- package/corpus/templates/clips/app/routes/record.tsx +134 -40
- package/corpus/templates/clips/chrome-extension/src/background.ts +3 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +73 -16
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +188 -18
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +1 -0
- package/corpus/templates/clips/server/db/schema.ts +4 -0
- package/corpus/templates/clips/server/jobs/media-verification.ts +78 -4
- package/corpus/templates/clips/server/jobs/recording-failure-backfill.ts +142 -0
- package/corpus/templates/clips/server/lib/media-verification-state.ts +29 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +2 -0
- package/corpus/templates/clips/server/lib/recording-failures.ts +111 -0
- package/corpus/templates/clips/server/lib/recordings.ts +6 -1
- package/corpus/templates/clips/server/lib/s3-upload-provider.ts +8 -3
- package/corpus/templates/clips/server/lib/upload-lease.ts +25 -6
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/plugins/db.ts +18 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +48 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +322 -31
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +223 -61
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +62 -4
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +74 -7
- package/corpus/templates/clips/shared/recording-core.ts +27 -0
- package/corpus/templates/design/actions/get-design.ts +35 -6
- package/corpus/templates/mail/.agents/skills/inbox-automations/SKILL.md +4 -0
- package/corpus/templates/mail/actions/consolidate-ai-filter-rules.ts +41 -0
- package/corpus/templates/mail/actions/get-ai-priority.ts +48 -8
- package/corpus/templates/mail/actions/record-ai-priority-feedback.ts +69 -0
- package/corpus/templates/mail/actions/update-mail-preferences.ts +2 -0
- package/corpus/templates/mail/app/components/email/EmailList.tsx +179 -32
- package/corpus/templates/mail/app/components/email/EmailListItem.tsx +97 -9
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +55 -1
- package/corpus/templates/mail/app/components/email/ImportanceFeedbackMenu.tsx +52 -0
- package/corpus/templates/mail/app/components/email/compose-autocomplete.ts +2 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +219 -188
- package/corpus/templates/mail/app/components/onboarding/AiInboxSetup.tsx +338 -0
- package/corpus/templates/mail/app/components/settings/AiFilterSection.tsx +597 -781
- package/corpus/templates/mail/app/components/settings/AiRulePromptField.tsx +37 -0
- package/corpus/templates/mail/app/global.css +42 -26
- package/corpus/templates/mail/app/hooks/use-ai-priority-feedback.ts +43 -0
- package/corpus/templates/mail/app/hooks/use-automations.ts +23 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +58 -3
- package/corpus/templates/mail/app/pages/InboxPage.tsx +47 -10
- package/corpus/templates/mail/changelog/2026-09-25-editing-importance-rules-preserves-disabled-instructions-and.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-25-handle-astral-unicode-letters-in-autocomplete-word-boundarie.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-25-jev-priority-feedback-and-inbox-settings.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-25-keep-existing-ai-filter-rules-intact-when-saving-a-prompt.md +6 -0
- package/corpus/templates/mail/server/lib/automation-engine.ts +21 -12
- package/corpus/templates/mail/server/lib/automations.ts +100 -1
- package/corpus/templates/mail/shared/types.ts +3 -0
- package/corpus/templates/plan/app/i18n/en-US.ts +6 -0
- package/corpus/templates/plan/app/lib/plan-invite-suggestion.ts +43 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +249 -4
- package/corpus/templates/slides/actions/create-deck.ts +11 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +117 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +373 -330
- package/corpus/templates/slides/app/components/design-system/builder-index-response.ts +36 -5
- package/corpus/templates/slides/app/components/editor/BlockBubbleMenu.tsx +21 -53
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +347 -671
- package/corpus/templates/slides/app/components/editor/bullet-editing.ts +55 -8
- package/corpus/templates/slides/app/components/editor/in-place-text-session.ts +2082 -0
- package/corpus/templates/slides/app/components/editor/list-editing.ts +174 -16
- package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +497 -62
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +102 -20
- package/corpus/templates/slides/app/context/DeckContext.tsx +9 -4
- package/corpus/templates/slides/app/global.css +7 -219
- package/corpus/templates/slides/app/i18n/en-US.ts +3 -0
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +7 -0
- package/corpus/templates/slides/app/lib/slide-image-replacement.ts +203 -1
- package/corpus/templates/slides/app/lib/slide-source-map.ts +43 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +182 -4
- package/corpus/templates/slides/app/routes/settings.tsx +33 -2
- package/corpus/templates/slides/changelog/2026-09-25-improve-slides-design-system-setup-feedback.md +6 -0
- package/corpus/templates/slides/changelog/2026-09-25-org-admins-can-review-agent-runs-from-settings.md +6 -0
- package/corpus/templates/slides/changelog/2026-09-25-text-on-a-slide-is-now-edited-in-place-clicking-into-it-chan.md +6 -0
- package/corpus/templates/slides/package.json +0 -12
- package/corpus/templates/slides/scripts/edit-fidelity/README.md +4 -2
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +12 -3
- package/corpus/templates/slides/vite.config.ts +1 -10
- package/dist/agent/jev-tool-prefetch.d.ts +29 -3
- package/dist/agent/jev-tool-prefetch.js +161 -34
- package/dist/agent/production-agent.d.ts +11 -0
- package/dist/agent/production-agent.js +39 -8
- package/dist/app-config/runtime.d.ts +1 -0
- package/dist/app-config/runtime.js +4 -0
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/client/AgentSidebar.d.ts +3 -1
- package/dist/client/AgentSidebar.js +8 -12
- package/dist/client/analytics/index.d.ts +1 -1
- package/dist/client/analytics/index.js +1 -1
- package/dist/client/analytics.d.ts +2 -0
- package/dist/client/analytics.js +9 -0
- package/dist/client/api-path.js +5 -2
- package/dist/client/chat/run-recovery.d.ts +0 -3
- package/dist/client/chat/run-recovery.js +13 -23
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/observability/ObservabilityDashboard.d.ts +3 -0
- package/dist/client/observability/ObservabilityDashboard.js +366 -71
- package/dist/client/observability/ObservabilityReviewSummaryButton.d.ts +4 -1
- package/dist/client/observability/ObservabilityReviewSummaryButton.js +13 -9
- package/dist/client/observability/OutputPreview.d.ts +9 -4
- package/dist/client/observability/OutputPreview.js +230 -52
- package/dist/client/onboarding/FirstRunOnboarding.js +67 -4
- package/dist/client/onboarding/use-onboarding.js +2 -0
- package/dist/client/sharing/ShareButton.d.ts +2 -0
- package/dist/client/sharing/ShareButton.js +1 -0
- package/dist/client/sharing/useShareButtonController.d.ts +1 -0
- package/dist/client/sharing/useShareButtonController.js +29 -8
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +9 -1
- package/dist/embeddings/index.d.ts +3 -1
- package/dist/embeddings/index.js +20 -10
- package/dist/jobs/sweep-hooks.d.ts +7 -0
- package/dist/jobs/sweep-hooks.js +28 -0
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +1 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/actions/authorization.d.ts +1 -0
- package/dist/observability/actions/authorization.js +22 -0
- package/dist/observability/actions/get-observability-review-detail.d.ts +5 -0
- package/dist/observability/actions/get-observability-review-detail.js +10 -2
- package/dist/observability/actions/get-observability-review-summary-source.d.ts +2 -0
- package/dist/observability/actions/get-observability-review-summary-source.js +3 -2
- package/dist/observability/actions/save-observability-instruction-update.js +2 -1
- package/dist/observability/actions/save-observability-review-summary.js +21 -10
- package/dist/observability/migrations.js +25 -0
- package/dist/observability/reviews.d.ts +3 -1
- package/dist/observability/reviews.js +410 -53
- package/dist/observability/routes.d.ts +6 -6
- package/dist/observability/store.d.ts +15 -0
- package/dist/observability/store.js +131 -11
- package/dist/observability/types.d.ts +18 -0
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/index.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/plugin-options.d.ts +4 -20
- package/dist/server/agent-chat/prompt-resources.d.ts +16 -0
- package/dist/server/agent-chat/prompt-resources.js +385 -22
- package/dist/server/agent-chat-plugin.d.ts +3 -1
- package/dist/server/agent-chat-plugin.js +149 -27
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +3 -0
- package/dist/server/prompts/framework-core-compact.js +1 -1
- package/dist/server/prompts/framework-core.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +6 -3
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/settings/org-settings.d.ts +4 -2
- package/dist/settings/org-settings.js +3 -3
- package/dist/settings/store.d.ts +3 -1
- package/dist/settings/store.js +8 -3
- package/dist/styles/agent-native.css +5 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +1 -0
- package/dist/templates/default/app/i18n/de-DE.ts +1 -0
- package/dist/templates/default/app/i18n/en-US.ts +1 -0
- package/dist/templates/default/app/i18n/es-ES.ts +1 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +1 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +1 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +1 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +1 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +1 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +1 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -0
- package/dist/tracking/registry.js +11 -4
- package/package.json +4 -3
- package/src/templates/default/app/i18n/ar-SA.ts +1 -0
- package/src/templates/default/app/i18n/de-DE.ts +1 -0
- package/src/templates/default/app/i18n/en-US.ts +1 -0
- package/src/templates/default/app/i18n/es-ES.ts +1 -0
- package/src/templates/default/app/i18n/fr-FR.ts +1 -0
- package/src/templates/default/app/i18n/hi-IN.ts +1 -0
- package/src/templates/default/app/i18n/ja-JP.ts +1 -0
- package/src/templates/default/app/i18n/ko-KR.ts +1 -0
- package/src/templates/default/app/i18n/pt-BR.ts +1 -0
- package/src/templates/default/app/i18n/zh-CN.ts +1 -0
- package/src/templates/default/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/slides/app/components/editor/SlideBubbleMenu.tsx +0 -488
- package/corpus/templates/slides/app/components/editor/SlideInlineEditor.tsx +0 -589
- package/corpus/templates/slides/app/components/editor/SlideRichTextEditor.tsx +0 -1347
- package/corpus/templates/slides/app/components/editor/SlideSlashMenu.tsx +0 -373
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
getAllSettings,
|
|
3
2
|
getUserSetting,
|
|
4
3
|
listOrgSettings,
|
|
4
|
+
listSettingsByPrefix,
|
|
5
5
|
} from "@agent-native/core/settings";
|
|
6
6
|
|
|
7
7
|
import { dashboardCatalogEntries } from "./dashboard-catalog";
|
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
const DATA_DICTIONARY_KEY_PREFIX = "data-dict-";
|
|
20
20
|
const MAX_QUERY_LENGTH = 12_000;
|
|
21
21
|
const MAX_CATALOG_DASHBOARD_HYDRATION = 24;
|
|
22
|
+
// ponytail: scan the 200 most recently updated summaries; a search-backed index is the upgrade path if larger workspaces need older references.
|
|
23
|
+
const MAX_CATALOG_DASHBOARD_SUMMARIES = 200;
|
|
24
|
+
const MAX_CATALOG_DICTIONARY_ENTRIES = 200;
|
|
22
25
|
const RETIRED_CATALOG_STATES = new Set([
|
|
23
26
|
"deprecated",
|
|
24
27
|
"obsolete",
|
|
@@ -118,11 +121,29 @@ export type AnalyticsQueryCatalogCandidate =
|
|
|
118
121
|
columnsUsed?: string;
|
|
119
122
|
queryTemplate?: string;
|
|
120
123
|
knownGotchas?: string;
|
|
124
|
+
commonQuestions?: string;
|
|
125
|
+
cuts?: string;
|
|
126
|
+
joinPattern?: string;
|
|
127
|
+
updateFrequency?: string;
|
|
128
|
+
dataLag?: string;
|
|
129
|
+
dependencies?: string;
|
|
130
|
+
validDateRange?: string;
|
|
131
|
+
owner?: string;
|
|
121
132
|
approved?: boolean;
|
|
122
133
|
aiGenerated?: boolean;
|
|
123
134
|
sourceUrl?: string;
|
|
124
135
|
};
|
|
125
136
|
|
|
137
|
+
export type AnalyticsQueryCatalogSearchResult = {
|
|
138
|
+
candidates: AnalyticsQueryCatalogCandidate[];
|
|
139
|
+
searchedDashboardCount: number;
|
|
140
|
+
dashboardSearchTruncated: boolean;
|
|
141
|
+
dashboardSearchStatus: "available" | "unavailable";
|
|
142
|
+
searchedDictionaryEntryCount: number;
|
|
143
|
+
dictionarySearchTruncated: boolean;
|
|
144
|
+
dictionarySearchStatus: "available" | "partial" | "unavailable";
|
|
145
|
+
};
|
|
146
|
+
|
|
126
147
|
function text(value: unknown): string {
|
|
127
148
|
return typeof value === "string" ? value.trim() : "";
|
|
128
149
|
}
|
|
@@ -452,7 +473,7 @@ function dictionaryCandidates(
|
|
|
452
473
|
entries: DictionaryEntry[],
|
|
453
474
|
search: string,
|
|
454
475
|
): AnalyticsQueryCatalogCandidate[] {
|
|
455
|
-
|
|
476
|
+
const candidates = entries.flatMap((entry) => {
|
|
456
477
|
if (isRetiredCatalogReference(entry)) return [];
|
|
457
478
|
const { score, matchedTerms } = matchScore(search, [
|
|
458
479
|
{ value: entry.metric, weight: 28 },
|
|
@@ -493,6 +514,24 @@ function dictionaryCandidates(
|
|
|
493
514
|
...(text(entry.knownGotchas)
|
|
494
515
|
? { knownGotchas: text(entry.knownGotchas) }
|
|
495
516
|
: {}),
|
|
517
|
+
...(text(entry.commonQuestions)
|
|
518
|
+
? { commonQuestions: text(entry.commonQuestions) }
|
|
519
|
+
: {}),
|
|
520
|
+
...(text(entry.cuts) ? { cuts: text(entry.cuts) } : {}),
|
|
521
|
+
...(text(entry.joinPattern)
|
|
522
|
+
? { joinPattern: text(entry.joinPattern) }
|
|
523
|
+
: {}),
|
|
524
|
+
...(text(entry.updateFrequency)
|
|
525
|
+
? { updateFrequency: text(entry.updateFrequency) }
|
|
526
|
+
: {}),
|
|
527
|
+
...(text(entry.dataLag) ? { dataLag: text(entry.dataLag) } : {}),
|
|
528
|
+
...(text(entry.dependencies)
|
|
529
|
+
? { dependencies: text(entry.dependencies) }
|
|
530
|
+
: {}),
|
|
531
|
+
...(text(entry.validDateRange)
|
|
532
|
+
? { validDateRange: text(entry.validDateRange) }
|
|
533
|
+
: {}),
|
|
534
|
+
...(text(entry.owner) ? { owner: text(entry.owner) } : {}),
|
|
496
535
|
...(typeof entry.approved === "boolean"
|
|
497
536
|
? { approved: entry.approved }
|
|
498
537
|
: {}),
|
|
@@ -503,6 +542,19 @@ function dictionaryCandidates(
|
|
|
503
542
|
},
|
|
504
543
|
];
|
|
505
544
|
});
|
|
545
|
+
const strongestHumanOrApprovedScore = candidates.reduce(
|
|
546
|
+
(strongest, candidate) =>
|
|
547
|
+
candidate.approved === true || candidate.aiGenerated !== true
|
|
548
|
+
? Math.max(strongest, candidate.score)
|
|
549
|
+
: strongest,
|
|
550
|
+
0,
|
|
551
|
+
);
|
|
552
|
+
return candidates.filter(
|
|
553
|
+
(candidate) =>
|
|
554
|
+
candidate.aiGenerated !== true ||
|
|
555
|
+
candidate.approved === true ||
|
|
556
|
+
candidate.score > strongestHumanOrApprovedScore,
|
|
557
|
+
);
|
|
506
558
|
}
|
|
507
559
|
|
|
508
560
|
function candidateIsRunnable(
|
|
@@ -525,7 +577,9 @@ function candidateDedupeKey(candidate: AnalyticsQueryCatalogCandidate): string {
|
|
|
525
577
|
.toLowerCase()}`;
|
|
526
578
|
}
|
|
527
579
|
|
|
528
|
-
function candidateTrustTier(
|
|
580
|
+
export function candidateTrustTier(
|
|
581
|
+
candidate: AnalyticsQueryCatalogCandidate,
|
|
582
|
+
): number {
|
|
529
583
|
if (candidate.kind !== "dashboard-panel") return 0;
|
|
530
584
|
if (candidate.dashboardCertified) return 2;
|
|
531
585
|
return candidate.favorite ? 1 : 0;
|
|
@@ -591,7 +645,12 @@ export function rankAnalyticsQueryCatalog(args: {
|
|
|
591
645
|
async function listDictionaryEntries(args: {
|
|
592
646
|
email: string;
|
|
593
647
|
orgId: string | null;
|
|
594
|
-
}): Promise<
|
|
648
|
+
}): Promise<{
|
|
649
|
+
entries: DictionaryEntry[];
|
|
650
|
+
searchedEntryCount: number;
|
|
651
|
+
truncated: boolean;
|
|
652
|
+
status: "available" | "partial" | "unavailable";
|
|
653
|
+
}> {
|
|
595
654
|
const entries: DictionaryEntry[] = [];
|
|
596
655
|
const seen = new Set<string>();
|
|
597
656
|
const collect = (raw: unknown) => {
|
|
@@ -603,20 +662,76 @@ async function listDictionaryEntries(args: {
|
|
|
603
662
|
entries.push(entry);
|
|
604
663
|
};
|
|
605
664
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
DATA_DICTIONARY_KEY_PREFIX,
|
|
665
|
+
const userPrefix = `u:${args.email}:${DATA_DICTIONARY_KEY_PREFIX}`;
|
|
666
|
+
const [orgResult, userResult] = await Promise.allSettled([
|
|
667
|
+
args.orgId
|
|
668
|
+
? listOrgSettings(args.orgId, DATA_DICTIONARY_KEY_PREFIX, {
|
|
669
|
+
limit: MAX_CATALOG_DICTIONARY_ENTRIES + 1,
|
|
670
|
+
})
|
|
671
|
+
: Promise.resolve(null),
|
|
672
|
+
listSettingsByPrefix(userPrefix, {
|
|
673
|
+
limit: MAX_CATALOG_DICTIONARY_ENTRIES + 1,
|
|
674
|
+
}),
|
|
675
|
+
]);
|
|
676
|
+
if (orgResult.status === "fulfilled" && orgResult.value) {
|
|
677
|
+
const orgEntries = Object.entries(orgResult.value);
|
|
678
|
+
for (const [, value] of orgEntries.slice(
|
|
679
|
+
0,
|
|
680
|
+
MAX_CATALOG_DICTIONARY_ENTRIES,
|
|
681
|
+
)) {
|
|
682
|
+
collect(value);
|
|
683
|
+
}
|
|
684
|
+
} else if (orgResult.status === "rejected") {
|
|
685
|
+
console.warn(
|
|
686
|
+
"[analytics-query-catalog] Organization dictionary lookup failed:",
|
|
687
|
+
orgResult.reason,
|
|
610
688
|
);
|
|
611
|
-
for (const value of Object.values(orgEntries)) collect(value);
|
|
612
689
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
690
|
+
if (userResult.status === "fulfilled") {
|
|
691
|
+
for (const { value } of userResult.value.slice(
|
|
692
|
+
0,
|
|
693
|
+
MAX_CATALOG_DICTIONARY_ENTRIES,
|
|
694
|
+
)) {
|
|
695
|
+
collect(value);
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
console.warn(
|
|
699
|
+
"[analytics-query-catalog] User dictionary lookup failed:",
|
|
700
|
+
userResult.reason,
|
|
701
|
+
);
|
|
618
702
|
}
|
|
619
|
-
|
|
703
|
+
const orgCount =
|
|
704
|
+
orgResult.status === "fulfilled"
|
|
705
|
+
? Object.keys(orgResult.value ?? {}).length
|
|
706
|
+
: 0;
|
|
707
|
+
const userCount =
|
|
708
|
+
userResult.status === "fulfilled" ? userResult.value.length : 0;
|
|
709
|
+
const scopedResults = [
|
|
710
|
+
...(args.orgId ? [orgResult.status === "fulfilled"] : []),
|
|
711
|
+
userResult.status === "fulfilled",
|
|
712
|
+
];
|
|
713
|
+
const availableScopes = scopedResults.filter(Boolean).length;
|
|
714
|
+
const scopeCount = args.orgId ? 2 : 1;
|
|
715
|
+
return {
|
|
716
|
+
entries,
|
|
717
|
+
searchedEntryCount: entries.length,
|
|
718
|
+
truncated:
|
|
719
|
+
orgCount > MAX_CATALOG_DICTIONARY_ENTRIES ||
|
|
720
|
+
userCount > MAX_CATALOG_DICTIONARY_ENTRIES,
|
|
721
|
+
status:
|
|
722
|
+
availableScopes === scopeCount
|
|
723
|
+
? "available"
|
|
724
|
+
: availableScopes > 0
|
|
725
|
+
? "partial"
|
|
726
|
+
: "unavailable",
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function warnCatalogReadFailure(source: string, error: unknown): void {
|
|
731
|
+
console.warn(
|
|
732
|
+
`[analytics-query-catalog] ${source} lookup failed; continuing with available references:`,
|
|
733
|
+
error,
|
|
734
|
+
);
|
|
620
735
|
}
|
|
621
736
|
|
|
622
737
|
function savedDashboardInput(
|
|
@@ -640,8 +755,10 @@ export async function searchAnalyticsQueryCatalog(args: {
|
|
|
640
755
|
email: string;
|
|
641
756
|
orgId: string | null;
|
|
642
757
|
limit: number;
|
|
643
|
-
|
|
644
|
-
|
|
758
|
+
signal?: AbortSignal;
|
|
759
|
+
}): Promise<AnalyticsQueryCatalogSearchResult> {
|
|
760
|
+
args.signal?.throwIfAborted();
|
|
761
|
+
const [summariesResult, dictionaryResult, favoritesResult] =
|
|
645
762
|
await Promise.allSettled([
|
|
646
763
|
listDashboardSummaries(
|
|
647
764
|
{ email: args.email, orgId: args.orgId },
|
|
@@ -650,38 +767,83 @@ export async function searchAnalyticsQueryCatalog(args: {
|
|
|
650
767
|
archived: "active",
|
|
651
768
|
hidden: "visible",
|
|
652
769
|
includeCatalogMetadata: true,
|
|
770
|
+
limit: MAX_CATALOG_DASHBOARD_SUMMARIES + 1,
|
|
653
771
|
},
|
|
654
772
|
),
|
|
655
773
|
listDictionaryEntries({ email: args.email, orgId: args.orgId }),
|
|
656
774
|
listFavoriteDashboardIds(args.email),
|
|
657
775
|
]);
|
|
658
|
-
|
|
659
|
-
favoriteIdsResult.status === "fulfilled"
|
|
660
|
-
? favoriteIdsResult.value
|
|
661
|
-
: new Set<string>();
|
|
776
|
+
args.signal?.throwIfAborted();
|
|
662
777
|
const savedSummaries =
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
778
|
+
summariesResult.status === "fulfilled" ? summariesResult.value : [];
|
|
779
|
+
const searchedSummaries = savedSummaries.slice(
|
|
780
|
+
0,
|
|
781
|
+
MAX_CATALOG_DASHBOARD_SUMMARIES,
|
|
782
|
+
);
|
|
783
|
+
const dashboardSearchTruncated =
|
|
784
|
+
savedSummaries.length > MAX_CATALOG_DASHBOARD_SUMMARIES;
|
|
785
|
+
if (dashboardSearchTruncated) {
|
|
786
|
+
console.warn("[analytics] Dashboard reference search truncated.", {
|
|
787
|
+
searchedDashboardCount: searchedSummaries.length,
|
|
788
|
+
dashboardSearchTruncated,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
666
791
|
const dictionaryEntries =
|
|
667
|
-
|
|
668
|
-
?
|
|
792
|
+
dictionaryResult.status === "fulfilled"
|
|
793
|
+
? dictionaryResult.value.entries
|
|
669
794
|
: [];
|
|
795
|
+
const searchedDictionaryEntryCount =
|
|
796
|
+
dictionaryResult.status === "fulfilled"
|
|
797
|
+
? dictionaryResult.value.searchedEntryCount
|
|
798
|
+
: 0;
|
|
799
|
+
const dictionarySearchTruncated =
|
|
800
|
+
dictionaryResult.status === "fulfilled" && dictionaryResult.value.truncated;
|
|
801
|
+
let dashboardSearchStatus: "available" | "unavailable" =
|
|
802
|
+
summariesResult.status === "fulfilled" ? "available" : "unavailable";
|
|
803
|
+
const dictionarySearchStatus =
|
|
804
|
+
dictionaryResult.status === "fulfilled"
|
|
805
|
+
? dictionaryResult.value.status
|
|
806
|
+
: "unavailable";
|
|
807
|
+
if (dictionarySearchTruncated) {
|
|
808
|
+
console.warn("[analytics] Data dictionary search truncated.", {
|
|
809
|
+
searchedDictionaryEntryCount,
|
|
810
|
+
dictionarySearchTruncated,
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
const favoriteIds =
|
|
814
|
+
favoritesResult.status === "fulfilled"
|
|
815
|
+
? favoritesResult.value
|
|
816
|
+
: new Set<string>();
|
|
817
|
+
if (summariesResult.status === "rejected") {
|
|
818
|
+
warnCatalogReadFailure("Dashboard summary", summariesResult.reason);
|
|
819
|
+
}
|
|
820
|
+
if (dictionaryResult.status === "rejected") {
|
|
821
|
+
warnCatalogReadFailure("Data dictionary", dictionaryResult.reason);
|
|
822
|
+
}
|
|
823
|
+
if (favoritesResult.status === "rejected") {
|
|
824
|
+
warnCatalogReadFailure("Favorite dashboard", favoritesResult.reason);
|
|
825
|
+
}
|
|
670
826
|
const savedSummaryIds = new Set(
|
|
671
827
|
savedSummaries.map((dashboard) => dashboard.id),
|
|
672
828
|
);
|
|
673
829
|
|
|
674
830
|
const shortlistedSummaries = shortlistDashboardSummaries(
|
|
675
831
|
args.search,
|
|
676
|
-
|
|
832
|
+
searchedSummaries,
|
|
677
833
|
args.limit,
|
|
678
834
|
favoriteIds,
|
|
679
835
|
);
|
|
680
836
|
const shortlistedIds = shortlistedSummaries.map((dashboard) => dashboard.id);
|
|
837
|
+
args.signal?.throwIfAborted();
|
|
681
838
|
const savedDashboardsResult = await loadDashboardCatalogDashboards(
|
|
682
839
|
{ email: args.email, orgId: args.orgId },
|
|
683
840
|
shortlistedIds,
|
|
684
|
-
)
|
|
841
|
+
).catch((error: unknown) => {
|
|
842
|
+
warnCatalogReadFailure("Dashboard detail", error);
|
|
843
|
+
dashboardSearchStatus = "unavailable";
|
|
844
|
+
return [];
|
|
845
|
+
});
|
|
846
|
+
args.signal?.throwIfAborted();
|
|
685
847
|
const savedDashboards = new Map(
|
|
686
848
|
savedDashboardsResult.map((dashboard) => [dashboard.id, dashboard]),
|
|
687
849
|
);
|
|
@@ -707,22 +869,31 @@ export async function searchAnalyticsQueryCatalog(args: {
|
|
|
707
869
|
}
|
|
708
870
|
});
|
|
709
871
|
|
|
710
|
-
return
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
872
|
+
return {
|
|
873
|
+
candidates: rankAnalyticsQueryCatalog({
|
|
874
|
+
search: args.search,
|
|
875
|
+
dashboards: [
|
|
876
|
+
...shortlistedSummaries.flatMap((summary) => {
|
|
877
|
+
const dashboard = savedDashboards.get(summary.id);
|
|
878
|
+
if (!dashboard) return [];
|
|
879
|
+
return [
|
|
880
|
+
savedDashboardInput(
|
|
881
|
+
{ ...summary, favorite: favoriteIds.has(summary.id) },
|
|
882
|
+
dashboard,
|
|
883
|
+
),
|
|
884
|
+
];
|
|
885
|
+
}),
|
|
886
|
+
// A truncated window cannot prove a shipped default has no saved version.
|
|
887
|
+
...(dashboardSearchTruncated ? [] : templateDashboards),
|
|
888
|
+
],
|
|
889
|
+
dictionaryEntries,
|
|
890
|
+
limit: args.limit,
|
|
891
|
+
}),
|
|
892
|
+
searchedDashboardCount: searchedSummaries.length,
|
|
893
|
+
dashboardSearchTruncated,
|
|
894
|
+
dashboardSearchStatus,
|
|
895
|
+
searchedDictionaryEntryCount,
|
|
896
|
+
dictionarySearchTruncated,
|
|
897
|
+
dictionarySearchStatus,
|
|
898
|
+
};
|
|
728
899
|
}
|
|
@@ -931,7 +931,7 @@ export const dashboardCatalogEntries: DashboardCatalogEntry[] = [
|
|
|
931
931
|
id: "first-party-template-traffic",
|
|
932
932
|
name: "First-party Template Traffic",
|
|
933
933
|
description:
|
|
934
|
-
"Template signups, activation and onboarding
|
|
934
|
+
"Template signups, activation and onboarding step/choice funnels, sharing actions, clicks, demo starts, CLI copies, activity, top URLs, top clips, retention by template, and active users over time.",
|
|
935
935
|
category: "Product",
|
|
936
936
|
defaultDashboardId: "agent-native-templates-first-party",
|
|
937
937
|
dataSources: ["first-party"],
|
|
@@ -948,7 +948,7 @@ export const dashboardCatalogEntries: DashboardCatalogEntry[] = [
|
|
|
948
948
|
"referrals",
|
|
949
949
|
"virality",
|
|
950
950
|
],
|
|
951
|
-
panelCount:
|
|
951
|
+
panelCount: 43,
|
|
952
952
|
version: CATALOG_VERSION,
|
|
953
953
|
recommended: true,
|
|
954
954
|
visibleInCatalog: false,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "@agent-native/core/sharing";
|
|
32
32
|
import {
|
|
33
33
|
and,
|
|
34
|
+
asc,
|
|
34
35
|
desc,
|
|
35
36
|
eq,
|
|
36
37
|
inArray,
|
|
@@ -220,18 +221,29 @@ interface AccessCtx {
|
|
|
220
221
|
*/
|
|
221
222
|
async function getScopedLegacySettings(
|
|
222
223
|
ctx: Pick<AccessCtx, "email" | "orgId">,
|
|
224
|
+
options?: { dashboardKind?: DashboardKind; limit?: number },
|
|
223
225
|
): Promise<Record<string, Record<string, unknown>>> {
|
|
224
226
|
// User scope first, then org: callers append these to the SQL rows in
|
|
225
227
|
// iteration order and never re-sort, so the order is user-visible. The
|
|
226
228
|
// previous full-table read inherited whatever order the settings table
|
|
227
229
|
// returned, which no query pinned.
|
|
228
230
|
const prefixes: string[] = [];
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
+
if (options?.dashboardKind === "sql") {
|
|
232
|
+
if (ctx.email) prefixes.push(`u:${ctx.email}:${SQL_PREFIX}`);
|
|
233
|
+
if (ctx.orgId) prefixes.push(`o:${ctx.orgId}:${SQL_PREFIX}`);
|
|
234
|
+
} else {
|
|
235
|
+
if (ctx.email) prefixes.push(`u:${ctx.email}:`);
|
|
236
|
+
if (ctx.orgId) prefixes.push(`o:${ctx.orgId}:`);
|
|
237
|
+
}
|
|
231
238
|
if (prefixes.length === 0) return {};
|
|
232
239
|
const scoped: Record<string, Record<string, unknown>> = {};
|
|
233
240
|
for (const entries of await Promise.all(
|
|
234
|
-
prefixes.map((prefix) =>
|
|
241
|
+
prefixes.map((prefix) =>
|
|
242
|
+
listSettingsByPrefix(
|
|
243
|
+
prefix,
|
|
244
|
+
options?.limit === undefined ? undefined : { limit: options.limit },
|
|
245
|
+
),
|
|
246
|
+
),
|
|
235
247
|
)) {
|
|
236
248
|
for (const { key, value } of entries) scoped[key] = value;
|
|
237
249
|
}
|
|
@@ -956,6 +968,7 @@ export async function listDashboardSummaries(
|
|
|
956
968
|
hidden?: DashboardHiddenFilter;
|
|
957
969
|
includeCatalogMetadata?: boolean;
|
|
958
970
|
legacyScan?: "best-effort" | "strict";
|
|
971
|
+
limit?: number;
|
|
959
972
|
},
|
|
960
973
|
dbOverride?: any,
|
|
961
974
|
): Promise<DashboardSummaryRecord[]> {
|
|
@@ -963,6 +976,15 @@ export async function listDashboardSummaries(
|
|
|
963
976
|
const archived = filter?.archived ?? "active";
|
|
964
977
|
const hidden = filter?.hidden ?? "visible";
|
|
965
978
|
const includeCatalogMetadata = filter?.includeCatalogMetadata === true;
|
|
979
|
+
const summaryLimit = filter?.limit;
|
|
980
|
+
if (
|
|
981
|
+
summaryLimit !== undefined &&
|
|
982
|
+
(!Number.isSafeInteger(summaryLimit) || summaryLimit < 0)
|
|
983
|
+
) {
|
|
984
|
+
throw new RangeError(
|
|
985
|
+
"Dashboard summary limit must be a non-negative integer.",
|
|
986
|
+
);
|
|
987
|
+
}
|
|
966
988
|
const conditions: any[] = [
|
|
967
989
|
accessFilter(schema.dashboards, schema.dashboardShares, {
|
|
968
990
|
userEmail: ctx.email,
|
|
@@ -993,7 +1015,7 @@ export async function listDashboardSummaries(
|
|
|
993
1015
|
const demoId = sql<
|
|
994
1016
|
string | null
|
|
995
1017
|
>`(${schema.dashboards.config}::jsonb -> 'demo' ->> 'id')`;
|
|
996
|
-
const
|
|
1018
|
+
const rowsQuery = db
|
|
997
1019
|
.select({
|
|
998
1020
|
id: schema.dashboards.id,
|
|
999
1021
|
kind: schema.dashboards.kind,
|
|
@@ -1016,6 +1038,11 @@ export async function listDashboardSummaries(
|
|
|
1016
1038
|
})
|
|
1017
1039
|
.from(schema.dashboards)
|
|
1018
1040
|
.where(where);
|
|
1041
|
+
const rows = await (summaryLimit === undefined
|
|
1042
|
+
? rowsQuery
|
|
1043
|
+
: rowsQuery
|
|
1044
|
+
.orderBy(desc(schema.dashboards.updatedAt), asc(schema.dashboards.id))
|
|
1045
|
+
.limit(summaryLimit));
|
|
1019
1046
|
const out: DashboardSummaryRecord[] = rows.map((row: any) => {
|
|
1020
1047
|
const certification = parseDashboardCertification(row.certification);
|
|
1021
1048
|
const { certification: _rawCertification, ...summaryRow } = row;
|
|
@@ -1041,10 +1068,17 @@ export async function listDashboardSummaries(
|
|
|
1041
1068
|
});
|
|
1042
1069
|
const seen = new Set(out.map((row) => row.id));
|
|
1043
1070
|
|
|
1071
|
+
if (summaryLimit !== undefined && out.length >= summaryLimit) return out;
|
|
1044
1072
|
if (archived === "archived" || hidden === "hidden") return out;
|
|
1045
1073
|
try {
|
|
1046
|
-
const all = await getScopedLegacySettings(
|
|
1074
|
+
const all = await getScopedLegacySettings(
|
|
1075
|
+
ctx,
|
|
1076
|
+
summaryLimit === undefined
|
|
1077
|
+
? undefined
|
|
1078
|
+
: { dashboardKind: filter?.kind, limit: summaryLimit },
|
|
1079
|
+
);
|
|
1047
1080
|
for (const [key, value] of Object.entries(all)) {
|
|
1081
|
+
if (summaryLimit !== undefined && out.length >= summaryLimit) break;
|
|
1048
1082
|
let id: string | null = null;
|
|
1049
1083
|
let kind: DashboardKind | null = null;
|
|
1050
1084
|
let orgId: string | null = null;
|
|
@@ -59,6 +59,10 @@ function renderEntry(
|
|
|
59
59
|
|
|
60
60
|
const table = compact(entry.table, 240);
|
|
61
61
|
if (table) lines.push(` - table: ${table}`);
|
|
62
|
+
const source = compact(entry.source, 240);
|
|
63
|
+
if (source) lines.push(` - source: ${source}`);
|
|
64
|
+
const action = compact(entry.action, 160);
|
|
65
|
+
if (action) lines.push(` - query action: ${action}`);
|
|
62
66
|
const columns = compact(entry.columnsUsed, 360);
|
|
63
67
|
if (columns) lines.push(` - columns: ${columns}`);
|
|
64
68
|
const cuts = compact(entry.cuts, 240);
|