@agent-native/core 0.141.2 → 0.141.4

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 (157) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +1 -1
  3. package/corpus/templates/analytics/actions/gong-calls.ts +56 -18
  4. package/corpus/templates/analytics/changelog/2026-08-05-analytics-queries-keep-every-table-tenant-scoped.md +6 -0
  5. package/corpus/templates/analytics/changelog/2026-08-05-durable-a2a-workers-avoid-startup-migration-contention.md +6 -0
  6. package/corpus/templates/analytics/changelog/2026-08-05-fixed-sign-in-and-dashboard-requests-failing-when-background.md +6 -0
  7. package/corpus/templates/analytics/changelog/2026-08-05-historical-rollups-stay-complete-while-live-events-arrive.md +6 -0
  8. package/corpus/templates/analytics/server/db/schema.ts +1 -0
  9. package/corpus/templates/analytics/server/lib/dashboard-report.ts +2 -0
  10. package/corpus/templates/analytics/server/lib/emails.ts +51 -0
  11. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +8 -12
  12. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -0
  13. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +262 -13
  14. package/corpus/templates/analytics/server/lib/gong.ts +132 -33
  15. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  16. package/corpus/templates/analytics/server/plugins/auth.ts +21 -2
  17. package/corpus/templates/analytics/server/plugins/db.ts +35 -10
  18. package/corpus/templates/analytics/server/plugins/transactional-emails.ts +5 -0
  19. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +17 -7
  20. package/corpus/templates/calendar/server/lib/booking-emails.ts +154 -70
  21. package/corpus/templates/calendar/server/lib/emails.ts +167 -0
  22. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +64 -28
  23. package/corpus/templates/calendar/server/plugins/transactional-emails.ts +5 -0
  24. package/corpus/templates/clips/actions/invite-member.ts +39 -16
  25. package/corpus/templates/clips/app/components/player/share-dialog.tsx +73 -1
  26. package/corpus/templates/clips/app/i18n/en-US.ts +3 -0
  27. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -25
  28. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
  29. package/corpus/templates/clips/changelog/2026-08-05-activity-is-now-the-default-clips-recording-tab-and-ai-setup.md +6 -0
  30. package/corpus/templates/clips/changelog/2026-08-05-clips-can-copy-a-linked-email-preview-for-public-recordings.md +6 -0
  31. package/corpus/templates/clips/changelog/2026-08-05-preparing-recording-now-uses-a-clean-shadow-free-status-card.md +6 -0
  32. package/corpus/templates/clips/desktop/src/styles.css +0 -3
  33. package/corpus/templates/clips/server/lib/emails.ts +256 -0
  34. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +24 -0
  35. package/corpus/templates/clips/server/plugins/transactional-email-catalog.ts +5 -0
  36. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +4 -1
  37. package/corpus/templates/clips/shared/email-preview.ts +61 -0
  38. package/corpus/templates/content/server/lib/comment-notifications.ts +57 -26
  39. package/corpus/templates/content/server/lib/emails.ts +70 -0
  40. package/corpus/templates/content/server/plugins/transactional-emails.ts +5 -0
  41. package/corpus/templates/design/actions/import-design-tokens.ts +11 -8
  42. package/corpus/templates/design/actions/index-design-tokens.ts +13 -6
  43. package/corpus/templates/design/changelog/2026-08-05-design-token-imports-classify-typography-dimensions-correctly.md +6 -0
  44. package/corpus/templates/dispatch/app/routes/transactional-email.$appId.$id.tsx +4 -0
  45. package/corpus/templates/dispatch/app/routes/transactional-email.tsx +4 -0
  46. package/corpus/templates/dispatch/changelog/2026-08-05-transactional-email-catalogs-and-delivery-activity-are-available-again.md +6 -0
  47. package/corpus/templates/factory/AGENTS.md +18 -17
  48. package/corpus/templates/factory/actions/get-factory-automation-health.ts +50 -0
  49. package/corpus/templates/factory/actions/get-triage-config.ts +8 -0
  50. package/corpus/templates/factory/actions/save-triage-config.ts +26 -0
  51. package/corpus/templates/factory/app/i18n/en-US.ts +27 -0
  52. package/corpus/templates/factory/app/routes/factory.tsx +376 -206
  53. package/corpus/templates/factory/changelog/2026-08-05-factory-now-keeps-production-automations-running-shows-sched.md +6 -0
  54. package/corpus/templates/factory/server/db/schema.ts +6 -0
  55. package/corpus/templates/factory/server/plugins/factory-migrations.ts +10 -0
  56. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +141 -2
  57. package/corpus/templates/forms/app/pages/FormsListPage.tsx +41 -21
  58. package/corpus/templates/forms/changelog/2026-08-05-form-links-can-now-be-cmd-clicked-to-open-in-a-new-tab.md +6 -0
  59. package/corpus/templates/forms/server/lib/emails.ts +52 -0
  60. package/corpus/templates/forms/server/lib/response-email.ts +2 -0
  61. package/corpus/templates/forms/server/plugins/transactional-emails.ts +5 -0
  62. package/corpus/templates/plan/actions/request-plan-access.ts +33 -12
  63. package/corpus/templates/plan/server/lib/comment-notifications.ts +53 -27
  64. package/corpus/templates/plan/server/lib/emails.ts +67 -0
  65. package/corpus/templates/plan/server/plugins/transactional-emails.ts +5 -0
  66. package/corpus/templates/slides/actions/import-from-url.ts +1 -0
  67. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +492 -381
  68. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +8 -7
  69. package/corpus/templates/slides/app/components/layout/Layout.tsx +27 -23
  70. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +313 -0
  71. package/corpus/templates/slides/app/components/ui/command.tsx +1 -0
  72. package/corpus/templates/slides/app/i18n/en-US.ts +8 -2
  73. package/corpus/templates/slides/app/lib/create-deck-generation.ts +305 -0
  74. package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -12
  75. package/corpus/templates/slides/app/pages/Index.tsx +127 -137
  76. package/corpus/templates/slides/app/root.tsx +8 -0
  77. package/corpus/templates/slides/changelog/2026-08-05-deck-browsing-keeps-all-and-mine-in-the-header-with-a-tighte.md +6 -0
  78. package/corpus/templates/slides/changelog/2026-08-05-new-deck-creation-now-flows-through-a-clean-full-screen-refe.md +6 -0
  79. package/corpus/templates/slides/changelog/2026-08-05-website-imports-now-include-linked-stylesheets-for-more-accu.md +6 -0
  80. package/corpus/templates/slides/server/lib/comment-notifications.ts +44 -21
  81. package/corpus/templates/slides/server/lib/emails.ts +40 -0
  82. package/corpus/templates/slides/server/plugins/transactional-emails.ts +5 -0
  83. package/dist/brand-kit/index.d.ts +1 -0
  84. package/dist/brand-kit/index.js +1 -0
  85. package/dist/brand-kit/tokens.d.ts +91 -0
  86. package/dist/brand-kit/tokens.js +279 -0
  87. package/dist/brand-kit/types.d.ts +25 -0
  88. package/dist/client/AssistantChat.js +7 -7
  89. package/dist/client/onboarding/FirstRunOnboarding.js +26 -2
  90. package/dist/client/onboarding/first-run-registry.d.ts +25 -0
  91. package/dist/client/onboarding/first-run-registry.js +18 -0
  92. package/dist/client/onboarding/index.d.ts +2 -0
  93. package/dist/client/onboarding/index.js +1 -0
  94. package/dist/collab/awareness.d.ts +2 -2
  95. package/dist/collab/routes.d.ts +1 -1
  96. package/dist/collab/struct-routes.d.ts +1 -1
  97. package/dist/db/index.d.ts +1 -1
  98. package/dist/db/index.js +1 -1
  99. package/dist/db/migrations.d.ts +13 -3
  100. package/dist/db/migrations.js +19 -4
  101. package/dist/deploy/build.d.ts +8 -0
  102. package/dist/deploy/build.js +92 -3
  103. package/dist/deploy/workspace-deploy.js +86 -3
  104. package/dist/email-catalog/actions/list-email-activity.d.ts +5 -0
  105. package/dist/email-catalog/actions/list-email-activity.js +19 -0
  106. package/dist/email-catalog/actions/list-email-engagement.d.ts +5 -0
  107. package/dist/email-catalog/actions/list-email-engagement.js +15 -0
  108. package/dist/email-catalog/actions/list-email-log.d.ts +7 -0
  109. package/dist/email-catalog/actions/list-email-log.js +23 -0
  110. package/dist/email-catalog/actions/list-transactional-emails.d.ts +22 -0
  111. package/dist/email-catalog/actions/list-transactional-emails.js +67 -0
  112. package/dist/email-catalog/actions/render-transactional-email-preview.d.ts +9 -0
  113. package/dist/email-catalog/actions/render-transactional-email-preview.js +25 -0
  114. package/dist/email-catalog/authorize.d.ts +1 -0
  115. package/dist/email-catalog/authorize.js +9 -0
  116. package/dist/email-catalog/log.d.ts +60 -0
  117. package/dist/email-catalog/log.js +142 -0
  118. package/dist/email-catalog/provider-metrics.d.ts +34 -0
  119. package/dist/email-catalog/provider-metrics.js +182 -0
  120. package/dist/email-catalog/registry.d.ts +78 -0
  121. package/dist/email-catalog/registry.js +70 -0
  122. package/dist/email-catalog/schema.d.ts +231 -0
  123. package/dist/email-catalog/schema.js +53 -0
  124. package/dist/email-catalog/system-emails.d.ts +13 -0
  125. package/dist/email-catalog/system-emails.js +67 -0
  126. package/dist/jobs/index.d.ts +2 -0
  127. package/dist/jobs/index.js +2 -0
  128. package/dist/jobs/run-history.js +48 -1
  129. package/dist/jobs/scheduler-dispatch.d.ts +7 -0
  130. package/dist/jobs/scheduler-dispatch.js +7 -0
  131. package/dist/jobs/scheduler-health.d.ts +22 -0
  132. package/dist/jobs/scheduler-health.js +172 -0
  133. package/dist/jobs/scheduler.js +67 -2
  134. package/dist/localization/default-messages.d.ts +45 -0
  135. package/dist/localization/default-messages.js +45 -0
  136. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  137. package/dist/notifications/routes.d.ts +3 -3
  138. package/dist/observability/routes.d.ts +3 -3
  139. package/dist/org/handlers.js +9 -1
  140. package/dist/progress/routes.d.ts +1 -1
  141. package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
  142. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  143. package/dist/server/action-discovery.js +22 -0
  144. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +7 -1
  145. package/dist/server/agent-chat/recurring-jobs-runtime.js +12 -0
  146. package/dist/server/agent-chat-plugin.d.ts +2 -1
  147. package/dist/server/agent-chat-plugin.js +69 -22
  148. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  149. package/dist/server/better-auth-instance.js +17 -2
  150. package/dist/server/design-token-utils.d.ts +6 -1
  151. package/dist/server/design-token-utils.js +252 -59
  152. package/dist/server/email.d.ts +11 -0
  153. package/dist/server/email.js +54 -3
  154. package/dist/server/index.d.ts +3 -2
  155. package/dist/server/index.js +3 -2
  156. package/dist/vite/client.js +20 -14
  157. package/package.json +2 -1
