@agent-native/core 0.141.4 → 0.141.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +13 -6
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +15 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -2
- package/corpus/templates/analytics/app/i18n-data.ts +328 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +66 -30
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-now-repair-automatically-after-.md +6 -0
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +109 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +342 -0
- package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +8 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +11 -29
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +55 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +117 -31
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +15 -9
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +5 -16
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +61 -0
- package/corpus/templates/analytics/server/plugins/db.ts +58 -187
- package/corpus/templates/analytics/server/routes/api/analytics-rollups/backfill.post.ts +53 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-overlays-now-use-clean-surfaces-without-clipped-shadow.md +6 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +2 -2
- package/corpus/templates/clips/desktop/src/styles.css +3 -54
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -3
- package/corpus/templates/design/actions/get-design-system.ts +3 -1
- package/corpus/templates/design/changelog/2026-08-05-missing-design-systems-now-return-a-clear-not-found-response.md +6 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +5 -5
- package/corpus/templates/slides/changelog/2026-08-05-new-presentation-prompts-now-clearly-describe-presentation-g.md +6 -0
- package/dist/client/AssistantChat.js +1 -1
- package/dist/client/chat/run-recovery.d.ts +2 -1
- package/dist/client/chat/run-recovery.js +10 -3
- package/dist/client/error-format.d.ts +1 -0
- package/dist/client/error-format.js +4 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/docs/AGENTS.md +1 -1
- package/docs/content/actions.mdx +1 -1
- package/docs/content/agent-surfaces.mdx +1 -1
- package/docs/content/agents.mdx +9 -0
- package/docs/content/database.mdx +2 -2
- package/docs/content/drop-in-agent.mdx +1 -1
- package/docs/content/notifications.mdx +1 -1
- package/docs/content/routing.mdx +1 -1
- package/docs/content/server-database.mdx +437 -0
- package/docs/content/server-middleware.mdx +151 -0
- package/docs/content/server-overview.mdx +234 -0
- package/docs/content/server-plugins.mdx +147 -0
- package/docs/content/server-routes.mdx +194 -0
- package/package.json +1 -1
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +0 -6
- package/corpus/templates/analytics/changelog/2026-08-05-historical-rollups-stay-complete-while-live-events-arrive.md +0 -6
- package/docs/content/server.mdx +0 -469
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deferMigration,
|
|
3
3
|
ensureAdditiveColumns,
|
|
4
|
-
getDialect,
|
|
5
4
|
getDbExec,
|
|
6
|
-
isPostgres,
|
|
7
5
|
runMigrations,
|
|
8
6
|
} from "@agent-native/core/db";
|
|
9
7
|
import { isInBackgroundFunctionRuntime } from "@agent-native/core/server";
|
|
@@ -12,7 +10,7 @@ import { isInBackgroundFunctionRuntime } from "@agent-native/core/server";
|
|
|
12
10
|
// startup so the dashboard / analysis share actions know where to dispatch.
|
|
13
11
|
import "../db/index.js";
|
|
14
12
|
import * as schema from "../db/schema.js";
|
|
15
|
-
import {
|
|
13
|
+
import { isHistoricalAnalyticsRollupBackfillComplete } from "../jobs/analytics-rollup-backfill.js";
|
|
16
14
|
import { repairPersistedFirstPartyDashboardQueries } from "../lib/first-party-dashboard-repair.js";
|
|
17
15
|
|
|
18
16
|
/**
|
|
@@ -33,182 +31,6 @@ function isDrizzleTable(value: unknown): value is object {
|
|
|
33
31
|
|
|
34
32
|
const schemaTables = Object.values(schema).filter(isDrizzleTable);
|
|
35
33
|
|
|
36
|
-
const ANALYTICS_ROLLUP_BACKFILL_STATEMENTS = {
|
|
37
|
-
postgres: [
|
|
38
|
-
`
|
|
39
|
-
INSERT INTO analytics_event_daily_rollups (
|
|
40
|
-
id, tenant_key, owner_email, org_id, event_date, event_name,
|
|
41
|
-
app, template, event_count
|
|
42
|
-
)
|
|
43
|
-
SELECT
|
|
44
|
-
md5(random()::text || clock_timestamp()::text), tenant_key,
|
|
45
|
-
MIN(owner_email), MIN(org_id), event_date, event_name, app, template,
|
|
46
|
-
COUNT(*)::INTEGER
|
|
47
|
-
FROM (
|
|
48
|
-
SELECT
|
|
49
|
-
CASE
|
|
50
|
-
WHEN org_id IS NOT NULL AND org_id <> '' THEN 'org:' || org_id
|
|
51
|
-
ELSE 'user:' || owner_email
|
|
52
|
-
END AS tenant_key,
|
|
53
|
-
owner_email,
|
|
54
|
-
org_id,
|
|
55
|
-
COALESCE(NULLIF(event_date, ''), substr(timestamp, 1, 10)) AS event_date,
|
|
56
|
-
event_name,
|
|
57
|
-
COALESCE(app, '') AS app,
|
|
58
|
-
COALESCE(template, '') AS template
|
|
59
|
-
FROM analytics_events
|
|
60
|
-
) AS historical_events
|
|
61
|
-
WHERE event_date <> ''
|
|
62
|
-
GROUP BY tenant_key, event_date, event_name, app, template
|
|
63
|
-
ON CONFLICT (tenant_key, event_date, event_name, app, template)
|
|
64
|
-
DO UPDATE SET event_count = GREATEST(
|
|
65
|
-
analytics_event_daily_rollups.event_count,
|
|
66
|
-
EXCLUDED.event_count
|
|
67
|
-
)
|
|
68
|
-
`,
|
|
69
|
-
`
|
|
70
|
-
INSERT INTO analytics_user_days (
|
|
71
|
-
id, tenant_key, owner_email, org_id, event_date, user_key
|
|
72
|
-
)
|
|
73
|
-
SELECT
|
|
74
|
-
md5(random()::text || clock_timestamp()::text), tenant_key,
|
|
75
|
-
owner_email, org_id, event_date, user_key
|
|
76
|
-
FROM (
|
|
77
|
-
SELECT DISTINCT
|
|
78
|
-
CASE
|
|
79
|
-
WHEN org_id IS NOT NULL AND org_id <> '' THEN 'org:' || org_id
|
|
80
|
-
ELSE 'user:' || owner_email
|
|
81
|
-
END AS tenant_key,
|
|
82
|
-
owner_email,
|
|
83
|
-
org_id,
|
|
84
|
-
COALESCE(NULLIF(event_date, ''), substr(timestamp, 1, 10)) AS event_date,
|
|
85
|
-
user_key
|
|
86
|
-
FROM analytics_events
|
|
87
|
-
WHERE user_key IS NOT NULL AND TRIM(user_key) <> ''
|
|
88
|
-
) AS historical_user_days
|
|
89
|
-
WHERE event_date <> ''
|
|
90
|
-
ON CONFLICT (tenant_key, event_date, user_key) DO NOTHING
|
|
91
|
-
`,
|
|
92
|
-
],
|
|
93
|
-
sqlite: [
|
|
94
|
-
`
|
|
95
|
-
INSERT INTO analytics_event_daily_rollups (
|
|
96
|
-
id, tenant_key, owner_email, org_id, event_date, event_name,
|
|
97
|
-
app, template, event_count
|
|
98
|
-
)
|
|
99
|
-
SELECT
|
|
100
|
-
lower(hex(randomblob(16))), tenant_key, MIN(owner_email), MIN(org_id),
|
|
101
|
-
event_date, event_name, app, template, COUNT(*)
|
|
102
|
-
FROM (
|
|
103
|
-
SELECT
|
|
104
|
-
CASE
|
|
105
|
-
WHEN org_id IS NOT NULL AND org_id <> '' THEN 'org:' || org_id
|
|
106
|
-
ELSE 'user:' || owner_email
|
|
107
|
-
END AS tenant_key,
|
|
108
|
-
owner_email,
|
|
109
|
-
org_id,
|
|
110
|
-
COALESCE(NULLIF(event_date, ''), substr(timestamp, 1, 10)) AS event_date,
|
|
111
|
-
event_name,
|
|
112
|
-
COALESCE(app, '') AS app,
|
|
113
|
-
COALESCE(template, '') AS template
|
|
114
|
-
FROM analytics_events
|
|
115
|
-
) AS historical_events
|
|
116
|
-
WHERE event_date <> ''
|
|
117
|
-
GROUP BY tenant_key, event_date, event_name, app, template
|
|
118
|
-
ON CONFLICT (tenant_key, event_date, event_name, app, template)
|
|
119
|
-
DO UPDATE SET event_count = excluded.event_count
|
|
120
|
-
`,
|
|
121
|
-
`
|
|
122
|
-
INSERT INTO analytics_user_days (
|
|
123
|
-
id, tenant_key, owner_email, org_id, event_date, user_key
|
|
124
|
-
)
|
|
125
|
-
SELECT
|
|
126
|
-
lower(hex(randomblob(16))), tenant_key, owner_email, org_id,
|
|
127
|
-
event_date, user_key
|
|
128
|
-
FROM (
|
|
129
|
-
SELECT DISTINCT
|
|
130
|
-
CASE
|
|
131
|
-
WHEN org_id IS NOT NULL AND org_id <> '' THEN 'org:' || org_id
|
|
132
|
-
ELSE 'user:' || owner_email
|
|
133
|
-
END AS tenant_key,
|
|
134
|
-
owner_email,
|
|
135
|
-
org_id,
|
|
136
|
-
COALESCE(NULLIF(event_date, ''), substr(timestamp, 1, 10)) AS event_date,
|
|
137
|
-
user_key
|
|
138
|
-
FROM analytics_events
|
|
139
|
-
WHERE user_key IS NOT NULL AND TRIM(user_key) <> ''
|
|
140
|
-
) AS historical_user_days
|
|
141
|
-
WHERE event_date <> ''
|
|
142
|
-
ON CONFLICT (tenant_key, event_date, user_key) DO NOTHING
|
|
143
|
-
`,
|
|
144
|
-
],
|
|
145
|
-
} as const;
|
|
146
|
-
|
|
147
|
-
async function runHistoricalAnalyticsRollupBackfill() {
|
|
148
|
-
// Durable agent workers share this plugin bundle with the regular server,
|
|
149
|
-
// but they must not become a second migration runner for an expensive
|
|
150
|
-
// historical scan. The keep-warm/regular server path owns this work.
|
|
151
|
-
if (isInBackgroundFunctionRuntime()) {
|
|
152
|
-
console.info(
|
|
153
|
-
"[db] Deferring historical Analytics rollup backfill from durable background runtime",
|
|
154
|
-
);
|
|
155
|
-
return deferMigration();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const db = getDbExec();
|
|
159
|
-
|
|
160
|
-
if (isPostgres()) {
|
|
161
|
-
if (!db.transaction) {
|
|
162
|
-
throw new Error(
|
|
163
|
-
"Analytics rollup backfill requires a Postgres transaction",
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const result = await db.transaction(async (tx) => {
|
|
168
|
-
// Only one serverless instance should perform the expensive scan. A
|
|
169
|
-
// A try-lock keeps competing cold starts from holding pooled Neon
|
|
170
|
-
// connections while waiting for the winner. A lock loser defers without
|
|
171
|
-
// recording the migration so a failed winner can be retried safely.
|
|
172
|
-
// The monotonic rollup upsert below keeps a live increment from being
|
|
173
|
-
// overwritten if ingest commits during the historical snapshot. Live
|
|
174
|
-
// ingest takes this same lock before inserting its raw event.
|
|
175
|
-
const lockResult = await tx.execute({
|
|
176
|
-
sql: "SELECT pg_try_advisory_xact_lock(hashtextextended(?, 0::bigint)) AS acquired",
|
|
177
|
-
args: [FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY],
|
|
178
|
-
});
|
|
179
|
-
const acquired = lockResult.rows[0]?.acquired;
|
|
180
|
-
if (acquired !== true && acquired !== "t") {
|
|
181
|
-
console.info(
|
|
182
|
-
"[db] Deferring historical Analytics rollup backfill; another instance owns the advisory lock",
|
|
183
|
-
);
|
|
184
|
-
return deferMigration();
|
|
185
|
-
}
|
|
186
|
-
for (const statement of ANALYTICS_ROLLUP_BACKFILL_STATEMENTS.postgres) {
|
|
187
|
-
await tx.execute(statement);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
return result;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const statements = ANALYTICS_ROLLUP_BACKFILL_STATEMENTS.sqlite;
|
|
194
|
-
if (getDialect() === "d1") {
|
|
195
|
-
if (!db.atomicBatch) {
|
|
196
|
-
throw new Error("D1 analytics rollup backfill requires an atomic batch");
|
|
197
|
-
}
|
|
198
|
-
await db.atomicBatch(statements);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (!db.transaction) {
|
|
203
|
-
throw new Error(
|
|
204
|
-
"Analytics rollup backfill requires a database transaction",
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
await db.transaction(async (tx) => {
|
|
208
|
-
for (const statement of statements) await tx.execute(statement);
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
34
|
// Convention: every new migration below MUST set a unique `name:` slug (see
|
|
213
35
|
// packages/core/src/db/migrations.ts for the full rationale). Version numbers
|
|
214
36
|
// alone are not a safe identity across parallel branches that each extend
|
|
@@ -1548,14 +1370,56 @@ const runAnalyticsMigrations = runMigrations(
|
|
|
1548
1370
|
name: "analytics-query-pressure-daily-key-idx",
|
|
1549
1371
|
sql: `CREATE UNIQUE INDEX IF NOT EXISTS analytics_query_pressure_daily_key_idx ON analytics_query_pressure_daily (tenant_key, event_date, query_class)`,
|
|
1550
1372
|
},
|
|
1551
|
-
//
|
|
1552
|
-
//
|
|
1553
|
-
//
|
|
1373
|
+
// Keep this historical migration name reserved, but record it without a
|
|
1374
|
+
// boot-time run. Scanning analytics_events here makes every concurrent
|
|
1375
|
+
// serverless migration runner hold a database connection for the full
|
|
1376
|
+
// history; v126-v131 continue to maintain the compact tables incrementally.
|
|
1377
|
+
// Any future one-shot backfill must use a new migration identity or an
|
|
1378
|
+
// explicit out-of-band job because this marker is permanently applied.
|
|
1554
1379
|
{
|
|
1555
1380
|
version: 132,
|
|
1556
1381
|
name: "analytics-rollups-historical-backfill",
|
|
1557
1382
|
sql: {},
|
|
1558
|
-
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
version: 133,
|
|
1386
|
+
name: "analytics-rollups-historical-backfill-state",
|
|
1387
|
+
sql: {
|
|
1388
|
+
postgres: `CREATE TABLE IF NOT EXISTS analytics_rollup_backfill_state (
|
|
1389
|
+
id TEXT PRIMARY KEY,
|
|
1390
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
1391
|
+
completed_at TEXT,
|
|
1392
|
+
lease_token TEXT,
|
|
1393
|
+
lease_expires_at TEXT,
|
|
1394
|
+
updated_at TEXT NOT NULL DEFAULT (now()::text)
|
|
1395
|
+
)`,
|
|
1396
|
+
sqlite: `CREATE TABLE IF NOT EXISTS analytics_rollup_backfill_state (
|
|
1397
|
+
id TEXT PRIMARY KEY,
|
|
1398
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
1399
|
+
completed_at TEXT,
|
|
1400
|
+
lease_token TEXT,
|
|
1401
|
+
lease_expires_at TEXT,
|
|
1402
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1403
|
+
)`,
|
|
1404
|
+
},
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
version: 134,
|
|
1408
|
+
name: "analytics-rollups-historical-backfill-repair",
|
|
1409
|
+
sql: {},
|
|
1410
|
+
run: async () => {
|
|
1411
|
+
if (!(await isHistoricalAnalyticsRollupBackfillComplete())) {
|
|
1412
|
+
return deferMigration();
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
version: 135,
|
|
1418
|
+
name: "analytics-rollups-historical-backfill-lease",
|
|
1419
|
+
sql: `
|
|
1420
|
+
ALTER TABLE analytics_rollup_backfill_state ADD COLUMN IF NOT EXISTS lease_token TEXT;
|
|
1421
|
+
ALTER TABLE analytics_rollup_backfill_state ADD COLUMN IF NOT EXISTS lease_expires_at TEXT;
|
|
1422
|
+
`,
|
|
1559
1423
|
},
|
|
1560
1424
|
],
|
|
1561
1425
|
{ table: "analytics_migrations" },
|
|
@@ -1572,10 +1436,17 @@ const runAnalyticsMigrations = runMigrations(
|
|
|
1572
1436
|
* swallowed so it can never fail boot.
|
|
1573
1437
|
*/
|
|
1574
1438
|
export default async (nitroApp: any): Promise<void> => {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1439
|
+
const isScheduledRollupRuntime =
|
|
1440
|
+
(
|
|
1441
|
+
globalThis as typeof globalThis & {
|
|
1442
|
+
__AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__?: boolean;
|
|
1443
|
+
}
|
|
1444
|
+
).__AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__ === true;
|
|
1445
|
+
if (isInBackgroundFunctionRuntime() && !isScheduledRollupRuntime) {
|
|
1446
|
+
// Most durable workers execute signed internal routes against a schema
|
|
1447
|
+
// owned by the regular server. A second migration runner only adds a Neon
|
|
1448
|
+
// pool probe to every worker cold start. The scheduled rollup worker is
|
|
1449
|
+
// the exception because it can be the first post-deploy invocation.
|
|
1579
1450
|
console.info(
|
|
1580
1451
|
"[db] Skipping Analytics migrations in durable background runtime",
|
|
1581
1452
|
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import { createError, defineEventHandler, getHeader } from "h3";
|
|
4
|
+
|
|
5
|
+
// guard:allow-action-twin — external cron endpoint authenticates scheduled callers before invoking the rollup job.
|
|
6
|
+
import { runAnalyticsRollupBackfillOnce } from "../../../jobs/analytics-rollup-backfill";
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
var __AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__:
|
|
10
|
+
| boolean
|
|
11
|
+
| undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function scheduledFunctionRuntime(): boolean {
|
|
15
|
+
return (
|
|
16
|
+
globalThis.__AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__ ===
|
|
17
|
+
true
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function cronSecret(): string | null {
|
|
22
|
+
const secret = process.env.ANALYTICS_ROLLUP_BACKFILL_CRON_SECRET?.trim();
|
|
23
|
+
return secret ? secret : null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function headerMatchesSecret(
|
|
27
|
+
header: string | undefined,
|
|
28
|
+
secret: string,
|
|
29
|
+
): boolean {
|
|
30
|
+
const expected = `Bearer ${secret}`;
|
|
31
|
+
const value = header?.trim() ?? "";
|
|
32
|
+
if (value.length !== expected.length) return false;
|
|
33
|
+
return timingSafeEqual(Buffer.from(value), Buffer.from(expected));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default defineEventHandler(async (event) => {
|
|
37
|
+
const secret = cronSecret();
|
|
38
|
+
const scheduledRuntime = scheduledFunctionRuntime();
|
|
39
|
+
const authenticatedHeader =
|
|
40
|
+
secret !== null &&
|
|
41
|
+
headerMatchesSecret(getHeader(event, "authorization"), secret);
|
|
42
|
+
if (!scheduledRuntime && !authenticatedHeader) {
|
|
43
|
+
throw createError({
|
|
44
|
+
statusCode: secret ? 401 : 503,
|
|
45
|
+
statusMessage: secret
|
|
46
|
+
? "Unauthorized"
|
|
47
|
+
: "ANALYTICS_ROLLUP_BACKFILL_CRON_SECRET is required",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = await runAnalyticsRollupBackfillOnce();
|
|
52
|
+
return { ok: true, ...result };
|
|
53
|
+
});
|
|
@@ -40,8 +40,8 @@ interface TranscriptionStatusPayload {
|
|
|
40
40
|
const SNOOZE_MS = 5 * 60_000;
|
|
41
41
|
const FALLBACK_AUTO_HIDE_MS = 6 * 60_000;
|
|
42
42
|
const DISMISSAL_TOMBSTONE_MS = 30 * 60_000;
|
|
43
|
-
// Card is up to 440px wide; the extra width
|
|
44
|
-
//
|
|
43
|
+
// Card is up to 440px wide; the extra width keeps its close control and menu
|
|
44
|
+
// inside the transparent window edges.
|
|
45
45
|
const NOTIFICATION_WINDOW_WIDTH = 504;
|
|
46
46
|
const NOTIFICATION_COLLAPSED_HEIGHT = 120;
|
|
47
47
|
const NOTIFICATION_MENU_HEIGHT = 224;
|
|
@@ -856,7 +856,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
856
856
|
width: 3px;
|
|
857
857
|
border-radius: 999px;
|
|
858
858
|
background: rgba(132, 204, 22, 0.98);
|
|
859
|
-
box-shadow: 0 0 5px rgba(132, 204, 22, 0.35);
|
|
860
859
|
transition: height 90ms ease-out;
|
|
861
860
|
}
|
|
862
861
|
|
|
@@ -3474,7 +3473,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
3474
3473
|
border: 1px solid rgba(255, 255, 255, 0.22);
|
|
3475
3474
|
border-radius: 50%;
|
|
3476
3475
|
background: rgba(10, 12, 16, 0.42);
|
|
3477
|
-
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
|
|
3478
3476
|
color: #ffffff;
|
|
3479
3477
|
cursor: pointer;
|
|
3480
3478
|
pointer-events: auto;
|
|
@@ -3530,21 +3528,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
3530
3528
|
font-weight: 800;
|
|
3531
3529
|
font-variant-numeric: tabular-nums;
|
|
3532
3530
|
color: #ffffff;
|
|
3533
|
-
/*
|
|
3534
|
-
* Do NOT use -webkit-text-stroke here: it joins with a hard miter and no way
|
|
3535
|
-
* to set stroke-linejoin, so at this size/weight the sharp concave corner of
|
|
3536
|
-
* the "2" (where the curved top meets the flat bottom bar) sprouts star-shaped
|
|
3537
|
-
* miter spikes. We fake a soft dark edge with a 4-direction 1px shadow halo
|
|
3538
|
-
* instead, which has no join geometry and cannot spike.
|
|
3539
|
-
*/
|
|
3540
|
-
text-shadow:
|
|
3541
|
-
1px 0 1px rgba(17, 24, 39, 0.22),
|
|
3542
|
-
-1px 0 1px rgba(17, 24, 39, 0.22),
|
|
3543
|
-
0 1px 1px rgba(17, 24, 39, 0.22),
|
|
3544
|
-
0 -1px 1px rgba(17, 24, 39, 0.22),
|
|
3545
|
-
0 2px 4px rgba(0, 0, 0, 0.48),
|
|
3546
|
-
0 12px 34px rgba(0, 0, 0, 0.36),
|
|
3547
|
-
0 0 2px rgba(0, 0, 0, 0.72);
|
|
3548
3531
|
animation: cd-pop 1s ease-out forwards;
|
|
3549
3532
|
line-height: 1;
|
|
3550
3533
|
}
|
|
@@ -3560,7 +3543,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
3560
3543
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
3561
3544
|
border-radius: var(--radius-pill);
|
|
3562
3545
|
background: rgba(10, 12, 16, 0.28);
|
|
3563
|
-
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.24);
|
|
3564
3546
|
color: rgba(255, 255, 255, 0.58);
|
|
3565
3547
|
font-size: 11px;
|
|
3566
3548
|
font-weight: 500;
|
|
@@ -3676,9 +3658,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
3676
3658
|
backdrop-filter: blur(20px);
|
|
3677
3659
|
-webkit-backdrop-filter: blur(20px);
|
|
3678
3660
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
3679
|
-
box-shadow:
|
|
3680
|
-
0 14px 40px rgba(0, 0, 0, 0.45),
|
|
3681
|
-
0 2px 6px rgba(0, 0, 0, 0.3);
|
|
3682
3661
|
color: white;
|
|
3683
3662
|
}
|
|
3684
3663
|
|
|
@@ -4404,9 +4383,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
4404
4383
|
justify-content: center;
|
|
4405
4384
|
flex-shrink: 0;
|
|
4406
4385
|
border-radius: 50%;
|
|
4407
|
-
transition:
|
|
4408
|
-
background 120ms,
|
|
4409
|
-
box-shadow 120ms;
|
|
4386
|
+
transition: background 120ms;
|
|
4410
4387
|
}
|
|
4411
4388
|
|
|
4412
4389
|
.bubble-control-button {
|
|
@@ -4438,7 +4415,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
4438
4415
|
|
|
4439
4416
|
.bubble-dot.is-active {
|
|
4440
4417
|
background: white;
|
|
4441
|
-
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.25);
|
|
4442
4418
|
}
|
|
4443
4419
|
|
|
4444
4420
|
.bubble-dot-small {
|
|
@@ -4832,8 +4808,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
4832
4808
|
display: flex;
|
|
4833
4809
|
align-items: flex-start;
|
|
4834
4810
|
justify-content: flex-end;
|
|
4835
|
-
/*
|
|
4836
|
-
transparent window edges (shadow blur is ~30px). */
|
|
4811
|
+
/* Keep the card and its edge controls inside the transparent window. */
|
|
4837
4812
|
padding: 12px 32px;
|
|
4838
4813
|
background: transparent;
|
|
4839
4814
|
pointer-events: none;
|
|
@@ -4850,9 +4825,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
4850
4825
|
backdrop-filter: blur(20px);
|
|
4851
4826
|
-webkit-backdrop-filter: blur(20px);
|
|
4852
4827
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
4853
|
-
box-shadow:
|
|
4854
|
-
0 10px 30px rgba(0, 0, 0, 0.35),
|
|
4855
|
-
0 2px 6px rgba(0, 0, 0, 0.3);
|
|
4856
4828
|
color: white;
|
|
4857
4829
|
pointer-events: auto;
|
|
4858
4830
|
min-width: 320px;
|
|
@@ -5008,7 +4980,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5008
4980
|
border-radius: 10px;
|
|
5009
4981
|
background: rgba(24, 26, 32, 0.98);
|
|
5010
4982
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
5011
|
-
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4);
|
|
5012
4983
|
z-index: 5;
|
|
5013
4984
|
display: flex;
|
|
5014
4985
|
flex-direction: column;
|
|
@@ -5061,7 +5032,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5061
5032
|
align-items: center;
|
|
5062
5033
|
justify-content: center;
|
|
5063
5034
|
padding: 0;
|
|
5064
|
-
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
|
|
5065
5035
|
z-index: 6;
|
|
5066
5036
|
}
|
|
5067
5037
|
|
|
@@ -5097,7 +5067,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5097
5067
|
backdrop-filter: blur(20px);
|
|
5098
5068
|
-webkit-backdrop-filter: blur(20px);
|
|
5099
5069
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
5100
|
-
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
|
|
5101
5070
|
cursor: pointer;
|
|
5102
5071
|
color: white;
|
|
5103
5072
|
}
|
|
@@ -5321,10 +5290,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5321
5290
|
border: 1.5px solid rgba(255, 255, 255, 0.62);
|
|
5322
5291
|
border-radius: 7px;
|
|
5323
5292
|
background: rgba(255, 255, 255, 0.018);
|
|
5324
|
-
box-shadow:
|
|
5325
|
-
0 0 120px 42px rgba(0, 0, 0, 0.075),
|
|
5326
|
-
inset 0 0 34px rgba(0, 0, 0, 0.06),
|
|
5327
|
-
0 0 0 1px rgba(0, 0, 0, 0.12);
|
|
5328
5293
|
}
|
|
5329
5294
|
|
|
5330
5295
|
.region-guide-rect-editable {
|
|
@@ -5336,19 +5301,11 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5336
5301
|
.region-guide-rect-editable:hover,
|
|
5337
5302
|
.region-guide-rect-editable.selected {
|
|
5338
5303
|
border-color: rgba(255, 255, 255, 0.92);
|
|
5339
|
-
box-shadow:
|
|
5340
|
-
0 0 150px 50px rgba(0, 0, 0, 0.105),
|
|
5341
|
-
inset 0 0 36px rgba(0, 0, 0, 0.08),
|
|
5342
|
-
0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
5343
5304
|
}
|
|
5344
5305
|
|
|
5345
5306
|
.region-guide-rect-editable:focus-visible {
|
|
5346
5307
|
outline: none;
|
|
5347
5308
|
border-color: rgba(255, 255, 255, 0.98);
|
|
5348
|
-
box-shadow:
|
|
5349
|
-
0 0 0 2px rgba(23, 23, 23, 0.5),
|
|
5350
|
-
0 0 150px 50px rgba(0, 0, 0, 0.12),
|
|
5351
|
-
inset 0 0 36px rgba(0, 0, 0, 0.08);
|
|
5352
5309
|
}
|
|
5353
5310
|
|
|
5354
5311
|
.region-guide-rect-draft {
|
|
@@ -5365,9 +5322,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5365
5322
|
border: 1px solid rgba(23, 23, 23, 0.38);
|
|
5366
5323
|
border-radius: 4px;
|
|
5367
5324
|
background: rgba(255, 255, 255, 0.96);
|
|
5368
|
-
box-shadow:
|
|
5369
|
-
0 3px 12px rgba(0, 0, 0, 0.18),
|
|
5370
|
-
0 0 0 1px rgba(255, 255, 255, 0.35);
|
|
5371
5325
|
}
|
|
5372
5326
|
|
|
5373
5327
|
.region-guide-handle-nw {
|
|
@@ -5412,7 +5366,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5412
5366
|
border-radius: 12px;
|
|
5413
5367
|
background: rgba(15, 17, 21, 0.74);
|
|
5414
5368
|
color: #f8fafc;
|
|
5415
|
-
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.22);
|
|
5416
5369
|
transform: translateX(-50%);
|
|
5417
5370
|
backdrop-filter: blur(18px);
|
|
5418
5371
|
}
|
|
@@ -5616,7 +5569,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5616
5569
|
border-radius: 16px;
|
|
5617
5570
|
background: rgba(26, 26, 26, 0.95);
|
|
5618
5571
|
color: white;
|
|
5619
|
-
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
5620
5572
|
cursor: grab;
|
|
5621
5573
|
backdrop-filter: blur(12px);
|
|
5622
5574
|
-webkit-backdrop-filter: blur(12px);
|
|
@@ -5651,9 +5603,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5651
5603
|
rectangle. */
|
|
5652
5604
|
border-radius: 999px;
|
|
5653
5605
|
cursor: pointer;
|
|
5654
|
-
transition:
|
|
5655
|
-
background 120ms ease,
|
|
5656
|
-
box-shadow 120ms ease;
|
|
5606
|
+
transition: background 120ms ease;
|
|
5657
5607
|
}
|
|
5658
5608
|
|
|
5659
5609
|
/* CSS :hover covers the focused case; .pill-hovered is the Rust-polled
|
|
@@ -5661,7 +5611,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5661
5611
|
.pill-inner-compact:hover,
|
|
5662
5612
|
.pill-inner-compact.pill-hovered {
|
|
5663
5613
|
background: rgba(42, 42, 42, 0.97);
|
|
5664
|
-
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2);
|
|
5665
5614
|
}
|
|
5666
5615
|
|
|
5667
5616
|
.pill-controls {
|
|
@@ -22,9 +22,9 @@ use crate::util::{
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const MEETING_NOTIFICATION_LABEL: &str = "meeting-notif";
|
|
25
|
-
// Window is wider than the 440px card so
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// Window is wider than the 440px card so its close control and menu stay inside
|
|
26
|
+
// the transparent window. The right margin is pulled in to keep the card near
|
|
27
|
+
// the top-right corner.
|
|
28
28
|
const NOTIFICATION_W_LOGICAL: u32 = 504;
|
|
29
29
|
const NOTIFICATION_H_LOGICAL: u32 = 120;
|
|
30
30
|
const NOTIFICATION_TOP_MARGIN_LOGICAL: u32 = 44;
|
|
@@ -156,7 +156,9 @@ export default defineAction({
|
|
|
156
156
|
run: async ({ id }) => {
|
|
157
157
|
const access = await resolveAccess("design-system", id);
|
|
158
158
|
if (!access) {
|
|
159
|
-
throw new Error("Design system not found")
|
|
159
|
+
throw Object.assign(new Error("Design system not found"), {
|
|
160
|
+
statusCode: 404,
|
|
161
|
+
});
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
const row = access.resource;
|
|
@@ -190,7 +190,7 @@ export default function DeckCard({
|
|
|
190
190
|
{deck.starred ? (
|
|
191
191
|
<IconStarFilled className="h-3.5 w-3.5 text-[#F5C451]" />
|
|
192
192
|
) : (
|
|
193
|
-
<IconStar className="h-3.5 w-3.5 text-
|
|
193
|
+
<IconStar className="h-3.5 w-3.5 text-white/70" />
|
|
194
194
|
)}
|
|
195
195
|
</button>
|
|
196
196
|
)}
|
|
@@ -208,7 +208,7 @@ export default function DeckCard({
|
|
|
208
208
|
}`}
|
|
209
209
|
aria-label={t("raw.deckOptions")}
|
|
210
210
|
>
|
|
211
|
-
<IconDots className="w-3.5 h-3.5 text-
|
|
211
|
+
<IconDots className="w-3.5 h-3.5 text-white/70" />
|
|
212
212
|
</button>
|
|
213
213
|
</DropdownMenuTrigger>
|
|
214
214
|
<DropdownMenuContent
|
|
@@ -4112,7 +4112,7 @@ export default function SlideEditor({
|
|
|
4112
4112
|
// to stay mounted or that background becomes uneditable.
|
|
4113
4113
|
const contextToolbar = !readOnly ? (
|
|
4114
4114
|
<div
|
|
4115
|
-
className="
|
|
4115
|
+
className="shrink-0"
|
|
4116
4116
|
// Snapshotting the range is only half the job: without this marker the
|
|
4117
4117
|
// click-outside handler exits the edit and clears the snapshot before
|
|
4118
4118
|
// the button's onClick runs, so partial-text formatting would silently
|
|
@@ -654,17 +654,17 @@ const messages = {
|
|
|
654
654
|
mine: "Mine",
|
|
655
655
|
deckCount_one: "deck",
|
|
656
656
|
deckCount_other: "decks",
|
|
657
|
-
createDeckOrVisual: "Create a
|
|
657
|
+
createDeckOrVisual: "Create a presentation",
|
|
658
658
|
noMineDecks: "No decks created by you yet.",
|
|
659
659
|
deleteDeckTitle: "Delete Deck?",
|
|
660
660
|
deleteDeckDescription:
|
|
661
661
|
"This will permanently delete this deck and all its slides. This action cannot be undone.",
|
|
662
662
|
cancel: "Cancel",
|
|
663
663
|
delete: "Delete",
|
|
664
|
-
newDeckPromptTitle: "New
|
|
665
|
-
newDeckPlaceholder: "Describe
|
|
664
|
+
newDeckPromptTitle: "New presentation",
|
|
665
|
+
newDeckPlaceholder: "Describe the presentation you want to generate...",
|
|
666
666
|
skipPrompt: "Skip prompt",
|
|
667
|
-
firstDeckPromptTitle: "What
|
|
667
|
+
firstDeckPromptTitle: "What kind of presentation should we generate?",
|
|
668
668
|
firstDeckSkip: "Skip",
|
|
669
669
|
chooseReferences: "Choose references",
|
|
670
670
|
addDesignSystem: "+ Design system",
|
|
@@ -716,7 +716,7 @@ const messages = {
|
|
|
716
716
|
emptyTitle: "No decks yet",
|
|
717
717
|
createFirstDeck: "Create your first deck",
|
|
718
718
|
emptyDescription:
|
|
719
|
-
"Build beautiful presentations
|
|
719
|
+
"Build beautiful presentations with AI-powered generation.",
|
|
720
720
|
},
|
|
721
721
|
};
|
|
722
722
|
|
|
@@ -4007,7 +4007,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
4007
4007
|
} }) })), shouldShowRunError && visibleRunError && (_jsx(MessageScrollerItem, { children: _jsx(RunErrorRecoveryCard, { info: visibleRunError, onContinue: () => {
|
|
4008
4008
|
setRunErrorInfo(null);
|
|
4009
4009
|
addToQueue(RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE, undefined, undefined, undefined, undefined, "queued", "continue");
|
|
4010
|
-
}, onRetry: retryAfterRunError, onFork: onForkChat, onDismiss: () => {
|
|
4010
|
+
}, onRetry: retryAfterRunError, onFork: onForkChat, onProviderConnected: handleBuilderConnected, onDismiss: () => {
|
|
4011
4011
|
if (visibleRunErrorKey) {
|
|
4012
4012
|
setDismissedRunErrorKey(visibleRunErrorKey);
|
|
4013
4013
|
}
|
|
@@ -35,12 +35,13 @@ export declare function BuilderSetupCard({ onConnected, bouncePulse, fullWidth,
|
|
|
35
35
|
fullWidth?: boolean;
|
|
36
36
|
layout?: BuilderSetupCardLayout;
|
|
37
37
|
}): import("react").JSX.Element;
|
|
38
|
-
export declare function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDismiss, }: {
|
|
38
|
+
export declare function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDismiss, onProviderConnected, }: {
|
|
39
39
|
info: RunErrorInfo;
|
|
40
40
|
onContinue: () => void;
|
|
41
41
|
onRetry: () => void;
|
|
42
42
|
onFork?: () => void | boolean | Promise<void | boolean>;
|
|
43
43
|
onDismiss: () => void;
|
|
44
|
+
onProviderConnected?: () => void;
|
|
44
45
|
}): import("react").JSX.Element;
|
|
45
46
|
export declare function LoopLimitContinueCard({ info, onContinue, }: {
|
|
46
47
|
info: LoopLimitInfo;
|