@agent-native/core 0.136.5 → 0.137.1

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 (174) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/components/AgentCompletionSound.tsx +105 -0
  3. package/corpus/templates/analytics/app/components/layout/Layout.tsx +44 -35
  4. package/corpus/templates/analytics/app/i18n-data.ts +38 -0
  5. package/corpus/templates/analytics/app/pages/Settings.tsx +53 -1
  6. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +6 -0
  7. package/corpus/templates/analytics/changelog/2026-08-04-choose-whether-analytics-plays-a-bell-when-the-agent-finishe.md +6 -0
  8. package/corpus/templates/analytics/shared/analytics-user-prefs.ts +2 -0
  9. package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
  10. package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
  11. package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
  12. package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
  13. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
  14. package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
  15. package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
  16. package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
  17. package/corpus/templates/content/actions/_database-utils.ts +6 -0
  18. package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
  19. package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
  20. package/corpus/templates/content/actions/configure-document-property.ts +113 -32
  21. package/corpus/templates/content/actions/delete-content-database.ts +5 -7
  22. package/corpus/templates/content/actions/delete-document-property.ts +109 -62
  23. package/corpus/templates/content/actions/delete-document.ts +178 -36
  24. package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
  25. package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
  26. package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
  27. package/corpus/templates/content/actions/remove-database-items.ts +13 -0
  28. package/corpus/templates/content/actions/set-document-property.ts +69 -1
  29. package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
  30. package/corpus/templates/content/parity/matrix.md +1 -1
  31. package/corpus/templates/content/parity/matrix.ts +1 -0
  32. package/corpus/templates/content/server/db/schema.ts +27 -0
  33. package/corpus/templates/content/server/plugins/db.ts +24 -0
  34. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
  35. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  36. package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
  37. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
  38. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
  39. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
  40. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
  41. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
  42. package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
  43. package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
  44. package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
  45. package/corpus/templates/design/app/i18n-data.ts +8 -0
  46. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
  47. package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
  48. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
  49. package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
  50. package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
  51. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
  52. package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
  53. package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
  54. package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
  55. package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
  56. package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
  57. package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
  58. package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
  59. package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
  60. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
  61. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
  62. package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
  63. package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
  64. package/corpus/templates/factory/.env.example +17 -0
  65. package/corpus/templates/factory/AGENTS.md +27 -17
  66. package/corpus/templates/factory/README.md +19 -9
  67. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
  68. package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
  69. package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
  70. package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
  71. package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
  72. package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
  73. package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
  74. package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
  75. package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
  76. package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
  77. package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
  78. package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
  79. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
  80. package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
  81. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
  82. package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
  83. package/corpus/templates/factory/app/routes/factory.tsx +462 -9
  84. package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
  85. package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
  86. package/corpus/templates/factory/netlify.toml +2 -2
  87. package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
  88. package/corpus/templates/factory/server/connectors/slack.ts +133 -5
  89. package/corpus/templates/factory/server/db/schema.ts +6 -0
  90. package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
  91. package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
  92. package/corpus/templates/factory/server/plugins/auth.ts +1 -0
  93. package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
  94. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
  95. package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
  96. package/corpus/templates/factory/server/triage/contracts.ts +14 -1
  97. package/corpus/templates/factory/server/triage/github-client.ts +404 -0
  98. package/corpus/templates/factory/server/triage/metadata.ts +44 -0
  99. package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
  100. package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
  101. package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
  102. package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
  103. package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
  104. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
  105. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
  106. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
  107. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
  108. package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
  109. package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
  110. package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
  111. package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
  112. package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
  113. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
  114. package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
  115. package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
  116. package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
  117. package/corpus/templates/plan/shared/plan-content.ts +17 -2
  118. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +321 -0
  119. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +32 -11
  120. package/corpus/templates/slides/app/lib/recent-references.ts +82 -0
  121. package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
  122. package/corpus/templates/slides/app/pages/Index.tsx +236 -181
  123. package/dist/cli/skills-content/canvas.d.ts +3 -3
  124. package/dist/cli/skills-content/canvas.js +16 -5
  125. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  126. package/dist/cli/skills-content/visual-plan-skill.js +27 -0
  127. package/dist/cli/skills-content/wireframe.d.ts +2 -2
  128. package/dist/cli/skills-content/wireframe.js +7 -0
  129. package/dist/client/AgentPanel.js +23 -8
  130. package/dist/client/DefaultSpinner.d.ts +0 -12
  131. package/dist/client/DefaultSpinner.js +22 -2
  132. package/dist/client/api-path.d.ts +6 -0
  133. package/dist/client/api-path.js +55 -0
  134. package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
  135. package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
  136. package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
  137. package/dist/client/onboarding/first-run-enabled.js +9 -0
  138. package/dist/client/onboarding/index.d.ts +2 -1
  139. package/dist/client/onboarding/index.js +1 -0
  140. package/dist/client/onboarding/use-onboarding.d.ts +6 -1
  141. package/dist/client/onboarding/use-onboarding.js +35 -1
  142. package/dist/client/route-state.js +10 -0
  143. package/dist/collab/awareness.d.ts +2 -2
  144. package/dist/collab/routes.d.ts +1 -1
  145. package/dist/connections/catalog.d.ts +4 -4
  146. package/dist/connections/catalog.js +3 -3
  147. package/dist/db/index.d.ts +1 -1
  148. package/dist/db/index.js +1 -1
  149. package/dist/deploy/build.js +2 -1
  150. package/dist/notifications/routes.d.ts +3 -3
  151. package/dist/observability/routes.d.ts +1 -1
  152. package/dist/onboarding/app-profile.d.ts +4 -0
  153. package/dist/onboarding/app-profile.js +378 -0
  154. package/dist/onboarding/index.d.ts +2 -1
  155. package/dist/onboarding/index.js +1 -0
  156. package/dist/onboarding/plugin.d.ts +2 -0
  157. package/dist/onboarding/plugin.js +21 -1
  158. package/dist/onboarding/types.d.ts +19 -0
  159. package/dist/progress/routes.d.ts +1 -1
  160. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  161. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  162. package/dist/secrets/routes.d.ts +3 -3
  163. package/dist/server/auth.js +21 -1
  164. package/dist/server/better-auth-instance.d.ts +3 -2
  165. package/dist/server/better-auth-instance.js +9 -7
  166. package/dist/server/email-markdown.js +3 -8
  167. package/dist/shared/first-run-onboarding.d.ts +3 -0
  168. package/dist/shared/first-run-onboarding.js +3 -0
  169. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
  170. package/dist/triggers/index.d.ts +3 -0
  171. package/dist/triggers/index.js +5 -0
  172. package/docs/content/cross-app-sso.mdx +26 -0
  173. package/package.json +1 -1
  174. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
