@agent-native/core 0.84.21 → 0.84.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AssistantChat.tsx +27 -4
  5. package/corpus/core/src/client/guided-questions.tsx +11 -6
  6. package/corpus/core/src/client/tool-display.ts +8 -0
  7. package/corpus/core/src/file-upload/builder.ts +7 -2
  8. package/corpus/core/src/notifications/channels.ts +235 -38
  9. package/corpus/core/src/server/analytics.ts +32 -6
  10. package/corpus/core/src/server/ssr-handler.ts +31 -12
  11. package/corpus/templates/analytics/AGENTS.md +21 -0
  12. package/corpus/templates/analytics/README.md +35 -0
  13. package/corpus/templates/analytics/actions/delete-analytics-alert-rule.ts +23 -0
  14. package/corpus/templates/analytics/actions/list-analytics-alert-rules.ts +20 -0
  15. package/corpus/templates/analytics/actions/run-analytics-alerts.ts +23 -0
  16. package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +69 -0
  17. package/corpus/templates/analytics/changelog/2026-07-01-analytics-can-alert-when-first-party-events-spike.md +6 -0
  18. package/corpus/templates/analytics/changelog/2026-07-01-session-replays-play-back-in-production-instead-of-showing.md +6 -0
  19. package/corpus/templates/analytics/netlify.toml +3 -0
  20. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +109 -0
  21. package/corpus/templates/analytics/server/db/schema.ts +55 -0
  22. package/corpus/templates/analytics/server/handlers/session-replay.ts +5 -2
  23. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +71 -0
  24. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +734 -0
  25. package/corpus/templates/analytics/server/lib/session-replay.ts +10 -3
  26. package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +54 -0
  27. package/corpus/templates/analytics/server/plugins/db.ts +100 -0
  28. package/corpus/templates/analytics/server/routes/api/analytics-alerts/run.post.ts +60 -0
  29. package/corpus/templates/assets/README.md +30 -8
  30. package/corpus/templates/brain/README.md +20 -552
  31. package/corpus/templates/calendar/README.md +22 -28
  32. package/corpus/templates/chat/README.md +32 -0
  33. package/corpus/templates/clips/README.md +37 -0
  34. package/corpus/templates/clips/app/components/library/library-grid.tsx +18 -7
  35. package/corpus/templates/clips/app/components/library/recording-card.tsx +42 -5
  36. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +41 -1
  37. package/corpus/templates/clips/changelog/2026-07-01-move-to-folder-now-opens-folder-choices-directly-instead-of.md +6 -0
  38. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  39. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +37 -0
  40. package/corpus/templates/content/AGENTS.md +7 -3
  41. package/corpus/templates/content/README.md +22 -34
  42. package/corpus/templates/content/actions/list-trashed-content-databases.ts +4 -0
  43. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +58 -6
  44. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +257 -24
  45. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +41 -15
  46. package/corpus/templates/content/app/i18n/zh-TW.ts +25 -7
  47. package/corpus/templates/content/app/i18n-data.ts +278 -40
  48. package/corpus/templates/content/changelog/2026-06-30-database-once-again-creates-an-inline-database-in-the-curren.md +6 -0
  49. package/corpus/templates/content/shared/api.ts +1 -0
  50. package/corpus/templates/design/AGENTS.md +7 -6
  51. package/corpus/templates/design/README.md +33 -0
  52. package/corpus/templates/design/actions/delete-file.ts +86 -10
  53. package/corpus/templates/design/actions/get-design-snapshot.ts +13 -0
  54. package/corpus/templates/design/actions/present-design-variants.ts +11 -13
  55. package/corpus/templates/design/app/hooks/use-question-flow.ts +2 -2
  56. package/corpus/templates/design/app/pages/DesignEditor.tsx +2 -2
  57. package/corpus/templates/dispatch/README.md +34 -0
  58. package/corpus/templates/forms/README.md +34 -0
  59. package/corpus/templates/macros/README.md +28 -0
  60. package/corpus/templates/mail/README.md +35 -0
  61. package/corpus/templates/plan/README.md +30 -118
  62. package/corpus/templates/slides/README.md +34 -0
  63. package/corpus/templates/videos/README.md +22 -201
  64. package/dist/client/AssistantChat.d.ts.map +1 -1
  65. package/dist/client/AssistantChat.js +28 -4
  66. package/dist/client/AssistantChat.js.map +1 -1
  67. package/dist/client/guided-questions.d.ts.map +1 -1
  68. package/dist/client/guided-questions.js +10 -6
  69. package/dist/client/guided-questions.js.map +1 -1
  70. package/dist/client/tool-display.d.ts.map +1 -1
  71. package/dist/client/tool-display.js +8 -0
  72. package/dist/client/tool-display.js.map +1 -1
  73. package/dist/collab/awareness.d.ts +2 -2
  74. package/dist/collab/awareness.d.ts.map +1 -1
  75. package/dist/collab/routes.d.ts +1 -1
  76. package/dist/file-upload/builder.d.ts.map +1 -1
  77. package/dist/file-upload/builder.js +6 -2
  78. package/dist/file-upload/builder.js.map +1 -1
  79. package/dist/notifications/channels.d.ts +10 -0
  80. package/dist/notifications/channels.d.ts.map +1 -1
  81. package/dist/notifications/channels.js +172 -20
  82. package/dist/notifications/channels.js.map +1 -1
  83. package/dist/notifications/routes.d.ts +3 -3
  84. package/dist/observability/routes.d.ts +5 -5
  85. package/dist/progress/routes.d.ts +1 -1
  86. package/dist/resources/handlers.d.ts +1 -1
  87. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  88. package/dist/server/analytics.d.ts +16 -0
  89. package/dist/server/analytics.d.ts.map +1 -1
  90. package/dist/server/analytics.js +30 -7
  91. package/dist/server/analytics.js.map +1 -1
  92. package/dist/server/ssr-handler.d.ts.map +1 -1
  93. package/dist/server/ssr-handler.js +28 -12
  94. package/dist/server/ssr-handler.js.map +1 -1
  95. package/dist/server/transcribe-voice.d.ts +1 -1
  96. package/package.json +1 -1