@@ -3,7 +3,7 @@
3
3
  Factory is the visual workspace for building agent factories from incoming work
4
4
  to governed delivery. The map is the source of truth; Dispatch owns the shared
5
5
  inbox and routing, while Factory owns graph versions, queue state, rules,
6
- decisions, feedback, agent runs, and provider-action audit records.
6
+ decisions, feedback, agent runs, and provider audit records.
7
7
 
8
8
  Before building common workspace or agent UI, read `agent-native-toolkit`; use
9
9
  `customizing-agent-native` for the configure → compose → eject → propose
@@ -12,7 +12,7 @@ ladder.
12
12
  ## Core rules
13
13
 
14
14
  - Keep app state in SQL via Drizzle and scope every read/write by org and
15
- authenticated member. Use actions as the UI, agent, CLI, MCP, and A2A surface.
15
+ member. Use actions as the UI, agent, CLI, MCP, and A2A surface.
16
16
  - Keep migrations additive and portable. These tables intentionally use explicit
17
17
  `ownerEmail`/`orgId` columns for org-visible data, not `ownableColumns()`;
18
18
  do not call `accessFilter` on them without adding deliberate visibility data.
@@ -31,23 +31,23 @@ ladder.
31
31
  automations add 👀 and tag `@builderio` in the source thread; GitHub and Sentry