@@ -0,0 +1,161 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { and, eq } from "drizzle-orm";
3
+ import { z } from "zod";
4
+
5
+ import { getDb } from "../server/db/index.js";
6
+ import { triageConfig, triageItems } from "../server/db/schema.js";
7
+ import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
8
+ import {
9
+ requireWorkspaceMember,
10
+ workspaceMemberIdentityFromContext,
11
+ } from "../server/lib/require-workspace-member.js";
12
+ import { itemDedupeKey } from "../server/triage/ids.js";
13
+ import { mergeTriageMetadata } from "../server/triage/metadata.js";
14
+ import { createSentryClient } from "../server/triage/sentry-client.js";
15
+
16
+ export default defineAction({
17
+ description:
18
+ "Poll bounded unresolved Sentry issues for the configured organization and record them in the Factory queue. This does not change Sentry.",
19
+ schema: z.object({ limit: z.number().int().min(1).max(50).default(25) }),
20
+ http: false,
21
+ run: async ({ limit }, context) => {
22
+ const { userEmail, orgId } = await requireWorkspaceMember(
23
+ workspaceMemberIdentityFromContext(context),
24
+ );
25
+ await requireFactoryAutomation(
26
+ context,
27
+ { userEmail, orgId },
28
+ "sourcePolling",
29
+ );
30
+ const config = (
31
+ await getDb()
32
+ .select()
33
+ .from(triageConfig)
34
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
35
+ .limit(1)
36
+ )[0];
37
+ if (config?.sentryPollingEnabled !== 1) {
38
+ throw new Error("Enable Sentry polling before polling Sentry.");
39
+ }
40
+ if (!config.sentryOrgSlug) {
41
+ throw new Error("Configure a Sentry organization before polling Sentry.");
42
+ }
43
+ const query = [
44
+ "is:unresolved",
45
+ config.sentryProjectSlug ? `project:${config.sentryProjectSlug}` : "",
46
+ config.sentryEnvironment ? `environment:${config.sentryEnvironment}` : "",
47
+ ]
48
+ .filter(Boolean)
49
+ .join(" ");
50
+ const issues = await createSentryClient({
51
+ ownerEmail: userEmail,
52
+ orgId,
53
+ orgSlug: config.sentryOrgSlug,
54
+ }).listIssues(query, limit);
55
+ const cursor = config.lastSentrySeenAt
56
+ ? Date.parse(config.lastSentrySeenAt)
57
+ : null;
58
+ if (cursor !== null && Number.isNaN(cursor)) {
59
+ throw new Error("Stored Sentry polling cursor is not a valid timestamp.");
60
+ }
61
+ // Reconcile every bounded result by its stable Sentry issue id. Frequency
62
+ // ordering is not a safe timestamp cursor: an older issue can re-enter the
63
+ // top page after its frequency changes.
64
+ for (const issue of issues) {
65
+ const firstSeen = Date.parse(issue.firstSeen);
66
+ if (Number.isNaN(firstSeen))
67
+ throw new Error(
68
+ `Sentry issue ${issue.id} has an invalid firstSeen timestamp.`,
69
+ );
70
+ }
71
+ const observedIssues = issues;
72
+ const db = getDb();
73
+ const now = new Date().toISOString();
74
+
75
+ await db.transaction(async (tx) => {
76
+ for (const issue of observedIssues) {
77
+ const id = itemDedupeKey(
78
+ { source: "sentry", externalId: issue.id },
79
+ orgId,
80
+ );
81
+ const existing = (
82
+ await tx
83
+ .select()
84
+ .from(triageItems)
85
+ .where(and(eq(triageItems.id, id), eq(triageItems.orgId, orgId)))
86
+ .limit(1)
87
+ )[0];
88
+ const metadata = mergeTriageMetadata(existing?.metadataJson ?? "{}", {
89
+ kind: "sentry_issue",
90
+ sentryIssueId: issue.id,
91
+ shortId: issue.shortId,
92
+ culprit: issue.culprit,
93
+ level: issue.level,
94
+ projectSlug: issue.projectSlug,
95
+ errorReport: [issue.title, issue.culprit].filter(Boolean).join("\n"),
96
+ count: issue.count,
97
+ firstSeen: issue.firstSeen,
98
+ lastSeen: issue.lastSeen,
99
+ });
100
+ await tx
101
+ .insert(triageItems)
102
+ .values({
103
+ id,
104
+ source: "sentry",
105
+ externalId: issue.id,
106
+ sourceUrl: issue.permalink,
107
+ title: issue.title,
108
+ summary: [issue.culprit, `${issue.count} events`, issue.level]
109
+ .filter(Boolean)
110
+ .join(" · ")
111
+ .slice(0, 4_000),
112
+ status: existing?.status ?? "received",
113
+ risk: existing?.risk ?? "unknown",
114
+ coverage: existing?.coverage ?? "complete",
115
+ dedupeKey: id,
116
+ metadataJson: metadata,
117
+ lastSeenAt: issue.lastSeen,
118
+ createdAt: existing?.createdAt ?? now,
119
+ updatedAt: now,
120
+ ownerEmail: existing?.ownerEmail ?? userEmail,
121
+ orgId,
122
+ })
123
+ .onConflictDoUpdate({
124
+ target: triageItems.id,
125
+ set: {
126
+ sourceUrl: issue.permalink,
127
+ title: issue.title,
128
+ summary: [issue.culprit, `${issue.count} events`, issue.level]
129
+ .filter(Boolean)
130
+ .join(" · ")
131
+ .slice(0, 4_000),
132
+ metadataJson: metadata,
133
+ lastSeenAt: issue.lastSeen,
134
+ updatedAt: now,
135
+ },
136
+ });
137
+ }
138
+
139
+ await tx
140
+ .update(triageConfig)
141
+ .set({
142
+ lastSentrySeenAt:
143
+ observedIssues.reduce<string | null>((latest, issue) => {
144
+ if (!latest) return issue.firstSeen;
145
+ return Date.parse(issue.firstSeen) > Date.parse(latest)
146
+ ? issue.firstSeen
147
+ : latest;
148
+ }, config.lastSentrySeenAt) ?? config.lastSentrySeenAt,
149
+ updatedAt: now,
150
+ })
151
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)));
152
+ });
153
+
154
+ return {
155
+ ok: true,
156
+ observed: observedIssues.length,
157
+ fetched: issues.length,
158
+ sentryOrgSlug: config.sentryOrgSlug,
159
+ };
160
+ },
161
+ });
@@ -27,9 +27,12 @@ export default defineAction({
27
27
  await db
28
28
  .select()
29
29
  .from(triageConfig)
30
- .where(eq(triageConfig.id, orgId))
30
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
31
31
  .limit(1)
32
32
  )[0];
33
+ if (config?.pollingEnabled !== 1) {
34
+ throw new Error("Enable Slack polling before polling Slack.");
35
+ }
33
36
  const channelId = requestedChannelId ?? config?.slackChannelId;
34
37
  if (!channelId) {
35
38
  throw new Error("Configure a Slack channel before polling.");
@@ -83,7 +86,6 @@ export default defineAction({
83
86
  channelId: envelope.channelId ?? null,
84
87
  threadTs: envelope.threadTs ?? null,
85
88
  coverage: envelope.coverage,
86
- metadataJson: JSON.stringify(envelope.metadata ?? {}),
87
89
  lastSeenAt: now,
88
90
  updatedAt: now,
89
91
  },
@@ -0,0 +1,42 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import {
3
+ listAutomationDefinitions,
4
+ queueAutomationRunNow,
5
+ } from "@agent-native/core/triggers";
6
+ import { z } from "zod";
7
+
8
+ import {
9
+ requireWorkspaceMember,
10
+ workspaceMemberIdentityFromContext,
11
+ } from "../server/lib/require-workspace-member.js";
12
+
13
+ export default defineAction({
14
+ description:
15
+ "Queue one organization-scoped Factory automation for an immediate run and return its durable run id.",
16
+ agentTool: false,
17
+ schema: z.object({
18
+ factoryId: z.string().trim().min(1).optional(),
19
+ automationId: z.string().trim().min(1),
20
+ }),
21
+ http: { method: "POST" },
22
+ run: async ({ automationId }, context) => {
23
+ const { userEmail, orgId } = await requireWorkspaceMember(
24
+ workspaceMemberIdentityFromContext(context),
25
+ );
26
+ const definitions = await listAutomationDefinitions(
27
+ { userEmail, orgId },
28
+ "organization",
29
+ );
30
+ const definition = definitions.find(
31
+ (entry) =>
32
+ entry.meta.domain === "factory" && entry.resource.id === automationId,
33
+ );
34
+ if (!definition) throw new Error("Factory automation not found.");
35
+ return queueAutomationRunNow({
36
+ userEmail,
37
+ orgId,
38
+ scope: "organization",
39
+ name: definition.name,
40
+ });
41
+ },
42
+ });
@@ -0,0 +1,69 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import {
3
+ listAutomationDefinitions,
4
+ updateAutomation,
5
+ } from "@agent-native/core/triggers";
6
+ import { z } from "zod";
7
+
8
+ import {
9
+ requireWorkspaceMember,
10
+ workspaceMemberIdentityFromContext,
11
+ } from "../server/lib/require-workspace-member.js";
12
+
13
+ export default defineAction({
14
+ description:
15
+ "Edit a Factory automation's prompt, model, schedule, or enabled state in its organization-owned markdown resource.",
16
+ agentTool: false,
17
+ schema: z.object({
18
+ factoryId: z.string().trim().min(1).optional(),
19
+ automationId: z.string().trim().min(1),
20
+ name: z.string().trim().min(1).max(120),
21
+ prompt: z.string().trim().min(1).max(20_000),
22
+ model: z.string().trim().max(200).optional(),
23
+ schedule: z.string().trim().min(1).max(100),
24
+ enabled: z.boolean(),
25
+ }),
26
+ http: { method: "POST" },
27
+ run: async (
28
+ { automationId, name, prompt, model, schedule, enabled },
29
+ context,
30
+ ) => {
31
+ const { userEmail, orgId } = await requireWorkspaceMember(
32
+ workspaceMemberIdentityFromContext(context),
33
+ );
34
+ const definitions = await listAutomationDefinitions(
35
+ { userEmail, orgId },
36
+ "organization",
37
+ );
38
+ const definition = definitions.find(
39
+ (entry) =>
40
+ entry.meta.domain === "factory" && entry.resource.id === automationId,
41
+ );
42
+ if (!definition) throw new Error("Factory automation not found.");
43
+ if (definition.name !== name) {
44
+ throw new Error(
45
+ "Factory automation id and name do not refer to the same automation.",
46
+ );
47
+ }
48
+ const updated = await updateAutomation(
49
+ { userEmail, orgId },
50
+ {
51
+ name: definition.name,
52
+ scope: "organization",
53
+ body: prompt,
54
+ model: model?.trim() || null,
55
+ schedule,
56
+ enabled,
57
+ },
58
+ );
59
+ return {
60
+ ok: true,
61
+ id: definition.resource.id,
62
+ name: updated.name,
63
+ prompt: updated.body,
64
+ model: updated.meta.model ?? null,
65
+ schedule: updated.meta.schedule || null,
66
+ enabled: updated.meta.enabled,
67
+ };
68
+ },
69
+ });
@@ -12,12 +12,17 @@ const workspaceSchema = z.enum(["primary", "secondary"]);
12
12
 
13
13
  export default defineAction({
14
14
  description:
15
- "Save Factory observation settings. This controls read-only Slack polling and repository metadata; it never starts an executor or changes a provider.",
15
+ "Save Factory source settings. This controls Slack, GitHub, and Sentry polling; organization automations decide when governed provider work may start.",
16
16
  schema: z.object({
17
17
  slackWorkspace: workspaceSchema.default("primary"),
18
18
  slackChannelId: z.string().trim().min(1).max(128).optional(),
19
19
  slackChannelName: z.string().trim().max(200).optional(),
20
20
  pollingEnabled: z.boolean().default(false),
21
+ githubPollingEnabled: z.boolean().default(false),
22
+ sentryPollingEnabled: z.boolean().default(false),
23
+ sentryOrgSlug: z.string().trim().max(200).optional(),
24
+ sentryProjectSlug: z.string().trim().max(200).optional(),
25
+ sentryEnvironment: z.string().trim().max(200).optional(),
21
26
  repository: z.string().trim().max(256).optional(),
22
27
  }),
23
28
  http: { method: "POST" },
@@ -27,6 +32,11 @@ export default defineAction({
27
32
  slackChannelId,
28
33
  slackChannelName,
29
34
  pollingEnabled,
35
+ githubPollingEnabled,
36
+ sentryPollingEnabled,
37
+ sentryOrgSlug,
38
+ sentryProjectSlug,
39
+ sentryEnvironment,
30
40
  repository,
31
41
  },
32
42
  context,
@@ -44,6 +54,11 @@ export default defineAction({
44
54
  slackChannelId: slackChannelId ?? null,
45
55
  slackChannelName: slackChannelName ?? null,
46
56
  pollingEnabled: pollingEnabled ? 1 : 0,
57
+ githubPollingEnabled: githubPollingEnabled ? 1 : 0,
58
+ sentryPollingEnabled: sentryPollingEnabled ? 1 : 0,
59
+ sentryOrgSlug: sentryOrgSlug ?? null,
60
+ sentryProjectSlug: sentryProjectSlug ?? null,
61
+ sentryEnvironment: sentryEnvironment ?? null,
47
62
  repository: repository ?? null,
48
63
  createdAt: now,
49
64
  updatedAt: now,
@@ -57,11 +72,22 @@ export default defineAction({
57
72
  slackChannelId: slackChannelId ?? null,
58
73
  slackChannelName: slackChannelName ?? null,
59
74
  pollingEnabled: pollingEnabled ? 1 : 0,
75
+ githubPollingEnabled: githubPollingEnabled ? 1 : 0,
76
+ sentryPollingEnabled: sentryPollingEnabled ? 1 : 0,
77
+ sentryOrgSlug: sentryOrgSlug ?? null,
78
+ sentryProjectSlug: sentryProjectSlug ?? null,
79
+ sentryEnvironment: sentryEnvironment ?? null,
60
80
  repository: repository ?? null,
61
81
  updatedAt: now,
62
82
  ownerEmail: userEmail,
63
83
  },
64
84
  });
65
- return { ok: true, pollingEnabled, slackChannelId: slackChannelId ?? null };
85
+ return {
86
+ ok: true,
87
+ pollingEnabled,
88
+ githubPollingEnabled,
89
+ sentryPollingEnabled,
90
+ slackChannelId: slackChannelId ?? null,
91
+ };
66
92
  },
67
93
  });