@@ -1591,7 +1591,8 @@ export async function readSessionReplayChunkBytes(
1591
1591
  recording: SessionRecordingSummary;
1592
1592
  seq: number;
1593
1593
  checksum: string;
1594
- data: Buffer;
1594
+ /** Decompressed replay-chunk JSON text (a serialized rrweb events array). */
1595
+ json: string;
1595
1596
  }> {
1596
1597
  const recording = await getSessionReplaySummary(recordingId, scope);
1597
1598
  const db = getDb() as any;
@@ -1608,6 +1609,12 @@ export async function readSessionReplayChunkBytes(
1608
1609
  .limit(1);
1609
1610
  if (!row) throw replayError("Session replay chunk not found", 404);
1610
1611
 
1612
+ // Return decompressed JSON and let normal Accept-Encoding negotiation handle
1613
+ // wire compression. We intentionally do NOT hand back a pre-gzipped body with
1614
+ // a manual `Content-Encoding: gzip` header: serverless hosts (Netlify) mangle
1615
+ // binary function bodies and re-negotiate compression, which corrupted replay
1616
+ // chunk downloads in production and left the player blank. Storing gzip at
1617
+ // rest is unchanged — we just gunzip before serving.
1611
1618
  if (row.storageKind === "blob" && row.storageRef) {
1612
1619
  const ref = decodeReplayBlobRef(row.storageRef);
1613
1620
  if (!ref)
@@ -1617,7 +1624,7 @@ export async function readSessionReplayChunkBytes(
1617
1624
  recording,
1618
1625
  seq: row.seq,
1619
1626
  checksum: row.checksum,
1620
- data: Buffer.from(blob.data),
1627
+ json: gunzipSync(Buffer.from(blob.data)).toString("utf8"),
1621
1628
  };
1622
1629
  }
1623
1630
  if (!row.inlineData)
@@ -1626,7 +1633,7 @@ export async function readSessionReplayChunkBytes(
1626
1633
  recording,
1627
1634
  seq: row.seq,
1628
1635
  checksum: row.checksum,
1629
- data: gzipSync(Buffer.from(row.inlineData, "utf8")),
1636
+ json: row.inlineData,
1630
1637
  };
1631
1638
  }
1632
1639
 
@@ -0,0 +1,54 @@
1
+ import { runAnalyticsAlertsOnce } from "../jobs/analytics-alerts";
2
+
3
+ const DEFAULT_INTERVAL_MS = 60_000;
4
+ let skippingLogged = false;
5
+
6
+ declare global {
7
+ var __AGENT_NATIVE_ANALYTICS_ALERT_SCHEDULED_RUNTIME__: boolean | undefined;
8
+ }
9
+
10
+ function platformSchedulerOwnsAlerts(): boolean {
11
+ return (
12
+ process.env.NETLIFY === "true" ||
13
+ globalThis.__AGENT_NATIVE_ANALYTICS_ALERT_SCHEDULED_RUNTIME__ === true
14
+ );
15
+ }
16
+
17
+ function intervalMs(): number {
18
+ const raw = process.env.ANALYTICS_ALERT_INTERVAL_MS?.trim();
19
+ if (!raw) return DEFAULT_INTERVAL_MS;
20
+ const parsed = Number.parseInt(raw, 10);
21
+ return Number.isFinite(parsed) && parsed >= 10_000
22
+ ? parsed
23
+ : DEFAULT_INTERVAL_MS;
24
+ }
25
+
26
+ export default function registerAnalyticsAlertJobs(): void {
27
+ const isProd = process.env.NODE_ENV === "production";
28
+ const flag =
29
+ process.env.ANALYTICS_ALERT_JOBS ?? process.env.RUN_BACKGROUND_JOBS;
30
+ const enabled =
31
+ !platformSchedulerOwnsAlerts() &&
32
+ (flag === "1" || (isProd && flag !== "0"));
33
+
34
+ if (!enabled) {
35
+ if (!skippingLogged) {
36
+ console.log(
37
+ platformSchedulerOwnsAlerts()
38
+ ? "[analytics-alerts] Skipping in-process cron because the platform scheduler owns alert sweeps."
39
+ : "[analytics-alerts] Skipping background cron (set ANALYTICS_ALERT_JOBS=1 or RUN_BACKGROUND_JOBS=1 to enable in dev; on by default in production)",
40
+ );
41
+ skippingLogged = true;
42
+ }
43
+ return;
44
+ }
45
+
46
+ const ms = intervalMs();
47
+ setInterval(() => {
48
+ runAnalyticsAlertsOnce().catch((err) =>
49
+ console.error("[analytics-alerts] interval failed:", err),
50
+ );
51
+ }, ms);
52
+
53
+ console.log(`[analytics-alerts] Recurring alert sweep every ${ms / 1000}s.`);
54
+ }
@@ -513,6 +513,106 @@ export default runMigrations(
513
513
  sqlite: `UPDATE session_replay_chunks SET started_at = CASE WHEN started_at IS NOT NULL AND substr(started_at, 1, 10) > date('now') THEN min(COALESCE(NULLIF(created_at, ''), datetime('now')), datetime('now')) ELSE started_at END, ended_at = CASE WHEN ended_at IS NOT NULL AND substr(ended_at, 1, 10) > date('now') THEN min(COALESCE(NULLIF(created_at, ''), datetime('now')), datetime('now')) ELSE ended_at END WHERE (started_at IS NOT NULL AND substr(started_at, 1, 10) > date('now')) OR (ended_at IS NOT NULL AND substr(ended_at, 1, 10) > date('now'))`,
514
514
  },
515
515
  },