32
32
  clear bugs use the Builder run API. Clips, Design, and Content are always
33
33
  owner-managed and never enter autonomous dispatch or PR governance.
34
- - PR governance requires verified internal BuilderIO membership, a clear bug,
35
- passing CI, and handled review feedback. Product or UX implications stay
34
+ - PR governance requires verified BuilderIO membership, a clear bug, passing
35
+ CI, and handled review feedback. Product or UX implications stay
36
36
  manual. Auto-merge additionally requires a verified Factory Builder run.
37
37
  - Reuse the existing ai-services GitHub read and Builder execution APIs. Do not
38
38
  duplicate GitHub installation/webhook infrastructure in this template.
39
39
  - Do not add CRUD routes under `server/routes/api/`; actions are the domain
40
40
  surface. Provider callbacks are the only exception and must verify signatures.
41
- - Factory graph edits create immutable blueprint versions. AI proposes a
42
- complete graph with `source=ai`; a person reviews and publishes it through
41
+ - Factory graph edits create immutable blueprint versions. AI proposes a graph
42
+ with `source=ai`; a person reviews and publishes it through
43
43
  the same action surface as manual edits.
44
44
 
45
45
  ## Application state
46
46
 
47
- - `navigation.view`: `factory` when the visual workspace is open.
47
+ - `navigation.view`: `factory` when the workspace is open.
48
48
  - `navigation.factoryId`: selected Factory id when present.
