@agent-native/core 0.154.5 → 0.157.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/account-health/SKILL.md +76 -0
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
- package/corpus/templates/analytics/actions/bigquery.ts +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
- package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/calendar/AGENTS.md +2 -0
- package/corpus/templates/calendar/DEVELOPING.md +4 -4
- package/corpus/templates/calendar/actions/get-settings.ts +4 -11
- package/corpus/templates/calendar/actions/update-availability.ts +15 -4
- package/corpus/templates/calendar/actions/update-settings.ts +15 -4
- package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
- package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
- package/corpus/templates/calendar/app/i18n-data.ts +30 -0
- package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
- package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
- package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
- package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
- package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
- package/corpus/templates/calendar/shared/api.ts +1 -0
- package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
- package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
- package/corpus/templates/calendar/shared/settings.ts +44 -0
- package/corpus/templates/clips/AGENTS.md +2 -0
- package/corpus/templates/clips/actions/add-comment.ts +5 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
- package/corpus/templates/clips/actions/update-comment.ts +9 -2
- package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
- package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
- package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
- package/corpus/templates/clips/app/root.tsx +2 -1
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
- package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +116 -19
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
- package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
- package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
- package/corpus/templates/clips/desktop/src/styles.css +117 -0
- package/corpus/templates/clips/server/db/index.ts +10 -0
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/recordings.ts +3 -1
- package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
- package/corpus/templates/clips/server/plugins/db.ts +5 -0
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
- package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
- package/corpus/templates/content/actions/add-comment.ts +2 -1
- package/corpus/templates/content/actions/update-comment.ts +1 -1
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
- package/corpus/templates/design/actions/generate-design.ts +10 -7
- package/corpus/templates/design/actions/present-design-variants.ts +35 -6
- package/corpus/templates/design/actions/run-design-audit.ts +33 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +66 -0
- package/corpus/templates/dispatch/.env.example +5 -0
- package/corpus/templates/dispatch/AGENTS.md +24 -19
- package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
- package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
- package/corpus/templates/factory/AGENTS.md +5 -1
- package/corpus/templates/factory/README.md +23 -0
- package/corpus/templates/factory/actions/view-screen.ts +17 -0
- package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
- package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
- package/corpus/templates/factory/app/routes/factory.tsx +41 -0
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
- package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
- package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
- package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
- package/corpus/templates/mail/vite.config.ts +7 -0
- package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
- package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
- package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
- package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +105 -9
- package/dist/agent/thread-data-builder.js +17 -1
- package/dist/agent/types.d.ts +9 -0
- package/dist/cli/skills-content/help.js +6 -4
- package/dist/cli/skills.js +17 -2
- package/dist/cli/workspacify.d.ts +5 -0
- package/dist/cli/workspacify.js +65 -8
- package/dist/client/AgentPanel.d.ts +5 -0
- package/dist/client/AgentPanel.js +32 -13
- package/dist/client/AssistantChat.d.ts +36 -1
- package/dist/client/AssistantChat.js +175 -110
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/active-run-state.d.ts +14 -1
- package/dist/client/active-run-state.js +0 -0
- package/dist/client/agent-chat-adapter.js +107 -5
- package/dist/client/analytics.js +9 -2
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/chat-first/apps-rail.js +9 -4
- package/dist/client/chat-first/primary-nav.d.ts +2 -1
- package/dist/client/chat-first/primary-nav.js +3 -3
- package/dist/client/chat-first/types.d.ts +5 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
- package/dist/client/markdown/InlineMarkdown.js +65 -0
- package/dist/client/markdown/index.d.ts +1 -0
- package/dist/client/markdown/index.js +1 -0
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/review/ReviewThreadPanel.js +2 -1
- package/dist/client/run-stream-ownership.d.ts +39 -0
- package/dist/client/run-stream-ownership.js +65 -0
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +10 -0
- package/dist/feature-flags/store.js +112 -1
- package/dist/guards/no-env-credentials.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/integrations/adapters/slack.js +5 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.js +3 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/resources/agents.js +40 -5
- package/dist/resources/metadata.d.ts +10 -0
- package/dist/resources/metadata.js +7 -3
- package/dist/review/actions/create-review-comment.js +1 -1
- package/dist/review/actions/reply-review-comment.js +1 -1
- package/dist/review/actions/resolve-review-thread.js +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-routes.js +32 -6
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-discovery.js +14 -3
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/core-routes-plugin.js +1 -1
- package/dist/server/identity-sso-migrations.d.ts +7 -0
- package/dist/server/identity-sso-migrations.js +36 -0
- package/dist/server/identity-sso-store.d.ts +3 -2
- package/dist/server/identity-sso-store.js +8 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +4 -0
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/dist/tracking/providers.js +13 -3
- package/dist/workspace-files/tool.js +1 -1
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +3 -2
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* of that share and is omitted unless the meeting owner enables it.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
getSession,
|
|
11
|
+
runWithRequestContext,
|
|
12
|
+
verifyScopedAgentAccessToken,
|
|
13
|
+
} from "@agent-native/core/server";
|
|
10
14
|
import { resolveAccess } from "@agent-native/core/sharing";
|
|
11
15
|
import { eq } from "drizzle-orm";
|
|
12
16
|
import {
|
|
@@ -16,6 +20,10 @@ import {
|
|
|
16
20
|
setResponseStatus,
|
|
17
21
|
} from "h3";
|
|
18
22
|
|
|
23
|
+
import {
|
|
24
|
+
CLIPS_MEETING_AGENT_ACCESS_PARAM,
|
|
25
|
+
CLIPS_MEETING_AGENT_RESOURCE_KIND,
|
|
26
|
+
} from "../../../shared/meeting-agent-access.js";
|
|
19
27
|
import {
|
|
20
28
|
normalizeTranscriptSegments,
|
|
21
29
|
parseTranscriptSegments,
|
|
@@ -43,17 +51,31 @@ function parseBullets(raw: string | null | undefined): Bullet[] {
|
|
|
43
51
|
}
|
|
44
52
|
}
|
|
45
53
|
|
|
54
|
+
function queryString(value: unknown): string {
|
|
55
|
+
if (typeof value === "string") return value;
|
|
56
|
+
if (Array.isArray(value) && typeof value[0] === "string") return value[0];
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
|
|
46
60
|
export default defineEventHandler(async (event) => {
|
|
47
61
|
setResponseHeader(event, "Cache-Control", "private, max-age=0, no-store");
|
|
48
62
|
setResponseHeader(event, "Referrer-Policy", "no-referrer");
|
|
49
63
|
|
|
50
64
|
const query = getQuery(event);
|
|
51
|
-
const meetingId =
|
|
65
|
+
const meetingId = queryString(query.id);
|
|
52
66
|
if (!meetingId) {
|
|
53
67
|
setResponseStatus(event, 400);
|
|
54
68
|
return { error: "id is required" };
|
|
55
69
|
}
|
|
56
70
|
|
|
71
|
+
const agentAccessToken = queryString(query[CLIPS_MEETING_AGENT_ACCESS_PARAM]);
|
|
72
|
+
const tokenAccess = agentAccessToken
|
|
73
|
+
? verifyScopedAgentAccessToken(agentAccessToken, {
|
|
74
|
+
resourceKind: CLIPS_MEETING_AGENT_RESOURCE_KIND,
|
|
75
|
+
resourceId: meetingId,
|
|
76
|
+
})
|
|
77
|
+
: null;
|
|
78
|
+
|
|
57
79
|
const session = await getSession(event).catch(() => null);
|
|
58
80
|
const accessContext = {
|
|
59
81
|
userEmail: session?.email,
|
|
@@ -61,14 +83,25 @@ export default defineEventHandler(async (event) => {
|
|
|
61
83
|
};
|
|
62
84
|
|
|
63
85
|
return runWithRequestContext(accessContext, async () => {
|
|
64
|
-
|
|
86
|
+
let db: ReturnType<typeof getDb> | undefined;
|
|
87
|
+
const access = tokenAccess?.ok
|
|
88
|
+
? await (async () => {
|
|
89
|
+
db = getDb();
|
|
90
|
+
const [resource] = await db
|
|
91
|
+
.select()
|
|
92
|
+
.from(schema.meetings)
|
|
93
|
+
.where(eq(schema.meetings.id, meetingId))
|
|
94
|
+
.limit(1);
|
|
95
|
+
return resource ? { role: "viewer" as const, resource } : null;
|
|
96
|
+
})()
|
|
97
|
+
: await resolveAccess("meeting", meetingId, accessContext);
|
|
65
98
|
const meeting = access?.resource;
|
|
66
99
|
if (!meeting || meeting.trashedAt) {
|
|
67
100
|
setResponseStatus(event, 404);
|
|
68
101
|
return { error: "Not found" };
|
|
69
102
|
}
|
|
70
103
|
|
|
71
|
-
|
|
104
|
+
db ??= getDb();
|
|
72
105
|
const [participants, actionItems, transcriptRows] = await Promise.all([
|
|
73
106
|
db
|
|
74
107
|
.select({
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
parseSpaceIds,
|
|
59
59
|
type RecordingVisibility,
|
|
60
60
|
} from "../../lib/recordings.js";
|
|
61
|
+
import { isSeekableRepairPending } from "../../lib/seekable-media-state.js";
|
|
61
62
|
import { verifySharePassword } from "../../lib/share-password.js";
|
|
62
63
|
|
|
63
64
|
function appPath(path: string): string {
|
|
@@ -406,11 +407,19 @@ export default defineEventHandler(async (event) => {
|
|
|
406
407
|
// Referer of any outbound link the share page renders.
|
|
407
408
|
setResponseHeader(event, "Referrer-Policy", "no-referrer");
|
|
408
409
|
const transcriptPresentation = resolveTranscriptPresentation(transcript);
|
|
409
|
-
const verificationPending = await
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
410
|
+
const [verificationPending, seekableRepairPending] = await Promise.all([
|
|
411
|
+
isMediaVerificationPending({
|
|
412
|
+
ownerEmail: rec.ownerEmail,
|
|
413
|
+
recordingId,
|
|
414
|
+
recordingStatus: rec.status,
|
|
415
|
+
}),
|
|
416
|
+
isSeekableRepairPending({
|
|
417
|
+
ownerEmail: rec.ownerEmail,
|
|
418
|
+
recordingId,
|
|
419
|
+
recordingStatus: rec.status,
|
|
420
|
+
videoUrl: rec.videoUrl,
|
|
421
|
+
}),
|
|
422
|
+
]);
|
|
414
423
|
|
|
415
424
|
const [viewCount, agentViewCount] = await Promise.all([
|
|
416
425
|
countRecordingViews(recordingId),
|
|
@@ -454,12 +463,14 @@ export default defineEventHandler(async (event) => {
|
|
|
454
463
|
videoUrl: playbackVideoUrl,
|
|
455
464
|
videoFormat: rec.videoFormat,
|
|
456
465
|
videoSizeBytes: rec.videoSizeBytes ?? null,
|
|
466
|
+
mediaUpdatedAt: rec.mediaUpdatedAt,
|
|
457
467
|
width: rec.width,
|
|
458
468
|
height: rec.height,
|
|
459
469
|
hasAudio: Boolean(rec.hasAudio),
|
|
460
470
|
hasCamera: Boolean(rec.hasCamera),
|
|
461
471
|
status: rec.status,
|
|
462
472
|
verificationPending,
|
|
473
|
+
seekableRepairPending,
|
|
463
474
|
uploadProgress: rec.uploadProgress,
|
|
464
475
|
failureReason: rec.failureReason,
|
|
465
476
|
// Don't leak the password to clients; just indicate whether one was set.
|
|
@@ -37,6 +37,9 @@ export type ClipsUserPrefs = ClipsAiPrefs & {
|
|
|
37
37
|
/** Visibility applied to new recordings unless the creator picks another. */
|
|
38
38
|
export type ClipsDefaultVisibility = "private" | "org" | "public";
|
|
39
39
|
|
|
40
|
+
export const DEFAULT_CLIPS_RECORDING_VISIBILITY: ClipsDefaultVisibility =
|
|
41
|
+
"public";
|
|
42
|
+
|
|
40
43
|
export function isIncludeFullVideoInAiEnabled(
|
|
41
44
|
prefs: ClipsAiPrefs | Record<string, unknown> | null | undefined,
|
|
42
45
|
): boolean {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AGENT_ACCESS_PARAM } from "@agent-native/core/shared";
|
|
2
|
+
|
|
3
|
+
export const CLIPS_MEETING_AGENT_RESOURCE_KIND = "clips:meeting";
|
|
4
|
+
export const CLIPS_MEETING_AGENT_CONTEXT_ENDPOINT = "/api/public-meeting";
|
|
5
|
+
export const CLIPS_MEETING_AGENT_ACCESS_PARAM = AGENT_ACCESS_PARAM;
|
|
@@ -44,7 +44,8 @@ function displayNameFromEmail(email: string): string {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export default defineAction({
|
|
47
|
-
description:
|
|
47
|
+
description:
|
|
48
|
+
"Add a comment to a document. Comment text supports inline Markdown for emphasis, inline code, links, and line breaks; headings are flattened. For new threads, omit threadId.",
|
|
48
49
|
schema: z.object({
|
|
49
50
|
documentId: z.string().optional().describe("Document ID (required)"),
|
|
50
51
|
content: z.string().optional().describe("Comment text (required)"),
|
|
@@ -9,7 +9,7 @@ import { getDb, schema } from "../server/db/index.js";
|
|
|
9
9
|
|
|
10
10
|
export default defineAction({
|
|
11
11
|
description:
|
|
12
|
-
"Update a document comment. Resolving or reopening a comment applies to the full thread.",
|
|
12
|
+
"Update a document comment. Comment text supports inline Markdown without headings. Resolving or reopening a comment applies to the full thread.",
|
|
13
13
|
schema: z.object({
|
|
14
14
|
id: z.string().describe("Comment ID"),
|
|
15
15
|
documentId: z.string().optional().describe("Document ID"),
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
2
|
import { emailToName } from "@agent-native/core/client/collab";
|
|
3
3
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
|
+
import {
|
|
5
|
+
InlineMarkdown,
|
|
6
|
+
type InlineMarkdownProtectedSpan,
|
|
7
|
+
} from "@agent-native/core/client/markdown";
|
|
4
8
|
import {
|
|
5
9
|
IconCheck,
|
|
6
10
|
IconMessageCircle,
|
|
@@ -40,23 +44,28 @@ import { CommentComposer, type MentionEntry } from "./CommentComposer";
|
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
46
|
* Render a comment body, styling any `@mention` tokens that match the comment's
|
|
43
|
-
* stored mentions.
|
|
47
|
+
* stored mentions. Raw HTML is never interpreted.
|
|
44
48
|
*/
|
|
45
|
-
function
|
|
49
|
+
function commentMentionSpans(
|
|
50
|
+
mentions: CommentMention[],
|
|
51
|
+
): InlineMarkdownProtectedSpan[] {
|
|
46
52
|
const labels = Array.from(
|
|
47
53
|
new Set(mentions.map((m) => m.name).filter((n): n is string => !!n)),
|
|
48
54
|
).sort((a, b) => b.length - a.length);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
return labels.map((label) => ({
|
|
56
|
+
source: `@${label}`,
|
|
57
|
+
label: `@${label}`,
|
|
58
|
+
className: "comment-mention",
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function renderCommentBody(content: string, mentions: CommentMention[]) {
|
|
63
|
+
return (
|
|
64
|
+
<InlineMarkdown
|
|
65
|
+
content={content}
|
|
66
|
+
inline
|
|
67
|
+
protectedSpans={commentMentionSpans(mentions)}
|
|
68
|
+
/>
|
|
60
69
|
);
|
|
61
70
|
}
|
|
62
71
|
|
|
@@ -942,9 +951,9 @@ function ThreadView({
|
|
|
942
951
|
{formatDate(c.created_at)}
|
|
943
952
|
</span>
|
|
944
953
|
</div>
|
|
945
|
-
<
|
|
954
|
+
<div className="text-[13px] text-foreground/90 pl-8 leading-relaxed">
|
|
946
955
|
{renderCommentBody(c.content, c.mentions)}
|
|
947
|
-
</
|
|
956
|
+
</div>
|
|
948
957
|
</div>
|
|
949
958
|
))}
|
|
950
959
|
</div>
|
|
@@ -171,12 +171,15 @@ const reuseLabelSchema = z
|
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
function classifyBreakpointSet(
|
|
175
|
+
value: unknown,
|
|
176
|
+
): "absent" | "malformed" | "present" {
|
|
177
|
+
if (value === null || value === undefined) return "absent";
|
|
178
|
+
if (typeof value !== "object" || Array.isArray(value)) return "malformed";
|
|
178
179
|
const breakpoints = (value as { breakpoints?: unknown }).breakpoints;
|
|
179
|
-
|
|
180
|
+
if (breakpoints === undefined) return "malformed";
|
|
181
|
+
if (!Array.isArray(breakpoints)) return "malformed";
|
|
182
|
+
return breakpoints.length > 0 ? "present" : "malformed";
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
function jsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
@@ -1137,7 +1140,7 @@ const generateDesignAction = defineAction({
|
|
|
1137
1140
|
mergedData.breakpointSetUpdatedAt = updatedAt;
|
|
1138
1141
|
} else if (
|
|
1139
1142
|
generatedBreakpointSet.length > 0 &&
|
|
1140
|
-
|
|
1143
|
+
classifyBreakpointSet(mergedData.breakpointSet) === "absent"
|
|
1141
1144
|
) {
|
|
1142
1145
|
mergedData.breakpointSet = {
|
|
1143
1146
|
id: "generated-responsive",
|
|
@@ -1200,7 +1203,7 @@ const generateDesignAction = defineAction({
|
|
|
1200
1203
|
devices && devices.length > 0
|
|
1201
1204
|
? jsonValuesEqual(currentBreakpointWidths, expectedBreakpointWidths)
|
|
1202
1205
|
: generatedBreakpointSet.length === 0 ||
|
|
1203
|
-
|
|
1206
|
+
classifyBreakpointSet(current.breakpointSet) !== "absent";
|
|
1204
1207
|
return framesApplied && breakpointSetApplied;
|
|
1205
1208
|
},
|
|
1206
1209
|
});
|
|
@@ -89,12 +89,25 @@ async function hasLinkedDesignSystem(designId: string): Promise<boolean> {
|
|
|
89
89
|
return Boolean(design?.designSystemId?.trim());
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Absent, or present but unreadable — the caller must not treat these alike.
|
|
94
|
+
* A malformed set is still the user's data: overwriting it with the generated
|
|
95
|
+
* default silently discards breakpoints they configured, so it reports
|
|
96
|
+
* `"malformed"` and the install is skipped rather than clobbering it.
|
|
97
|
+
*/
|
|
98
|
+
function classifyBreakpointSet(
|
|
99
|
+
value: unknown,
|
|
100
|
+
): "absent" | "malformed" | "present" {
|
|
101
|
+
if (value === null || value === undefined) return "absent";
|
|
102
|
+
if (typeof value !== "object" || Array.isArray(value)) return "malformed";
|
|
96
103
|
const breakpoints = (value as { breakpoints?: unknown }).breakpoints;
|
|
97
|
-
|
|
104
|
+
if (breakpoints === undefined) return "malformed";
|
|
105
|
+
if (!Array.isArray(breakpoints)) return "malformed";
|
|
106
|
+
return breakpoints.length > 0 ? "present" : "malformed";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasBreakpointSet(value: unknown): boolean {
|
|
110
|
+
return classifyBreakpointSet(value) === "present";
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
function designDeepLink(designId: string): string {
|
|
@@ -1042,9 +1055,16 @@ export default defineAction({
|
|
|
1042
1055
|
});
|
|
1043
1056
|
}
|
|
1044
1057
|
|
|
1058
|
+
// Presenting options should not silently reconfigure the design. When it
|
|
1059
|
+
// does, the overview paints an extra preview beside EVERY primary frame
|
|
1060
|
+
// from then on — including screens created later — so the caller is told.
|
|
1061
|
+
let installedBreakpointSet = false;
|
|
1062
|
+
|
|
1045
1063
|
await mutateDesignData({
|
|
1046
1064
|
designId,
|
|
1047
1065
|
mutate: (current, { updatedAt }) => {
|
|
1066
|
+
installedBreakpointSet =
|
|
1067
|
+
classifyBreakpointSet(current.breakpointSet) === "absent";
|
|
1048
1068
|
// Placement depends on the breakpoint set in effect after this call, so
|
|
1049
1069
|
// it is resolved here (inside the compare-and-set body) rather than
|
|
1050
1070
|
// against a design snapshot that a concurrent write may have moved on
|
|
@@ -1106,7 +1126,9 @@ export default defineAction({
|
|
|
1106
1126
|
canvasFrames: mergedFrames.canvasFrames,
|
|
1107
1127
|
screenMetadata: previousMetadata,
|
|
1108
1128
|
designVariantSets: previousVariantSets,
|
|
1109
|
-
|
|
1129
|
+
// Only when genuinely absent. A malformed set is the user's data in
|
|
1130
|
+
// a shape this action cannot read, not a blank slate to overwrite.
|
|
1131
|
+
...(classifyBreakpointSet(current.breakpointSet) !== "absent"
|
|
1110
1132
|
? {}
|
|
1111
1133
|
: {
|
|
1112
1134
|
breakpointSet: {
|
|
@@ -1227,6 +1249,13 @@ export default defineAction({
|
|
|
1227
1249
|
embed: true,
|
|
1228
1250
|
cleanedUpPreviousVariantScreens: variantSetCleanup.removedFileIds.length,
|
|
1229
1251
|
deletedSupersededSetIds: variantSetCleanup.removedSetIds,
|
|
1252
|
+
...(installedBreakpointSet
|
|
1253
|
+
? {
|
|
1254
|
+
installedBreakpointSet: DEFAULT_RESPONSIVE_BREAKPOINTS.map(
|
|
1255
|
+
(breakpoint) => breakpoint.widthPx,
|
|
1256
|
+
),
|
|
1257
|
+
}
|
|
1258
|
+
: {}),
|
|
1230
1259
|
fallbackInstructions: FALLBACK_INSTRUCTIONS,
|
|
1231
1260
|
nextRequiredAction:
|
|
1232
1261
|
'Wait for the user to pick a screen in chat. Then delete each unchosen variant screen with delete-file at most once, call get-design-snapshot exactly once with fileId for the chosen screen, and call edit-design with that same fileId in a bounded pass. Use mode "replace-file" to replace the representative direction screen with a complete but compact requested app/product UI in the chosen visual style. Prioritize the primary workflow and render secondary details as visible controls, states, or affordances if the full feature list is too large for one reliable edit. Do not leave a direction board, variant brief, or summary card as the final result. Do not repeat delete/snapshot cycles. Do not call generate-design after a variant pick. Stop after the first successful edit-design save.',
|
|
@@ -25,6 +25,10 @@ import type {
|
|
|
25
25
|
A11yFindingCategory,
|
|
26
26
|
A11ySeverity,
|
|
27
27
|
} from "../shared/design-review.js";
|
|
28
|
+
import {
|
|
29
|
+
describeDesignHtmlIntegrityIssue,
|
|
30
|
+
inspectDesignHtmlDocumentIntegrity,
|
|
31
|
+
} from "../shared/html-integrity.js";
|
|
28
32
|
|
|
29
33
|
// ---------------------------------------------------------------------------
|
|
30
34
|
// HTML helpers (static analysis — no DOM runtime available server-side)
|
|
@@ -259,6 +263,34 @@ export function checkTapTargets(html: string): A11yFinding[] {
|
|
|
259
263
|
return findings;
|
|
260
264
|
}
|
|
261
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Screens that render with an Alpine-controlled element covering them. Every
|
|
268
|
+
* other check here is a regex over the raw string; this one delegates to the
|
|
269
|
+
* save-time integrity parser so the audit and the write gate cannot drift into
|
|
270
|
+
* disagreeing about the same document. It is the only check that can see the
|
|
271
|
+
* failure a screenshot cannot: `take-design-screenshot` waits for Alpine to
|
|
272
|
+
* settle, so a pre-Alpine cover never appears in the agent's own capture.
|
|
273
|
+
*/
|
|
274
|
+
export function checkRenderBlockingOverlays(html: string): A11yFinding[] {
|
|
275
|
+
const result = inspectDesignHtmlDocumentIntegrity(html);
|
|
276
|
+
const issues = [...(result.detail ?? []), ...(result.advisory ?? [])].filter(
|
|
277
|
+
(issue) =>
|
|
278
|
+
issue.issue === "runtime-overlay-unhidden" ||
|
|
279
|
+
issue.issue === "runtime-cloak-missing" ||
|
|
280
|
+
issue.issue === "runtime-alpine-missing",
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
return issues.map((issue, index) => ({
|
|
284
|
+
id: `render-blocking-overlay:${issue.issue}-${index}`,
|
|
285
|
+
severity: "error" as A11ySeverity,
|
|
286
|
+
category: "render-blocking-overlay" as A11yFindingCategory,
|
|
287
|
+
message:
|
|
288
|
+
"An Alpine-controlled element can cover the screen before Alpine starts.",
|
|
289
|
+
detail: describeDesignHtmlIntegrityIssue(issue),
|
|
290
|
+
fixAvailable: false,
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
|
|
262
294
|
/** Check for animations/transitions without a prefers-reduced-motion guard. */
|
|
263
295
|
function checkReducedMotion(html: string): A11yFinding[] {
|
|
264
296
|
const findings: A11yFinding[] = [];
|
|
@@ -848,6 +880,7 @@ export default defineAction({
|
|
|
848
880
|
...checkReducedMotion(html),
|
|
849
881
|
...checkFocusVisibility(html),
|
|
850
882
|
...checkContrastHint(html),
|
|
883
|
+
...checkRenderBlockingOverlays(html),
|
|
851
884
|
...tokenDriftFindings,
|
|
852
885
|
...designSystemFindings,
|
|
853
886
|
];
|
|
@@ -34,6 +34,7 @@ export type DesignHtmlIntegrityIssue =
|
|
|
34
34
|
| "runtime-missing"
|
|
35
35
|
| "runtime-alpine-missing"
|
|
36
36
|
| "runtime-cloak-missing"
|
|
37
|
+
| "runtime-overlay-unhidden"
|
|
37
38
|
| "url-backed-screen-replaced";
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -153,6 +154,14 @@ export function describeDesignHtmlIntegrityIssue(
|
|
|
153
154
|
`but no script source contains Alpine.js. The element will remain ` +
|
|
154
155
|
`hidden forever; load Alpine.js before relying on x-cloak.`
|
|
155
156
|
);
|
|
157
|
+
case "runtime-overlay-unhidden":
|
|
158
|
+
return (
|
|
159
|
+
`<${detail.tag ?? "element"}> at ${at} covers the whole frame and is ` +
|
|
160
|
+
`shown by Alpine (${detail.attribute ?? "x-show"}), but nothing hides ` +
|
|
161
|
+
`it before Alpine starts. It paints over the design on first render. ` +
|
|
162
|
+
`Add x-cloak plus [x-cloak] { display: none !important; }, or an ` +
|
|
163
|
+
`inline style="display:none".`
|
|
164
|
+
);
|
|
156
165
|
case "runtime-cloak-missing":
|
|
157
166
|
return (
|
|
158
167
|
`the document uses x-cloak on <${detail.tag ?? "element"}> at ${at}, ` +
|
|
@@ -1175,6 +1184,53 @@ function collectInteractiveRuntimeIssues(
|
|
|
1175
1184
|
];
|
|
1176
1185
|
}
|
|
1177
1186
|
|
|
1187
|
+
/**
|
|
1188
|
+
* Covers the frame when it is taken out of flow AND stretched to every edge.
|
|
1189
|
+
* `fixed` alone is a toolbar; `inset-0` alone is a normal filled parent.
|
|
1190
|
+
*/
|
|
1191
|
+
function coversViewport(className: string): boolean {
|
|
1192
|
+
const classes = new Set(className.split(/\s+/));
|
|
1193
|
+
const positioned = classes.has("fixed") || classes.has("absolute");
|
|
1194
|
+
const fullBleed =
|
|
1195
|
+
classes.has("inset-0") ||
|
|
1196
|
+
(classes.has("w-screen") && classes.has("h-screen"));
|
|
1197
|
+
return positioned && fullBleed;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* The shape the `x-cloak` checks above cannot see. An overlay toggled by
|
|
1202
|
+
* `x-show` with no `x-cloak` at all paints over the design until Alpine
|
|
1203
|
+
* evaluates the expression — the same symptom, minus the attribute that makes
|
|
1204
|
+
* it detectable. Advisory rather than blocking: with Alpine healthy this is one
|
|
1205
|
+
* frame, and a genuinely broken runtime is already caught above.
|
|
1206
|
+
*
|
|
1207
|
+
* `<template x-if>` is deliberately not checked: template content is inert
|
|
1208
|
+
* until Alpine clones it, so it cannot paint early.
|
|
1209
|
+
*/
|
|
1210
|
+
function collectOverlayAdvisory(
|
|
1211
|
+
parsed: ParsedDocument,
|
|
1212
|
+
locate: Locator,
|
|
1213
|
+
): DesignHtmlIntegrityIssueDetail[] {
|
|
1214
|
+
for (const element of parsed.elements) {
|
|
1215
|
+
const names = new Set(
|
|
1216
|
+
element.attrs.map((attribute) => attribute.name.toLowerCase()),
|
|
1217
|
+
);
|
|
1218
|
+
if (names.has("x-cloak") || !names.has("x-show")) continue;
|
|
1219
|
+
if (!coversViewport(attributeOf(element, "class") ?? "")) continue;
|
|
1220
|
+
if (INLINE_PRE_HIDE.test(attributeOf(element, "style") ?? "")) continue;
|
|
1221
|
+
|
|
1222
|
+
return [
|
|
1223
|
+
{
|
|
1224
|
+
issue: "runtime-overlay-unhidden",
|
|
1225
|
+
...locate(locationOf(element)?.startOffset ?? 0),
|
|
1226
|
+
tag: element.tagName,
|
|
1227
|
+
attribute: "x-show",
|
|
1228
|
+
},
|
|
1229
|
+
];
|
|
1230
|
+
}
|
|
1231
|
+
return [];
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1178
1234
|
/**
|
|
1179
1235
|
* Reported, never enforced: legitimate fragments and token-only screens carry no
|
|
1180
1236
|
* runtime of their own, so blocking here would reject valid work.
|
|
@@ -1182,6 +1238,16 @@ function collectInteractiveRuntimeIssues(
|
|
|
1182
1238
|
function collectAdvisoryIssues(
|
|
1183
1239
|
parsed: ParsedDocument,
|
|
1184
1240
|
locate: Locator,
|
|
1241
|
+
): DesignHtmlIntegrityIssueDetail[] {
|
|
1242
|
+
return [
|
|
1243
|
+
...collectOverlayAdvisory(parsed, locate),
|
|
1244
|
+
...collectTailwindRuntimeAdvisory(parsed, locate),
|
|
1245
|
+
];
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
function collectTailwindRuntimeAdvisory(
|
|
1249
|
+
parsed: ParsedDocument,
|
|
1250
|
+
locate: Locator,
|
|
1185
1251
|
): DesignHtmlIntegrityIssueDetail[] {
|
|
1186
1252
|
// Only documents that actually depend on utility classes can be broken by a
|
|
1187
1253
|
// missing runtime. A screen styled entirely through its own CSS needs no
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
# App URL (used for webhook callback construction)
|
|
44
44
|
# APP_URL=https://your-app.example.com
|
|
45
45
|
|
|
46
|
+
# Optional exact registry for custom workspace apps that opt into Desktop SSO.
|
|
47
|
+
# Each entry must declare appId, clientId, an exact HTTPS origin, callbackPath
|
|
48
|
+
# "/_agent-native/identity/callback", and the "identity-sso" capability.
|
|
49
|
+
# IDENTITY_SSO_APP_REGISTRY_JSON=
|
|
50
|
+
|
|
46
51
|
# Builder-backed app creation in production
|
|
47
52
|
# DISPATCH_BUILDER_PROJECT_ID= # Default Builder project for new app branches
|
|
48
53
|
# BUILDER_PUBLIC_KEY= # Builder space/public key
|
|
@@ -13,10 +13,9 @@ Read the relevant skill before deeper work:
|
|
|
13
13
|
|
|
14
14
|
## Core Rules
|
|
15
15
|
|
|
16
|
-
- Store large file/blob payloads in configured file/blob storage, not SQL:
|
|
17
|
-
|
|
18
|
-
thumbnails, or replay chunks
|
|
19
|
-
or `resources`; persist URLs, ids, or handles instead.
|
|
16
|
+
- Store large file/blob payloads in configured file/blob storage, not SQL:
|
|
17
|
+
persist URLs, ids, or handles instead of base64, media, documents, archives,
|
|
18
|
+
screenshots, thumbnails, or replay chunks.
|
|
20
19
|
- Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
|
|
21
20
|
- Treat Dispatch as workspace infrastructure. Prefer actions over raw SQL for
|
|
22
21
|
vault, integrations, resource grants, messaging, routing, and approvals.
|
|
@@ -32,13 +31,22 @@ Read the relevant skill before deeper work:
|
|
|
32
31
|
values or silently widen app access while doing this.
|
|
33
32
|
- Use `view-screen` when the current integration, resource, approval, route, or
|
|
34
33
|
setup item is unclear.
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
- Use `import-agent` to normalize safe Claude Markdown or JSON into an
|
|
35
|
+
`agents/<slug>.md` profile; it skips credentials, hooks, shell, and local env.
|
|
36
|
+
- Use `import-agent-pack` for a Claude Project/Cowork-style folder. It keeps the
|
|
37
|
+
runnable profile at `agents/<slug>.md` and stores text references, context,
|
|
38
|
+
and agent-owned skills below `agents/<slug>/`. Use `list-agent-pack` to
|
|
39
|
+
inspect the files and the shared agent pack UI to edit them.
|
|
40
|
+
- Use `connect-external-agent` for public HTTP/A2A metadata; authenticate through
|
|
41
|
+
the normal connection flow.
|
|
42
|
+
- Dispatch's primary nav is Overview, Chat, Apps, Agents, and the app rail.
|
|
43
|
+
`/agents` creates/imports reusable profiles, opens per-agent chat, and can
|
|
44
|
+
hand a profile off to app creation; `/admin/agents` manages technical MCP/A2A
|
|
45
|
+
connections; other workspace/operator tools live under `/admin`.
|
|
46
|
+
- Agent profiles and agentic apps are also managed from Factory's top-level
|
|
47
|
+
Agents tab. Factory embeds the same agent actions and pack editor and reads
|
|
48
|
+
mounted app metadata through the shared Dispatch database; it does not create
|
|
49
|
+
a second agent registry.
|
|
42
50
|
- Keep approval and routing behavior explicit. Never silently widen access to
|
|
43
51
|
secrets, apps, integrations, or workspace resources.
|
|
44
52
|
- Curated workspace templates are private app sources. Use
|
|
@@ -65,15 +73,12 @@ Read the relevant skill before deeper work:
|
|
|
65
73
|
preserve the returned per-source health instead of treating an unavailable
|
|
66
74
|
source as zero failures.
|
|
67
75
|
- For a Slack-linked issue, call `read-slack-thread-context` with the exact
|
|
68
|
-
permalink before diagnosing it
|
|
69
|
-
|
|
70
|
-
complete. Never treat an unreadable Slack thread as an empty one.
|
|
76
|
+
permalink before diagnosing it; preserve its pagination and readability
|
|
77
|
+
status instead of treating an unreadable thread as empty.
|
|
71
78
|
- For usage investigations, use `list-dispatch-usage-metrics` with the smallest
|
|
72
|
-
useful scope
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`/admin/metrics` to keep the agent's analysis aligned with the visible scope
|
|
76
|
-
and selected user.
|
|
79
|
+
useful scope and lookback. Treat `not-captured` and `unavailable` attribution
|
|
80
|
+
as gaps, not zero usage; use `view-screen` on `/admin/metrics` to align with
|
|
81
|
+
the visible scope and selected user.
|
|
77
82
|
|
|
78
83
|
## Application State
|
|
79
84
|
|