516
+ {
517
+ version: 75,
518
+ sql: {
519
+ postgres: `CREATE TABLE IF NOT EXISTS analytics_alert_rules (
520
+ id TEXT PRIMARY KEY,
521
+ name TEXT NOT NULL,
522
+ description TEXT NOT NULL DEFAULT '',
523
+ event_name TEXT,
524
+ filters TEXT NOT NULL DEFAULT '[]',
525
+ threshold_mode TEXT NOT NULL DEFAULT 'event_count',
526
+ distinct_by TEXT,
527
+ threshold INTEGER NOT NULL DEFAULT 1,
528
+ window_minutes INTEGER NOT NULL DEFAULT 10,
529
+ cooldown_minutes INTEGER NOT NULL DEFAULT 30,
530
+ severity TEXT NOT NULL DEFAULT 'warning',
531
+ channels TEXT NOT NULL DEFAULT '["inbox"]',
532
+ email_recipients TEXT NOT NULL DEFAULT '[]',
533
+ enabled BOOLEAN NOT NULL DEFAULT true,
534
+ last_evaluated_at TEXT,
535
+ last_triggered_at TEXT,
536
+ last_status TEXT,
537
+ last_error TEXT,
538
+ created_at TEXT NOT NULL DEFAULT (now()::text),
539
+ updated_at TEXT NOT NULL DEFAULT (now()::text),
540
+ owner_email TEXT NOT NULL DEFAULT 'local@localhost',
541
+ org_id TEXT
542
+ )`,
543
+ sqlite: `CREATE TABLE IF NOT EXISTS analytics_alert_rules (
544
+ id TEXT PRIMARY KEY,
545
+ name TEXT NOT NULL,
546
+ description TEXT NOT NULL DEFAULT '',
547
+ event_name TEXT,
548
+ filters TEXT NOT NULL DEFAULT '[]',
549
+ threshold_mode TEXT NOT NULL DEFAULT 'event_count',
550
+ distinct_by TEXT,
551
+ threshold INTEGER NOT NULL DEFAULT 1,
552
+ window_minutes INTEGER NOT NULL DEFAULT 10,
553
+ cooldown_minutes INTEGER NOT NULL DEFAULT 30,
554
+ severity TEXT NOT NULL DEFAULT 'warning',
555
+ channels TEXT NOT NULL DEFAULT '["inbox"]',
556
+ email_recipients TEXT NOT NULL DEFAULT '[]',
557
+ enabled INTEGER NOT NULL DEFAULT 1,
558
+ last_evaluated_at TEXT,
559
+ last_triggered_at TEXT,
560
+ last_status TEXT,
561
+ last_error TEXT,
562
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
563
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
564
+ owner_email TEXT NOT NULL DEFAULT 'local@localhost',
565
+ org_id TEXT
566
+ )`,
567
+ },
568
+ },
569
+ {
570
+ version: 76,
571
+ sql: {
572
+ postgres: `CREATE TABLE IF NOT EXISTS analytics_alert_incidents (
573
+ id TEXT PRIMARY KEY,
574
+ rule_id TEXT NOT NULL,
575
+ triggered_at TEXT NOT NULL,
576
+ window_start TEXT NOT NULL,
577
+ window_end TEXT NOT NULL,
578
+ threshold INTEGER NOT NULL,
579
+ observed_value INTEGER NOT NULL,
580
+ event_count INTEGER NOT NULL,
581
+ severity TEXT NOT NULL,
582
+ channels TEXT NOT NULL DEFAULT '[]',
583
+ sample_events TEXT NOT NULL DEFAULT '[]',
584
+ notification_id TEXT,
585
+ created_at TEXT NOT NULL DEFAULT (now()::text),
586
+ owner_email TEXT NOT NULL DEFAULT 'local@localhost',
587
+ org_id TEXT
588
+ )`,
589
+ sqlite: `CREATE TABLE IF NOT EXISTS analytics_alert_incidents (
590
+ id TEXT PRIMARY KEY,
591
+ rule_id TEXT NOT NULL,
592
+ triggered_at TEXT NOT NULL,
593
+ window_start TEXT NOT NULL,
594
+ window_end TEXT NOT NULL,
595
+ threshold INTEGER NOT NULL,
596
+ observed_value INTEGER NOT NULL,
597
+ event_count INTEGER NOT NULL,
598
+ severity TEXT NOT NULL,
599
+ channels TEXT NOT NULL DEFAULT '[]',
600
+ sample_events TEXT NOT NULL DEFAULT '[]',
601
+ notification_id TEXT,
602
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
603
+ owner_email TEXT NOT NULL DEFAULT 'local@localhost',
604
+ org_id TEXT
605
+ )`,
606
+ },
607
+ },
608
+ {
609
+ version: 77,
610
+ sql: `CREATE INDEX IF NOT EXISTS analytics_alert_rules_scope_enabled_idx ON analytics_alert_rules (org_id, owner_email, enabled, updated_at)`,
611
+ },
612
+ {
613
+ version: 78,
614
+ sql: `CREATE INDEX IF NOT EXISTS analytics_alert_incidents_rule_triggered_idx ON analytics_alert_incidents (rule_id, triggered_at)`,
615
+ },
516
616
  ],