49
49
  - `navigation.factoryTab`: `map` | `inbox` | `rules` | `automations` | `settings`.
50
- - `navigation.factoryNodeId` / `navigation.factoryEdgeId`: selected graph target.
50
+ - `navigation.factoryNodeId` / `navigation.factoryEdgeId`: selected graph item.
51
51
  - A selected graph node or edge is part of `navigation` context. Read
52
52
  `view-screen` before answering why a route exists or changing the selected
53
53
  Factory.
@@ -56,18 +56,19 @@ ladder.
56
56
 
57
57
  | Action | Purpose |
58
58
  | --- | --- |
59
- | `list-triage-items` / `get-triage-item` | Inspect the queue and evidence. |
59
+ | `list-triage-items` / `get-triage-item` | Inspect queue and evidence. |
60
60
  | `poll-slack-channel` | Observe Slack history; never writes to Slack. |
61
61
  | `get-slack-feedback-context` | Read the bounded full Slack thread before classification. |
62
62
  | `poll-github-sources` / `poll-sentry-errors` | Observe bounded GitHub and Sentry source queues. |
63
63
  | `ingest-github-observation` | Store read-only PR evidence. |
64
64
  | `list-triage-rules` / `save-triage-rule` | Tune prompt rules and guards. |
65
- | `evaluate-triage-item` | Append a structured decision. |
65
+ | `evaluate-triage-item` | Append a decision. |
66
66
  | `record-triage-feedback` | Capture human correction for learning. |
