@agent-native/core-corpus 0.201.0-nightly-20261005153421 → 0.201.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +14 -4
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/analytics/CHANGELOG.md +6 -0
- package/corpus/templates/analytics/README.md +2 -2
- package/corpus/templates/analytics/changelog/2026-10-02-events-with-a-very-long-name-app-or-page-path-no-longer-caus.md +6 -0
- package/corpus/templates/analytics/package.json +1 -0
- package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -19
- package/corpus/templates/analytics/server/handlers/session-replay.ts +34 -47
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -36
- package/corpus/templates/analytics/server/lib/indexed-text.ts +53 -0
- package/corpus/templates/analytics/server/lib/request-errors.ts +73 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +6 -16
- package/corpus/templates/analytics/server/lib/session-replay.ts +12 -2
- package/corpus/templates/analytics/server/plugins/auth.ts +2 -1
- package/corpus/templates/analytics/server/plugins/otel.ts +6 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/assets/CHANGELOG.md +7 -0
- package/corpus/templates/assets/README.md +2 -2
- package/corpus/templates/assets/package.json +1 -0
- package/corpus/templates/assets/server/plugins/auth.ts +2 -1
- package/corpus/templates/assets/server/plugins/otel.ts +6 -0
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +2 -1
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +5 -4
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/brain/README.md +12 -8
- package/corpus/templates/brain/changelog/2026-10-05-private-slack-channels-are-searchable-org-wide.md +6 -0
- package/corpus/templates/brain/package.json +1 -0
- package/corpus/templates/brain/server/lib/audiences.ts +1 -98
- package/corpus/templates/brain/server/lib/connectors.ts +2 -166
- package/corpus/templates/brain/server/plugins/otel.ts +6 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/calendar/CHANGELOG.md +7 -0
- package/corpus/templates/calendar/README.md +2 -2
- package/corpus/templates/calendar/package.json +1 -0
- package/corpus/templates/calendar/server/plugins/auth.ts +2 -1
- package/corpus/templates/calendar/server/plugins/otel.ts +6 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/chat/README.md +2 -2
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +9 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/clips/CHANGELOG.md +24 -0
- package/corpus/templates/clips/README.md +2 -2
- package/corpus/templates/clips/actions/lib/audio-chunk-list.ts +23 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +187 -292
- package/corpus/templates/clips/actions/lib/chunked-transcription.ts +151 -0
- package/corpus/templates/clips/actions/lib/recording-audio-source.ts +191 -0
- package/corpus/templates/clips/actions/request-transcript.ts +81 -135
- package/corpus/templates/clips/actions/search-recordings.ts +19 -5
- package/corpus/templates/clips/app/components/clips-command-menu.tsx +5 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -1
- package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -0
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
- package/corpus/templates/clips/app/lib/local-recording-upload.ts +13 -6
- package/corpus/templates/clips/app/lib/recording-section.ts +1 -1
- package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +7 -5
- package/corpus/templates/clips/app/routes/record.tsx +16 -6
- package/corpus/templates/clips/changelog/2026-10-02-long-uploads-an-hour-or-more-now-transcribe-reliably-instead.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-confirming-discard-recording-now-returns-you-to-your-library.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recording-now-removes-its-failed-upload-card-fr.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recovered-recording-no-longer-warns-that-it-s-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-search-results-identify-recordings-in-trash-and-open-them-wi.md +6 -0
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/server/lib/builder-cdn.ts +5 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +2 -2
- package/corpus/templates/clips/server/plugins/auth.ts +2 -1
- package/corpus/templates/clips/server/plugins/otel.ts +6 -0
- package/corpus/templates/clips/shared/transcript-failure.ts +5 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
- package/corpus/templates/content/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/content/CHANGELOG.md +41 -0
- package/corpus/templates/content/README.md +2 -2
- package/corpus/templates/content/actions/_database-navigation.ts +523 -344
- package/corpus/templates/content/actions/_database-row-mutation.ts +44 -10
- package/corpus/templates/content/actions/_database-setup-discovery.ts +9 -3
- package/corpus/templates/content/actions/_database-utils.ts +299 -271
- package/corpus/templates/content/actions/_property-utils.ts +293 -190
- package/corpus/templates/content/actions/_relation-values.ts +3 -1
- package/corpus/templates/content/actions/get-content-database.ts +1 -0
- package/corpus/templates/content/actions/query-content-database-items.ts +32 -5
- package/corpus/templates/content/actions/set-document-property.ts +17 -11
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -43
- package/corpus/templates/content/app/components/editor/DocumentEditorSkeleton.tsx +159 -50
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +12 -28
- package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +6 -1
- package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +16 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +180 -75
- package/corpus/templates/content/app/components/editor/database/DatabaseViewSkeleton.tsx +76 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +60 -2
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +41 -42
- package/corpus/templates/content/app/components/editor/document-editor-layout.ts +18 -0
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +11 -3
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +15 -7
- package/corpus/templates/content/app/components/editor/suggestions/model.ts +13 -0
- package/corpus/templates/content/app/components/editor/suggestions/read-only-blocks.ts +136 -0
- package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
- package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +1 -1
- package/corpus/templates/content/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +57 -16
- package/corpus/templates/content/app/components/sidebar/MovePageDialog.tsx +4 -4
- package/corpus/templates/content/app/components/sidebar/SidebarNavigationRow.tsx +34 -10
- package/corpus/templates/content/app/global.css +16 -8
- package/corpus/templates/content/app/hooks/content-action-refresh.ts +14 -13
- package/corpus/templates/content/app/hooks/use-content-database.ts +72 -9
- package/corpus/templates/content/app/hooks/use-content-personal-navigation.ts +7 -3
- package/corpus/templates/content/app/hooks/use-documents.ts +27 -0
- package/corpus/templates/content/app/i18n-data.ts +3 -2
- package/corpus/templates/content/app/lib/content-landing.ts +3 -31
- package/corpus/templates/content/app/lib/files-navigation.ts +182 -10
- package/corpus/templates/content/app/lib/files-root-hint.ts +20 -32
- package/corpus/templates/content/app/lib/page-startup-hints.ts +108 -0
- package/corpus/templates/content/app/lib/private-link-redirect.ts +25 -0
- package/corpus/templates/content/app/lib/sidebar-layout-hint.ts +34 -1
- package/corpus/templates/content/app/lib/startup-timing.ts +2 -0
- package/corpus/templates/content/app/root.tsx +3 -1
- package/corpus/templates/content/app/routes/_app.home.tsx +10 -19
- package/corpus/templates/content/app/routes/p.$id.tsx +23 -5
- package/corpus/templates/content/changelog/2026-10-02-a-page-link-you-cant-open-now-says-so-instead-of-opening-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-after-a-refresh-the-files-sidebar-shows-the-open-page-s-fold.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-large-collections-open-faster.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-with-open-comments-and-collections-with-sorted-or-filt.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-suggest-edits-works-on-pages-written-by-agents-including-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-while-you-suggest-edits-tables-and-other-blocks-that-suggest.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-view-context-now-survives-quick-page-changes-when.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-views-keep-their-saved-rows-accurate-during-refre.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-exact-saved-view-links-keep-collection-retry-available.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-expanding-a-files-folder-now-shares-one-navigation-read-acro.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-files-navigation-retries-temporary-failures-consistently.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-shared-page-owners-keep-edit-and-manage-controls-in-files-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-tagging-an-ai-in-a-comment-works-again-instead-of-failing-ri.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-the-home-loading-shell-keeps-the-layout-of-your-last-opened-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-typing-and-a-space-or-inserting-a-toggle-or-callout-no-longe.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +4 -1
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/content/package.json +2 -1
- package/corpus/templates/content/scripts/seed-perf-database.mjs +600 -0
- package/corpus/templates/content/scripts/trace-startup.mjs +25 -3
- package/corpus/templates/content/server/db/index.ts +1 -1
- package/corpus/templates/content/server/lib/suggested-edits.ts +23 -26
- package/corpus/templates/content/server/plugins/auth.ts +2 -1
- package/corpus/templates/content/server/plugins/otel.ts +6 -0
- package/corpus/templates/content/shared/api.ts +17 -0
- package/corpus/templates/content/shared/suggestion-diff.ts +124 -38
- package/corpus/templates/content/shared/suggestion-formatting.ts +134 -3
- package/corpus/templates/crm/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/crm/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/crm/package.json +1 -0
- package/corpus/templates/crm/server/plugins/otel.ts +6 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/design/CHANGELOG.md +41 -0
- package/corpus/templates/design/README.md +2 -2
- package/corpus/templates/design/actions/list-designs.ts +11 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +110 -32
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +28 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -0
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +79 -0
- package/corpus/templates/design/app/components/layout/Header.tsx +2 -4
- package/corpus/templates/design/app/components/ui/tabs.tsx +59 -1
- package/corpus/templates/design/app/global.css +1 -34
- package/corpus/templates/design/app/i18n/en-US.ts +4 -0
- package/corpus/templates/design/app/lib/design-filter.ts +4 -2
- package/corpus/templates/design/app/pages/Index.tsx +91 -59
- package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +58 -17
- package/corpus/templates/design/changelog/2026-10-01-filter-designs-by-owner.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-layers-dropped-into-visible-canvas-space-beyond-a-screen-now.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-visible-screen-overflow-no-longer-routes-drops-to-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
- package/corpus/templates/design/package.json +1 -0
- package/corpus/templates/design/server/plugins/auth.ts +2 -1
- package/corpus/templates/design/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/dispatch/README.md +2 -2
- package/corpus/templates/dispatch/package.json +1 -0
- package/corpus/templates/dispatch/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +2 -1
- package/corpus/templates/factory/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/plugins/otel.ts +6 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/forms/README.md +2 -2
- package/corpus/templates/forms/package.json +1 -0
- package/corpus/templates/forms/server/plugins/auth.ts +2 -1
- package/corpus/templates/forms/server/plugins/otel.ts +6 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/mail/CHANGELOG.md +6 -0
- package/corpus/templates/mail/README.md +2 -2
- package/corpus/templates/mail/package.json +1 -0
- package/corpus/templates/mail/server/plugins/auth.ts +2 -1
- package/corpus/templates/mail/server/plugins/otel.ts +6 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/plan/CHANGELOG.md +1 -0
- package/corpus/templates/plan/README.md +2 -2
- package/corpus/templates/plan/package.json +1 -0
- package/corpus/templates/plan/server/plugins/auth.ts +2 -1
- package/corpus/templates/plan/server/plugins/otel.ts +6 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/slides/CHANGELOG.md +23 -0
- package/corpus/templates/slides/README.md +2 -2
- package/corpus/templates/slides/actions/list-decks.ts +11 -4
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +44 -36
- package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +79 -0
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -15
- package/corpus/templates/slides/app/components/ui/tabs.tsx +59 -0
- package/corpus/templates/slides/app/global.css +3 -54
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/lib/deck-filter.ts +5 -2
- package/corpus/templates/slides/app/pages/Index.tsx +102 -88
- package/corpus/templates/slides/changelog/2026-10-01-filter-decks-by-owner.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-02-hide-recent-until-decks-available.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +8 -0
- package/corpus/templates/slides/server/plugins/auth.ts +2 -1
- package/corpus/templates/slides/server/plugins/otel.ts +6 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +12 -7
- package/package.json +1 -1
|
@@ -8,10 +8,7 @@ import type {
|
|
|
8
8
|
BrainSourceProvider,
|
|
9
9
|
} from "../../shared/types.js";
|
|
10
10
|
import { getDb, schema } from "../db/index.js";
|
|
11
|
-
import {
|
|
12
|
-
listAccessibleAudienceIds,
|
|
13
|
-
refreshSlackPrivateChannelAudience,
|
|
14
|
-
} from "./audiences.js";
|
|
11
|
+
import { listAccessibleAudienceIds } from "./audiences.js";
|
|
15
12
|
import {
|
|
16
13
|
BrainCaptureBlockedError,
|
|
17
14
|
createCapture,
|
|
@@ -245,28 +242,6 @@ interface SlackListResponse {
|
|
|
245
242
|
response_metadata?: { next_cursor?: string };
|
|
246
243
|
}
|
|
247
244
|
|
|
248
|
-
interface SlackMembersResponse {
|
|
249
|
-
members?: string[];
|
|
250
|
-
response_metadata?: { next_cursor?: string };
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
interface SlackUserInfoResponse {
|
|
254
|
-
user?: {
|
|
255
|
-
deleted?: boolean;
|
|
256
|
-
is_app_user?: boolean;
|
|
257
|
-
is_bot?: boolean;
|
|
258
|
-
is_workflow_bot?: boolean;
|
|
259
|
-
profile?: { email?: string };
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
type SlackUserEmailCacheEntry =
|
|
264
|
-
| { kind: "human"; email: string }
|
|
265
|
-
| { kind: "non-human" }
|
|
266
|
-
| { kind: "unresolved" };
|
|
267
|
-
type SlackUserEmailCache = Map<string, SlackUserEmailCacheEntry>;
|
|
268
|
-
|
|
269
|
-
const SLACK_USER_LOOKUP_CONCURRENCY = 4;
|
|
270
245
|
const SLACK_THREAD_CAPTURE_CONCURRENCY = 4;
|
|
271
246
|
const GRANOLA_NOTE_CAPTURE_CONCURRENCY = 4;
|
|
272
247
|
const CONNECTOR_SYNC_LEASE_MS = 10 * 60 * 1_000;
|
|
@@ -1073,94 +1048,6 @@ async function slackPermalink(
|
|
|
1073
1048
|
return data.permalink ?? null;
|
|
1074
1049
|
}
|
|
1075
1050
|
|
|
1076
|
-
async function slackPrivateChannelMemberEmails(
|
|
1077
|
-
token: string,
|
|
1078
|
-
channelId: string,
|
|
1079
|
-
userEmailCache: SlackUserEmailCache,
|
|
1080
|
-
): Promise<string[] | null> {
|
|
1081
|
-
const memberIds = new Set<string>();
|
|
1082
|
-
const seenCursors = new Set<string>();
|
|
1083
|
-
let cursor: string | undefined;
|
|
1084
|
-
while (true) {
|
|
1085
|
-
const response = await slackApi<SlackMembersResponse>(
|
|
1086
|
-
token,
|
|
1087
|
-
"conversations.members",
|
|
1088
|
-
{ channel: channelId, limit: 1_000, cursor },
|
|
1089
|
-
);
|
|
1090
|
-
if (
|
|
1091
|
-
!Array.isArray(response.members) ||
|
|
1092
|
-
response.members.some(
|
|
1093
|
-
(memberId) => typeof memberId !== "string" || !memberId,
|
|
1094
|
-
)
|
|
1095
|
-
) {
|
|
1096
|
-
return null;
|
|
1097
|
-
}
|
|
1098
|
-
for (const memberId of response.members) {
|
|
1099
|
-
memberIds.add(memberId);
|
|
1100
|
-
}
|
|
1101
|
-
const nextCursor = response.response_metadata?.next_cursor?.trim();
|
|
1102
|
-
if (!nextCursor) break;
|
|
1103
|
-
if (seenCursors.has(nextCursor)) return null;
|
|
1104
|
-
seenCursors.add(nextCursor);
|
|
1105
|
-
cursor = nextCursor;
|
|
1106
|
-
}
|
|
1107
|
-
const userIds = Array.from(memberIds);
|
|
1108
|
-
if (
|
|
1109
|
-
userIds.some((userId) => userEmailCache.get(userId)?.kind === "unresolved")
|
|
1110
|
-
) {
|
|
1111
|
-
return null;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
const uncachedUserIds = userIds.filter(
|
|
1115
|
-
(userId) => !userEmailCache.has(userId),
|
|
1116
|
-
);
|
|
1117
|
-
for (
|
|
1118
|
-
let offset = 0;
|
|
1119
|
-
offset < uncachedUserIds.length;
|
|
1120
|
-
offset += SLACK_USER_LOOKUP_CONCURRENCY
|
|
1121
|
-
) {
|
|
1122
|
-
const batch = uncachedUserIds.slice(
|
|
1123
|
-
offset,
|
|
1124
|
-
offset + SLACK_USER_LOOKUP_CONCURRENCY,
|
|
1125
|
-
);
|
|
1126
|
-
await Promise.all(
|
|
1127
|
-
batch.map(async (userId) => {
|
|
1128
|
-
const user = await slackApi<SlackUserInfoResponse>(
|
|
1129
|
-
token,
|
|
1130
|
-
"users.info",
|
|
1131
|
-
{ user: userId },
|
|
1132
|
-
);
|
|
1133
|
-
const slackUser = user.user;
|
|
1134
|
-
if (
|
|
1135
|
-
slackUser?.deleted === true ||
|
|
1136
|
-
slackUser?.is_app_user === true ||
|
|
1137
|
-
slackUser?.is_bot === true ||
|
|
1138
|
-
slackUser?.is_workflow_bot === true
|
|
1139
|
-
) {
|
|
1140
|
-
userEmailCache.set(userId, { kind: "non-human" });
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
const email = slackUser?.profile?.email?.trim().toLowerCase();
|
|
1144
|
-
userEmailCache.set(
|
|
1145
|
-
userId,
|
|
1146
|
-
email ? { kind: "human", email } : { kind: "unresolved" },
|
|
1147
|
-
);
|
|
1148
|
-
}),
|
|
1149
|
-
);
|
|
1150
|
-
if (
|
|
1151
|
-
batch.some((userId) => userEmailCache.get(userId)?.kind === "unresolved")
|
|
1152
|
-
) {
|
|
1153
|
-
return null;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
const emails = userIds.flatMap((userId) => {
|
|
1158
|
-
const entry = userEmailCache.get(userId);
|
|
1159
|
-
return entry?.kind === "human" ? [entry.email] : [];
|
|
1160
|
-
});
|
|
1161
|
-
return Array.from(new Set(emails)).sort();
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
1051
|
function configuredSlackChannelIds(config: Record<string, unknown>) {
|
|
1165
1052
|
return new Set(
|
|
1166
1053
|
slackChannelRefsFromConfig(config).filter((value) =>
|
|
@@ -1175,7 +1062,6 @@ async function createSlackThreadCapture(input: {
|
|
|
1175
1062
|
messages: SlackMessage[];
|
|
1176
1063
|
permalink: string | null;
|
|
1177
1064
|
syncRunId?: string;
|
|
1178
|
-
memberEmails?: string[] | null;
|
|
1179
1065
|
}) {
|
|
1180
1066
|
const normalized = normalizeSlackThreadCapture({
|
|
1181
1067
|
channel: input.channel,
|
|
@@ -1193,11 +1079,7 @@ async function createSlackThreadCapture(input: {
|
|
|
1193
1079
|
content: normalized.content,
|
|
1194
1080
|
capturedAt: normalized.capturedAt,
|
|
1195
1081
|
metadata: normalized.metadata,
|
|
1196
|
-
audience: {
|
|
1197
|
-
kind: input.channel.is_private ? "slack-private-channel" : "org",
|
|
1198
|
-
memberEmails: input.memberEmails ?? undefined,
|
|
1199
|
-
upstreamRefHash: input.channel.id,
|
|
1200
|
-
},
|
|
1082
|
+
audience: { kind: "org", upstreamRefHash: input.channel.id },
|
|
1201
1083
|
});
|
|
1202
1084
|
return { capture, blocked: false };
|
|
1203
1085
|
} catch (error) {
|
|
@@ -2468,7 +2350,6 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2468
2350
|
}
|
|
2469
2351
|
const channels = [...channelsById.values()];
|
|
2470
2352
|
stats.eligibleChannels = channels.length;
|
|
2471
|
-
const userEmailCache: SlackUserEmailCache = new Map();
|
|
2472
2353
|
|
|
2473
2354
|
const channelsToScan = includePublicChannels
|
|
2474
2355
|
? (() => {
|
|
@@ -2510,29 +2391,6 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2510
2391
|
stats.publicChannelsAlreadyJoined =
|
|
2511
2392
|
Number(stats.publicChannelsAlreadyJoined) + 1;
|
|
2512
2393
|
}
|
|
2513
|
-
const privateMemberEmails = channel.is_private
|
|
2514
|
-
? await slackPrivateChannelMemberEmails(
|
|
2515
|
-
token,
|
|
2516
|
-
channel.id,
|
|
2517
|
-
userEmailCache,
|
|
2518
|
-
)
|
|
2519
|
-
: null;
|
|
2520
|
-
if (channel.is_private) {
|
|
2521
|
-
if (privateMemberEmails === null) {
|
|
2522
|
-
stats.rejectedChannels = Number(stats.rejectedChannels) + 1;
|
|
2523
|
-
continue;
|
|
2524
|
-
}
|
|
2525
|
-
await refreshSlackPrivateChannelAudience({
|
|
2526
|
-
source,
|
|
2527
|
-
channelId: channel.id,
|
|
2528
|
-
memberEmails: privateMemberEmails,
|
|
2529
|
-
});
|
|
2530
|
-
if (!privateMemberEmails.length) {
|
|
2531
|
-
stats.rejectedChannels = Number(stats.rejectedChannels) + 1;
|
|
2532
|
-
continue;
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
|
|
2536
2394
|
stats.scannedChannels = Number(stats.scannedChannels) + 1;
|
|
2537
2395
|
const channelCursor = nextCursor.channels?.[channel.id] ?? {};
|
|
2538
2396
|
const pendingLatest =
|
|
@@ -2579,7 +2437,6 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2579
2437
|
messages: thread.messages?.length ? thread.messages : [message],
|
|
2580
2438
|
permalink,
|
|
2581
2439
|
syncRunId: runId,
|
|
2582
|
-
memberEmails: privateMemberEmails,
|
|
2583
2440
|
});
|
|
2584
2441
|
}),
|
|
2585
2442
|
);
|
|
@@ -2838,26 +2695,6 @@ export async function refreshSlackThreadCapture(
|
|
|
2838
2695
|
`Slack thread refresh rejected for channel ${channelId}: it matches a Brain public-channel exclusion`,
|
|
2839
2696
|
);
|
|
2840
2697
|
}
|
|
2841
|
-
const memberEmails = channel.is_private
|
|
2842
|
-
? await slackPrivateChannelMemberEmails(token, channel.id, new Map())
|
|
2843
|
-
: null;
|
|
2844
|
-
if (channel.is_private) {
|
|
2845
|
-
if (memberEmails === null) {
|
|
2846
|
-
throw new Error(
|
|
2847
|
-
`Slack private channel ${channel.id} has no resolvable member emails; refusing to refresh without an ACL`,
|
|
2848
|
-
);
|
|
2849
|
-
}
|
|
2850
|
-
if (!memberEmails.length) {
|
|
2851
|
-
await refreshSlackPrivateChannelAudience({
|
|
2852
|
-
source,
|
|
2853
|
-
channelId: channel.id,
|
|
2854
|
-
memberEmails,
|
|
2855
|
-
});
|
|
2856
|
-
throw new Error(
|
|
2857
|
-
`Slack private channel ${channel.id} has no human members; refusing to refresh a capture`,
|
|
2858
|
-
);
|
|
2859
|
-
}
|
|
2860
|
-
}
|
|
2861
2698
|
const [thread, permalink] = await Promise.all([
|
|
2862
2699
|
slackApi<SlackRepliesResponse>(token, "conversations.replies", {
|
|
2863
2700
|
channel: channel.id,
|
|
@@ -2872,7 +2709,6 @@ export async function refreshSlackThreadCapture(
|
|
|
2872
2709
|
messages: thread.messages ?? [],
|
|
2873
2710
|
permalink,
|
|
2874
2711
|
syncRunId: runId,
|
|
2875
|
-
memberEmails,
|
|
2876
2712
|
});
|
|
2877
2713
|
const stats = {
|
|
2878
2714
|
channelId: channel.id,
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-02
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Builder.io setup copy now clarifies account activation and sign-in.
|
|
11
|
+
- Owners and admins can save Apollo, HubSpot, Gong, and Pylon keys for the whole organization or just for themselves.
|
|
12
|
+
|
|
6
13
|
## 2026-10-01
|
|
7
14
|
|
|
8
15
|
### Improved
|
|
@@ -4,7 +4,7 @@ An open-source, agent-native alternative to the Google Calendar + Calendly combo
|
|
|
4
4
|
An agent-powered calendar with Google Calendar sync and Calendly-style public
|
|
5
5
|
booking links — schedule, find slots, and manage availability in plain English.
|
|
6
6
|
|
|
7
|
-
**Live app: [calendar.agent-native.com](https://calendar.agent-native.com)**
|
|
7
|
+
**Live app: [calendar.agent-native.com](https://calendar.agent-native.com?utm_source=github&utm_medium=referral&utm_content=calendar-readme)**
|
|
8
8
|
|
|
9
9
|
Connect your Google Calendar and the agent can read your schedule, find free
|
|
10
10
|
slots, create events, and manage booking links. Anything you can do in the UI,
|
|
@@ -33,4 +33,4 @@ pnpm dev
|
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Connecting Google Calendar in dev needs a Google OAuth client — see the docs for
|
|
36
|
-
setup. Full docs: [agent-native.com/docs/template-calendar](https://agent-native.com/docs/template-calendar).
|
|
36
|
+
setup. Full docs: [agent-native.com/docs/template-calendar](https://agent-native.com/docs/template-calendar?utm_source=github&utm_medium=referral&utm_content=calendar-readme).
|
|
@@ -6,7 +6,8 @@ export default createAuthPlugin({
|
|
|
6
6
|
workspaceAppPublicPaths: ["/"],
|
|
7
7
|
marketing: {
|
|
8
8
|
appName: "Calendar",
|
|
9
|
-
learnMoreUrl:
|
|
9
|
+
learnMoreUrl:
|
|
10
|
+
"https://agent-native.com/apps/calendar?utm_source=app&utm_medium=product&utm_content=onboarding-learn-more",
|
|
10
11
|
tagline:
|
|
11
12
|
"Your AI agent schedules, reschedules, and manages your calendar so you never have to.",
|
|
12
13
|
features: [
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -5,7 +5,7 @@ the center, durable threads, standard app navigation, auth, live sync, and
|
|
|
5
5
|
actions. Start here when you want a real browser app to build on without
|
|
6
6
|
committing to a domain template.
|
|
7
7
|
|
|
8
|
-
**Live app: [chat.agent-native.com](https://chat.agent-native.com)**
|
|
8
|
+
**Live app: [chat.agent-native.com](https://chat.agent-native.com?utm_source=github&utm_medium=referral&utm_content=chat-readme)**
|
|
9
9
|
|
|
10
10
|
Chat is the basic agent-native app starting point. It gives you the app-agent
|
|
11
11
|
loop wired end to end and one example action, so you can add your own UI, data,
|
|
@@ -30,4 +30,4 @@ pnpm install
|
|
|
30
30
|
pnpm dev
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat).
|
|
33
|
+
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat?utm_source=github&utm_medium=referral&utm_content=chat-readme).
|
|
@@ -131,6 +131,15 @@ Transcription takes an audio file and returns text + segments. That's not a prom
|
|
|
131
131
|
2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments. Retry a failed transcript with `force: true`; pass `regenerate: true` to replace an existing ready transcript from the stored recording media. Regeneration keeps the prior ready transcript available if the new provider attempt fails.
|
|
132
132
|
3. **Cloud fallback — Groq Whisper.** `GROQ_API_KEY` → `https://api.groq.com/openai/v1/audio/transcriptions`, model `whisper-large-v3-turbo`. Fast (~$0.04/hour of audio) Whisper-compatible speech-to-text used when Builder is unavailable.
|
|
133
133
|
|
|
134
|
+
Cloud transcription always re-encodes the audio to mono 16 kHz and splits it
|
|
135
|
+
into parts of about 15 minutes, transcribed a few at a time and stitched back on
|
|
136
|
+
the recording timeline. Long uploads therefore transcribe like short ones; do
|
|
137
|
+
not tell users a recording is "too long" to transcribe. The provider numbers
|
|
138
|
+
speakers per part, so in a multi-part transcript the same label may refer to
|
|
139
|
+
different people in different parts. If any part still fails after one retry, nothing is saved and the transcript fails with `CHUNK_FAILED`;
|
|
140
|
+
`transcript-cleanup-<id>` in application state records which part failed and
|
|
141
|
+
the provider error. Retry with `request-transcript` and `force: true`.
|
|
142
|
+
|
|
134
143
|
The transcript included by `view-screen` is only a bounded preview. When its
|
|
135
144
|
`previewTruncated` field is true, the preview may end mid-sentence and does not
|
|
136
145
|
show where transcription ended. Call `get-recording-player-data` before
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -3,10 +3,34 @@
|
|
|
3
3
|
All notable user-facing changes to Clips are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-05
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Confirming Discard recording now returns you to your library.
|
|
11
|
+
- Discarding a recording now removes its failed upload card from your library.
|
|
12
|
+
- Discarding a recovered recording no longer warns that it's open in another tab.
|
|
13
|
+
- Search results identify recordings in Trash and open them with Trash navigation.
|
|
14
|
+
|
|
15
|
+
## 2026-10-03
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Invalid Lab choices can be repaired from Labs settings.
|
|
20
|
+
|
|
6
21
|
## 2026-10-02
|
|
7
22
|
|
|
23
|
+
### Improved
|
|
24
|
+
|
|
25
|
+
- Builder.io setup now offers one-click activation and clear existing-account sign-in.
|
|
26
|
+
|
|
8
27
|
### Fixed
|
|
9
28
|
|
|
29
|
+
- Cancelled Rewind Clip setup can be retried immediately
|
|
30
|
+
- Long uploads (an hour or more) now transcribe reliably instead of failing.
|
|
31
|
+
- Recording countdowns begin during setup, with explicit cue outcomes and startup timing
|
|
32
|
+
- Recording visibility defaults no longer switch to Public when saved settings cannot be read.
|
|
33
|
+
- Screen recording startup now cleans up canceled Rewind setup and keeps countdown timing reliable on older macOS.
|
|
10
34
|
- Recording reminders and other actionable notifications show their message above the buttons
|
|
11
35
|
- Temporary upload authorization failures remain retryable, while permanently rejected Builder credentials trigger storage setup errors.
|
|
12
36
|
|
|
@@ -4,7 +4,7 @@ An open-source, agent-native alternative to Loom, Granola, and Wispr Flow rolled
|
|
|
4
4
|
into one app. Screen recording, calendar-synced meeting notes, and push-to-talk
|
|
5
5
|
voice dictation — all transcribed, searchable, and yours to own.
|
|
6
6
|
|
|
7
|
-
**Live app: [clips.agent-native.com](https://clips.agent-native.com)**
|
|
7
|
+
**Live app: [clips.agent-native.com](https://clips.agent-native.com?utm_source=github&utm_medium=referral&utm_content=clips-readme)**
|
|
8
8
|
|
|
9
9
|
The agent transcribes, titles, summarizes, and indexes everything you capture,
|
|
10
10
|
then lets you ask "find the clip where we discussed the rollout plan" across every
|
|
@@ -34,4 +34,4 @@ pnpm dev
|
|
|
34
34
|
|
|
35
35
|
Clips needs a video storage backend (Builder.io or an S3-compatible bucket)
|
|
36
36
|
before recordings can upload — see the docs for setup.
|
|
37
|
-
Full docs: [agent-native.com/docs/template-clips](https://agent-native.com/docs/template-clips).
|
|
37
|
+
Full docs: [agent-native.com/docs/template-clips](https://agent-native.com/docs/template-clips?utm_source=github&utm_medium=referral&utm_content=clips-readme).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface AudioChunkListEntry {
|
|
2
|
+
file: string;
|
|
3
|
+
startMs: number;
|
|
4
|
+
durationMs: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Parses ffmpeg's `-segment_list_type csv` output: `file,start,end` per line,
|
|
8
|
+
// times in seconds.
|
|
9
|
+
export function parseAudioChunkList(csv: string): AudioChunkListEntry[] {
|
|
10
|
+
return csv
|
|
11
|
+
.split(/\r?\n/)
|
|
12
|
+
.filter((line) => line.trim())
|
|
13
|
+
.map((line) => {
|
|
14
|
+
const [file, start, end] = line.split(",");
|
|
15
|
+
const startMs = Math.round(Number(start) * 1000);
|
|
16
|
+
const endMs = Math.round(Number(end) * 1000);
|
|
17
|
+
if (!file || !Number.isFinite(startMs) || !(endMs > startMs)) {
|
|
18
|
+
// guard:allow-bare-error — invariant: malformed ffmpeg output; the caller rethrows it as EXTRACTION_FAILED.
|
|
19
|
+
throw new Error(`Unreadable audio chunk list entry: "${line}"`);
|
|
20
|
+
}
|
|
21
|
+
return { file, startMs, durationMs: endMs - startMs };
|
|
22
|
+
});
|
|
23
|
+
}
|