517
617
  { table: "analytics_migrations" },
518
618
  );
@@ -0,0 +1,60 @@
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 alert action logic.
6
+ import { runAnalyticsAlertsOnce } from "../../../jobs/analytics-alerts";
7
+
8
+ declare global {
9
+ var __AGENT_NATIVE_ANALYTICS_ALERT_SCHEDULED_RUNTIME__: boolean | undefined;
10
+ }
11
+
12
+ function productionLike(): boolean {
13
+ return (
14
+ process.env.NODE_ENV === "production" || process.env.NETLIFY === "true"
15
+ );
16
+ }
17
+
18
+ function scheduledFunctionRuntime(): boolean {
19
+ return globalThis.__AGENT_NATIVE_ANALYTICS_ALERT_SCHEDULED_RUNTIME__ === true;
20
+ }
21
+
22
+ function cronSecret(): string | null {
23
+ const secret = process.env.ANALYTICS_ALERTS_CRON_SECRET?.trim();
24
+ return secret ? secret : null;
25
+ }
26
+
27
+ function headerMatchesSecret(
28
+ header: string | undefined,
29
+ secret: string,
30
+ ): boolean {
31
+ const expected = `Bearer ${secret}`;
32
+ const value = header?.trim() ?? "";
33
+ if (value.length !== expected.length) return false;
34
+ return timingSafeEqual(Buffer.from(value), Buffer.from(expected));
35
+ }
36
+
37
+ export default defineEventHandler(async (event) => {
38
+ const secret = cronSecret();
39
+ const scheduledRuntime = scheduledFunctionRuntime();
40
+ if (!secret && productionLike() && !scheduledRuntime) {
41
+ throw createError({
42
+ statusCode: 503,
43
+ statusMessage: "ANALYTICS_ALERTS_CRON_SECRET is required",
44
+ });
45
+ }
46
+
47
+ if (
48
+ secret &&
49
+ !scheduledRuntime &&
50
+ !headerMatchesSecret(getHeader(event, "authorization"), secret)
51
+ ) {
52
+ throw createError({
53
+ statusCode: 401,
54
+ statusMessage: "Unauthorized",
55
+ });
56
+ }
57
+
58
+ const result = await runAnalyticsAlertsOnce();
59
+ return { ok: true, ...result };
60
+ });
@@ -1,12 +1,34 @@
1
1
  # Assets