67
67
  | `approve-factory-item` | Explicitly authorize one bounded run. |
68
68
  | `start-builder-for-item` | Govern clear-bug dispatch; Slack tags Builder in-thread, other sources use Builder API. |
69
69
  | `govern-agent-native-pull-request` | Apply CI, review, internal-author, product, and owner gates to PR approval/merge. |
70
- | `list-factory-automations` / `save-factory-automation` / `run-factory-automation` | Inspect and edit organization-owned Factory prompts, models, schedules, and runs. |
70
+ | `list-factory-automations` / `save-factory-automation` / `run-factory-automation` | Inspect and edit org-owned Factory prompts, models, schedules, and runs. |
71
+ | `get-factory-automation-health` | Inspect the durable scheduler heartbeat and last scheduler error when runs appear stale. |
71
72
  | `suggest-factory-rules` | Mine feedback and fast approvals into proposals. |
72
73
  | `reconcile-triage-run` | Persist callback/provider reconciliation. |
73
74
  | `list-factories` / `get-factory-graph` | Inspect Factory definitions, graph versions, and live evidence metrics. |
@@ -77,7 +78,7 @@ ladder.
77
78
  Rules start in shadow mode; hard guards always apply. Editable organization
78
79
  automations execute stored prompts; every external mutation needs a durable run,
79
80
  idempotency key, and provider confirmation. The legacy observer is disabled
80
- when organization automations are seeded.
81
+ once organization automations are seeded.
81
82
 
82
83
  Use the visual editor for direct blueprint changes. Use the agent chat for
83
84
  natural language design, explanations, and proposals; it must preserve a
@@ -87,14 +88,14 @@ actions, never through graph JSON.
87
88
 
88
89
  ## Scheduler identity
89
90
 
90
- `WORKSPACE_OWNER_EMAIL` is read only at startup to find the deployment
91
- organization and stamp seeded automation `createdBy`; it is never caller
92
- identity and must not enter request authorization or credential resolution.
91
+ `WORKSPACE_OWNER_EMAIL` is read only at startup to find the deployment org and
92
+ stamp seeded automation `createdBy`; it is never caller identity and must not
93
+ enter request authorization or credential resolution.
93
94
 
94
95
  ## Hosting
95
96
 
96
97
  Production needs `DATABASE_URL`, `WORKSPACE_OWNER_EMAIL`, and
97
- `FACTORY_PUBLIC_URL`. Builder execution additionally needs the service URL and
98
- project ID plus workspace-resolved Builder credentials. GitHub and Sentry
98
+ `FACTORY_PUBLIC_URL`. Builder execution additionally needs the service URL,
99
+ project ID, and workspace-resolved Builder credentials. GitHub and Sentry
99
100
  polling use workspace-resolved provider credentials. Provider callbacks and
100
101
  external writes must remain auditable and fail closed when evidence is partial.