2
2
 
3
- Agent-native digital asset libraries for brand-consistent image and video generation.
3
+ An open-source, agent-native digital asset manager (DAM) and brand-image/video
4
+ generation workspace — a self-hostable alternative to tools like Brandfolder and
5
+ Air, with generation built in.
4
6
 
5
- Use libraries and folders to collect uploaded images, videos, logos, product
6
- shots, diagrams, style briefs, generated candidates, and saved assets. The UI
7
- curates the DAM; the agent handles generation, search, and iteration through
8
- actions and A2A.
7
+ **Live app: [assets.agent-native.com](https://assets.agent-native.com)**
9
8
 
10
- Every generated asset writes an audit run with user prompt, compiled prompt,
11
- model, source app, references, outputs, status, and refinement lineage. Org
12
- admins can review the log at `/audit` and export CSV for design-team QA.
9
+ Organize uploaded and generated media into libraries and folders, then route
10
+ image and video generation through the agent chat so every asset can be reviewed,
11
+ refined, and kept on-brand. Every generated asset writes an audit run with the
12
+ prompt, model, references, and lineage.
13
+
14
+ ## Features
15
+
16
+ - Brand-consistent image and video generation through the agent.
17
+ - Libraries, folders, and brand kits for organizing uploads and generated results.
18
+ - Generation presets that carry a brand style brief, prompt template, and logo policy.
19
+ - Pixel-perfect canonical logo compositing onto generated images.
20
+ - Reusable across apps: pick or generate assets from other apps over A2A and MCP.
21
+ - Full audit log of every generation run, exportable to CSV.
22
+
23
+ ## Develop locally
24
+
25
+ Scaffold your own copy and run it:
26
+
27
+ ```bash
28
+ npx @agent-native/core@latest create my-assets --standalone --template assets
29
+ cd my-assets
30
+ pnpm install
31
+ pnpm dev
32
+ ```
33
+
34
+ Full docs: [agent-native.com/docs/template-assets](https://agent-native.com/docs/template-assets).