@@ -0,0 +1,50 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { getAutomationSchedulerHealth } from "@agent-native/core/jobs";
3
+ import { z } from "zod";
4
+
5
+ import {
6
+ requireWorkspaceMember,
7
+ workspaceMemberIdentityFromContext,
8
+ } from "../server/lib/require-workspace-member.js";
9
+
10
+ const STALE_AFTER_MS = 3 * 60_000;
11
+
12
+ export default defineAction({
13
+ description:
14
+ "Inspect the Factory recurring-automation scheduler heartbeat and last error. Use this when an automation appears not to be running.",
15
+ schema: z.object({}),
16
+ http: { method: "GET" },
17
+ readOnly: true,
18
+ run: async (_, context) => {
19
+ const { orgId } = await requireWorkspaceMember(
20
+ workspaceMemberIdentityFromContext(context),
21
+ );
22
+ const health = await getAutomationSchedulerHealth({
23
+ appId: "factory",
24
+ orgId,
25
+ });
26
+ if (!health?.lastCheckedAt) {
27
+ return {
28
+ status: "no-data" as const,
29
+ lastCheckedAt: null,
30
+ lastDispatchedAt: health?.lastDispatchedAt ?? null,
31
+ lastError: health?.lastError ?? null,
32
+ runtime: health?.runtime ?? null,
33
+ staleAfterMs: STALE_AFTER_MS,
34
+ };
35
+ }
36
+ const stale = Date.now() - health.lastCheckedAt > STALE_AFTER_MS;
37
+ return {
38
+ status: health.lastError
39
+ ? ("error" as const)
40
+ : stale
41
+ ? ("stale" as const)
42
+ : ("healthy" as const),
43
+ lastCheckedAt: health.lastCheckedAt,
44
+ lastDispatchedAt: health.lastDispatchedAt,
45
+ lastError: health.lastError,
46
+ runtime: health.runtime,
47
+ staleAfterMs: STALE_AFTER_MS,
48
+ };
49
+ },
50
+ });
@@ -1,4 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core/action";
2
+ import { getEmailReadiness } from "@agent-native/core/server";
2
3
  import { and, eq } from "drizzle-orm";
3
4
  import { z } from "zod";
4
5
 
@@ -19,6 +20,7 @@ export default defineAction({
19
20
  const { orgId } = await requireWorkspaceMember(
20
21
  workspaceMemberIdentityFromContext(context),
21
22
  );
23
+ const emailReadiness = await getEmailReadiness();
22
24
  const row = (
23
25
  await getDb()
24
26
  .select()
@@ -41,6 +43,9 @@ export default defineAction({
41
43
  sentryProjectSlug: null,
42
44
  sentryEnvironment: null,
43
45
  lastSentrySeenAt: null,
46
+ automationFailureAlertsEnabled: true,
47
+ automationFailureAlertEmail: null,
48
+ emailReadiness,
44
49
  };
45
50
  }
46
51
  return {
@@ -48,6 +53,9 @@ export default defineAction({
48
53
  pollingEnabled: row.pollingEnabled === 1,
49
54
  githubPollingEnabled: row.githubPollingEnabled === 1,
50
55
  sentryPollingEnabled: row.sentryPollingEnabled === 1,
56
+ automationFailureAlertsEnabled: row.automationFailureAlertsEnabled === 1,
57
+ automationFailureAlertEmail: row.automationFailureAlertEmail,
58
+ emailReadiness,
51
59
  };
52
60
  },
53
61
  });
@@ -1,4 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core/action";
2
+ import { and, eq } from "drizzle-orm";
2
3
  import { z } from "zod";
3
4
 
4
5
  import { getDb } from "../server/db/index.js";
@@ -24,6 +25,8 @@ export default defineAction({
24
25
  sentryProjectSlug: z.string().trim().max(200).optional(),
25
26
  sentryEnvironment: z.string().trim().max(200).optional(),
26
27
  repository: z.string().trim().max(256).optional(),
28
+ automationFailureAlertsEnabled: z.boolean().default(true),
29
+ automationFailureAlertEmail: z.string().trim().email().optional(),
27
30
  }),
28
31
  http: { method: "POST" },
29
32
  run: async (
@@ -38,6 +41,8 @@ export default defineAction({
38
41
  sentryProjectSlug,
39
42
  sentryEnvironment,
40
43
  repository,
44
+ automationFailureAlertsEnabled,
45
+ automationFailureAlertEmail,
41
46
  },
42
47
  context,
43
48
  ) => {
@@ -46,6 +51,19 @@ export default defineAction({
46
51
  );
47
52
  const now = new Date().toISOString();
48
53
  const db = getDb();
54
+ const existing = (
55
+ await db
56
+ .select({
57
+ automationFailureAlertEmail: triageConfig.automationFailureAlertEmail,
58
+ })
59
+ .from(triageConfig)
60
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
61
+ .limit(1)
62
+ )[0];
63
+ const persistedAutomationFailureAlertEmail =
64
+ automationFailureAlertEmail ??
65
+ existing?.automationFailureAlertEmail ??
66
+ null;
49
67
  await db
50
68
  .insert(triageConfig)
51
69
  .values({
@@ -60,6 +78,8 @@ export default defineAction({
60
78
  sentryProjectSlug: sentryProjectSlug ?? null,
61
79
  sentryEnvironment: sentryEnvironment ?? null,
62
80
  repository: repository ?? null,
81
+ automationFailureAlertsEnabled: automationFailureAlertsEnabled ? 1 : 0,
82
+ automationFailureAlertEmail: persistedAutomationFailureAlertEmail,
63
83
  createdAt: now,
64
84
  updatedAt: now,
65
85
  ownerEmail: userEmail,
@@ -78,6 +98,10 @@ export default defineAction({
78
98
  sentryProjectSlug: sentryProjectSlug ?? null,
79
99
  sentryEnvironment: sentryEnvironment ?? null,
80
100
  repository: repository ?? null,
101
+ automationFailureAlertsEnabled: automationFailureAlertsEnabled
102
+ ? 1
103
+ : 0,
104
+ automationFailureAlertEmail: persistedAutomationFailureAlertEmail,
81
105
  updatedAt: now,
82
106
  ownerEmail: userEmail,
83
107
  },
@@ -88,6 +112,8 @@ export default defineAction({
88
112
  githubPollingEnabled,
89
113
  sentryPollingEnabled,
90
114
  slackChannelId: slackChannelId ?? null,
115
+ automationFailureAlertsEnabled,
116
+ automationFailureAlertEmail: persistedAutomationFailureAlertEmail,
91
117
  };
92
118
  },
93
119
  });
@@ -178,6 +178,33 @@ const messages = {
178
178
  pastRunsEmpty: "No runs recorded yet.",
179
179
  saveAutomation: "Save",
180
180
  runNow: "Run now",
181
+ automationHealthTitle: "Scheduler health",
182
+ automationHealthDescription:
183
+ "The heartbeat shows whether the deployed recurring-job worker is still checking schedules.",
184
+ automationHealthHealthy: "Healthy",
185
+ automationHealthStale: "Stale",
186
+ automationHealthError: "Error",
187
+ automationHealthNoData: "No heartbeat",
188
+ automationLastCheck: "Last check",
189
+ automationLastDispatch: "Last dispatch",
190
+ automationRuntime: "Runtime",
191
+ automationHealthNoDataHint:
192
+ "No scheduler heartbeat has been recorded yet. Deploy the latest Factory build, then check again.",
193
+ automationHealthStaleHint:
194
+ "The scheduler has not checked recently. This usually means the deployed scheduled function or background worker is not running.",
195
+ automationHealthErrorDetail: "Last scheduler error",
196
+ automationOpenThread: "Open thread",
197
+ automationFailureAlertsTitle: "Automation failure alerts",
198
+ automationFailureAlertsDescription:
199
+ "Send an in-app alert and email when a Factory automation fails. Repeated identical failures are grouped for 15 minutes.",
200
+ automationFailureAlertsEnabled: "Email me when automations fail",
201
+ automationFailureAlertEmail: "Alert email",
202
+ automationFailureAlertEmailPlaceholder: "Defaults to the workspace owner",
203
+ automationFailureEmailReadiness: "Email provider",
204
+ automationDiagnosticsLoadError:
205
+ "Could not load Factory diagnostics. Check access, deployment, and database migrations, then try again.",
206
+ automationEmailReadinessHint:
207
+ "Email uses the organization Dispatch vault. Configure a provider there if this is not ready.",
181
208
  },
182
209
  factoryCanvas: {
183
210
  dragHint: "Drag to arrange",