@agent-native/core 0.136.4 → 0.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +53 -0
  3. package/corpus/templates/clips/actions/import-loom-recording.ts +7 -0
  4. package/corpus/templates/clips/actions/lib/loom-import-job.ts +24 -4
  5. package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
  6. package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
  7. package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
  8. package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
  9. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
  10. package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
  11. package/corpus/templates/clips/changelog/2026-08-03-restart-during-a-recording-now-immediately-starts-a-fresh-ta.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
  13. package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
  14. package/corpus/templates/clips/desktop/src/app.tsx +81 -30
  15. package/corpus/templates/clips/desktop/src/lib/recorder.ts +436 -158
  16. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +14 -1
  17. package/corpus/templates/clips/server/plugins/auth.ts +9 -0
  18. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +13 -0
  19. package/corpus/templates/content/actions/_database-utils.ts +6 -0
  20. package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
  21. package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
  22. package/corpus/templates/content/actions/configure-document-property.ts +113 -32
  23. package/corpus/templates/content/actions/delete-content-database.ts +5 -7
  24. package/corpus/templates/content/actions/delete-document-property.ts +109 -62
  25. package/corpus/templates/content/actions/delete-document.ts +178 -36
  26. package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
  27. package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
  28. package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
  29. package/corpus/templates/content/actions/remove-database-items.ts +13 -0
  30. package/corpus/templates/content/actions/set-document-property.ts +69 -1
  31. package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
  32. package/corpus/templates/content/parity/matrix.md +1 -1
  33. package/corpus/templates/content/parity/matrix.ts +1 -0
  34. package/corpus/templates/content/server/db/schema.ts +27 -0
  35. package/corpus/templates/content/server/plugins/db.ts +24 -0
  36. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
  37. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  38. package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
  39. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
  40. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
  41. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
  42. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
  43. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
  44. package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
  45. package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
  46. package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
  47. package/corpus/templates/design/app/i18n-data.ts +8 -0
  48. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
  49. package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
  50. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
  51. package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
  52. package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
  53. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
  54. package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
  55. package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
  56. package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
  57. package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
  58. package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
  59. package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
  60. package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
  61. package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
  62. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
  63. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
  64. package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
  65. package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
  66. package/corpus/templates/factory/.env.example +17 -0
  67. package/corpus/templates/factory/AGENTS.md +27 -17
  68. package/corpus/templates/factory/README.md +19 -9
  69. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
  70. package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
  71. package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
  72. package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
  73. package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
  74. package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
  75. package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
  76. package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
  77. package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
  78. package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
  79. package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
  80. package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
  81. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
  82. package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
  83. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
  84. package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
  85. package/corpus/templates/factory/app/routes/factory.tsx +462 -9
  86. package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
  87. package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
  88. package/corpus/templates/factory/netlify.toml +2 -2
  89. package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
  90. package/corpus/templates/factory/server/connectors/slack.ts +133 -5
  91. package/corpus/templates/factory/server/db/schema.ts +6 -0
  92. package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
  93. package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
  94. package/corpus/templates/factory/server/plugins/auth.ts +1 -0
  95. package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
  96. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
  97. package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
  98. package/corpus/templates/factory/server/triage/contracts.ts +14 -1
  99. package/corpus/templates/factory/server/triage/github-client.ts +404 -0
  100. package/corpus/templates/factory/server/triage/metadata.ts +44 -0
  101. package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
  102. package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
  103. package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
  104. package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
  105. package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
  106. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
  107. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
  108. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
  109. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
  110. package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
  111. package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
  112. package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
  113. package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
  114. package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
  115. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
  116. package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
  117. package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
  118. package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
  119. package/corpus/templates/plan/shared/plan-content.ts +17 -2
  120. package/dist/cli/skills-content/canvas.d.ts +3 -3
  121. package/dist/cli/skills-content/canvas.js +16 -5
  122. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  123. package/dist/cli/skills-content/visual-plan-skill.js +27 -0
  124. package/dist/cli/skills-content/wireframe.d.ts +2 -2
  125. package/dist/cli/skills-content/wireframe.js +7 -0
  126. package/dist/client/AgentPanel.js +23 -8
  127. package/dist/client/api-path.d.ts +6 -0
  128. package/dist/client/api-path.js +55 -0
  129. package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
  130. package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
  131. package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
  132. package/dist/client/onboarding/first-run-enabled.js +9 -0
  133. package/dist/client/onboarding/index.d.ts +2 -1
  134. package/dist/client/onboarding/index.js +1 -0
  135. package/dist/client/onboarding/use-onboarding.d.ts +6 -1
  136. package/dist/client/onboarding/use-onboarding.js +32 -1
  137. package/dist/client/route-state.js +10 -0
  138. package/dist/client/settings/SecretsSection.js +32 -8
  139. package/dist/collab/struct-routes.d.ts +1 -1
  140. package/dist/connections/catalog.d.ts +4 -4
  141. package/dist/connections/catalog.js +3 -3
  142. package/dist/db/index.d.ts +1 -1
  143. package/dist/db/index.js +1 -1
  144. package/dist/localization/default-messages.d.ts +5 -0
  145. package/dist/localization/default-messages.js +5 -0
  146. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  147. package/dist/observability/routes.d.ts +3 -3
  148. package/dist/onboarding/app-profile.d.ts +4 -0
  149. package/dist/onboarding/app-profile.js +378 -0
  150. package/dist/onboarding/index.d.ts +2 -1
  151. package/dist/onboarding/index.js +1 -0
  152. package/dist/onboarding/plugin.d.ts +2 -0
  153. package/dist/onboarding/plugin.js +21 -1
  154. package/dist/onboarding/types.d.ts +19 -0
  155. package/dist/progress/routes.d.ts +1 -1
  156. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  157. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  158. package/dist/secrets/routes.d.ts +2 -2
  159. package/dist/secrets/routes.js +41 -17
  160. package/dist/server/auth.js +21 -1
  161. package/dist/server/better-auth-instance.d.ts +3 -2
  162. package/dist/server/better-auth-instance.js +9 -7
  163. package/dist/server/email-markdown.js +3 -8
  164. package/dist/server/transcribe-voice.d.ts +1 -1
  165. package/dist/shared/first-run-onboarding.d.ts +3 -0
  166. package/dist/shared/first-run-onboarding.js +3 -0
  167. package/dist/triggers/index.d.ts +3 -0
  168. package/dist/triggers/index.js +5 -0
  169. package/docs/content/cross-app-sso.mdx +26 -0
  170. package/package.json +1 -1
@@ -26,9 +26,35 @@ export interface ChannelHistoryResult {
26
26
  next_cursor?: string;
27
27
  }
28
28
 
29
+ export interface ThreadRepliesResult {
30
+ messages: SlackMessage[];
31
+ has_more: boolean;
32
+ next_cursor?: string;
33
+ }
34
+
35
+ export interface SlackReactionResult {
36
+ added: boolean;
37
+ already_present: boolean;
38
+ }
39
+
40
+ export interface SlackPostMessageResult {
41
+ ok?: boolean;
42
+ error?: string;
43
+ channel: string;
44
+ ts: string;
45
+ message?: SlackMessage;
46
+ }
47
+
29
48
  const cache = new Map<string, { value: unknown; expiresAt: number }>();
30
49
  const cacheTtlMs = 120_000;
31
50
 
51
+ function invalidateWorkspaceCache(workspace: Workspace): void {
52
+ const prefix = `${workspace}:`;
53
+ for (const key of cache.keys()) {
54
+ if (key.startsWith(prefix)) cache.delete(key);
55
+ }
56
+ }
57
+
32
58
  async function getToken(
33
59
  workspace: Workspace,
34
60
  tokenResolver?: SlackTokenResolver,
@@ -60,12 +86,40 @@ async function slackApi<T>(
60
86
  `Slack API error ${response.status}: ${await response.text()}`,
61
87
  );
62
88
  const data = (await response.json()) as T & { ok?: boolean; error?: string };
63
- if (data.ok === false)
89
+ if (data.ok !== true)
64
90
  throw new Error(`Slack API error: ${data.error ?? "unknown_error"}`);
65
91
  cache.set(cacheKey, { value: data, expiresAt: Date.now() + cacheTtlMs });
66
92
  return data;
67
93
  }
68
94
 
95
+ async function slackWrite<T extends { ok?: boolean; error?: string }>(
96
+ workspace: Workspace,
97
+ method: string,
98
+ body: Record<string, string>,
99
+ tokenResolver?: SlackTokenResolver,
100
+ ): Promise<T> {
101
+ const token = await getToken(workspace, tokenResolver);
102
+ const response = await fetch(`https://slack.com/api/${method}`, {
103
+ method: "POST",
104
+ headers: {
105
+ Authorization: `Bearer ${token}`,
106
+ "Content-Type": "application/json; charset=utf-8",
107
+ },
108
+ body: JSON.stringify(body),
109
+ });
110
+ if (!response.ok)
111
+ throw new Error(
112
+ `Slack API error ${response.status}: ${await response.text()}`,
113
+ );
114
+ const data = (await response.json()) as T;
115
+ if (data.ok !== true)
116
+ throw new Error(`Slack API error: ${data.error ?? "unknown_error"}`);
117
+ // A successful reaction or message write makes cached reads stale. This is
118
+ // especially important when a retry follows a partially recorded handoff.
119
+ invalidateWorkspaceCache(workspace);
120
+ return data;
121
+ }
122
+
69
123
  export async function getChannelHistory(
70
124
  workspace: Workspace,
71
125
  channelId: string,
@@ -83,7 +137,10 @@ export async function getChannelHistory(
83
137
  messages?: SlackMessage[];
84
138
  has_more?: boolean;
85
139
  }>(workspace, "conversations.history", params, tokenResolver);
86
- const messages = data.messages ?? [];
140
+ if (!Array.isArray(data.messages)) {
141
+ throw new Error("Slack history response is missing messages.");
142
+ }
143
+ const messages = data.messages;
87
144
  return {
88
145
  messages,
89
146
  has_more: Boolean(data.has_more),
@@ -100,13 +157,19 @@ export async function getChannelHistory(
100
157
  },
101
158
  body: JSON.stringify({ channel: channelId }),
102
159
  });
103
- const joinedData = (await joined.json()) as { ok?: boolean };
104
- if (!joinedData.ok) throw error;
160
+ const joinedData = (await joined.json()) as {
161
+ ok?: boolean;
162
+ error?: string;
163
+ };
164
+ if (joinedData.ok !== true) throw error;
105
165
  const data = await slackApi<{
106
166
  messages?: SlackMessage[];
107
167
  has_more?: boolean;
108
168
  }>(workspace, "conversations.history", params, tokenResolver);
109
- const messages = data.messages ?? [];
169
+ if (!Array.isArray(data.messages)) {
170
+ throw new Error("Slack history response is missing messages.");
171
+ }
172
+ const messages = data.messages;
110
173
  return {
111
174
  messages,
112
175
  has_more: Boolean(data.has_more),
@@ -115,6 +178,71 @@ export async function getChannelHistory(
115
178
  }
116
179
  }
117
180
 
181
+ export async function getThread(
182
+ workspace: Workspace,
183
+ channelId: string,
184
+ threadTs: string,
185
+ limit = 100,
186
+ cursor?: string,
187
+ tokenResolver?: SlackTokenResolver,
188
+ ): Promise<ThreadRepliesResult> {
189
+ const params: Record<string, string> = {
190
+ channel: channelId,
191
+ ts: threadTs,
192
+ limit: String(Math.min(Math.max(limit, 1), 100)),
193
+ };
194
+ if (cursor) params.cursor = cursor;
195
+ const data = await slackApi<{
196
+ messages?: SlackMessage[];
197
+ has_more?: boolean;
198
+ response_metadata?: { next_cursor?: string };
199
+ }>(workspace, "conversations.replies", params, tokenResolver);
200
+ if (!Array.isArray(data.messages)) {
201
+ throw new Error("Slack thread response is missing messages.");
202
+ }
203
+ return {
204
+ messages: data.messages,
205
+ has_more: Boolean(data.has_more),
206
+ next_cursor: data.response_metadata?.next_cursor || undefined,
207
+ };
208
+ }
209
+
210
+ export async function addEyesReaction(
211
+ workspace: Workspace,
212
+ channelId: string,
213
+ timestamp: string,
214
+ tokenResolver?: SlackTokenResolver,
215
+ ): Promise<SlackReactionResult> {
216
+ try {
217
+ await slackWrite(
218
+ workspace,
219
+ "reactions.add",
220
+ { channel: channelId, timestamp, name: "eyes" },
221
+ tokenResolver,
222
+ );
223
+ return { added: true, already_present: false };
224
+ } catch (error) {
225
+ if (!String(error).includes("already_reacted")) throw error;
226
+ return { added: false, already_present: true };
227
+ }
228
+ }
229
+
230
+ export async function postThreadReply(
231
+ workspace: Workspace,
232
+ channelId: string,
233
+ threadTs: string,
234
+ text: string,
235
+ tokenResolver?: SlackTokenResolver,
236
+ ): Promise<SlackPostMessageResult> {
237
+ const data = await slackWrite<SlackPostMessageResult>(
238
+ workspace,
239
+ "chat.postMessage",
240
+ { channel: channelId, thread_ts: threadTs, text },
241
+ tokenResolver,
242
+ );
243
+ return data;
244
+ }
245
+
118
246
  export async function getTeamInfo(
119
247
  workspace: Workspace,
120
248
  tokenResolver?: SlackTokenResolver,
@@ -114,6 +114,12 @@ export const triageConfig = table("factory_config", {
114
114
  lastSlackTs: text("last_slack_ts"),
115
115
  slackHistoryCursor: text("slack_history_cursor"),
116
116
  repository: text("repository"),
117
+ githubPollingEnabled: integer("github_polling_enabled").notNull().default(0),
118
+ sentryPollingEnabled: integer("sentry_polling_enabled").notNull().default(0),
119
+ sentryOrgSlug: text("sentry_org_slug"),
120
+ sentryProjectSlug: text("sentry_project_slug"),
121
+ sentryEnvironment: text("sentry_environment"),
122
+ lastSentrySeenAt: text("last_sentry_seen_at"),
117
123
  createdAt: text("created_at").notNull().default(now()),
118
124
  updatedAt: text("updated_at").notNull().default(now()),
119
125
  ownerEmail: text("owner_email").notNull(),
@@ -0,0 +1,65 @@
1
+ import type { ActionRunContext } from "@agent-native/core/action";
2
+ import { listAutomationDefinitions } from "@agent-native/core/triggers";
3
+
4
+ import type { WorkspaceMemberIdentity } from "./require-workspace-member.js";
5
+
6
+ const FACTORY_AUTOMATION_NAMES = {
7
+ builderDispatch: new Set([
8
+ "factory-slack-feedback",
9
+ "factory-sentry-errors",
10
+ "factory-github-issues",
11
+ ]),
12
+ governance: new Set(["factory-pr-governance"]),
13
+ sourcePolling: new Set([
14
+ "factory-slack-feedback",
15
+ "factory-sentry-errors",
16
+ "factory-github-issues",
17
+ "factory-pr-governance",
18
+ ]),
19
+ } as const;
20
+
21
+ export type FactoryAutomationRole = keyof typeof FACTORY_AUTOMATION_NAMES;
22
+
23
+ function workspaceOwnerEmail(): string | undefined {
24
+ const email = process.env.WORKSPACE_OWNER_EMAIL?.trim().toLowerCase(); // guard:allow-env-credential - deployment owner identity, not a user credential
25
+ if (!email || /[\r\n]/.test(email)) return undefined;
26
+ return email;
27
+ }
28
+
29
+ export async function requireFactoryAutomation(
30
+ context: ActionRunContext | undefined,
31
+ identity: Pick<WorkspaceMemberIdentity, "userEmail" | "orgId">,
32
+ role: FactoryAutomationRole,
33
+ ): Promise<void> {
34
+ if (context?.caller !== "automation") {
35
+ throw new Error("This action is only available to Factory automations.");
36
+ }
37
+ const lineage = context.automation;
38
+ const expectedNames = FACTORY_AUTOMATION_NAMES[role];
39
+ if (!lineage || !expectedNames.has(lineage.triggerName)) {
40
+ throw new Error(
41
+ "The action was not invoked by a governed Factory automation.",
42
+ );
43
+ }
44
+
45
+ const definition = (
46
+ await listAutomationDefinitions(
47
+ { userEmail: identity.userEmail, orgId: identity.orgId },
48
+ "organization",
49
+ )
50
+ ).find((entry) => entry.resource.id === lineage.triggerId);
51
+ const ownerEmail = workspaceOwnerEmail();
52
+ if (
53
+ !definition ||
54
+ definition.name !== lineage.triggerName ||
55
+ definition.meta.domain !== "factory" ||
56
+ definition.meta.orgId !== identity.orgId ||
57
+ definition.meta.runAs !== "creator" ||
58
+ !ownerEmail ||
59
+ definition.meta.createdBy?.trim().toLowerCase() !== ownerEmail
60
+ ) {
61
+ throw new Error(
62
+ "The action was not invoked by a governed Factory automation.",
63
+ );
64
+ }
65
+ }
@@ -17,7 +17,14 @@ const INITIAL_TOOL_NAMES = [
17
17
  "list-triage-items",
18
18
  "get-triage-item",
19
19
  "poll-slack-channel",
20
+ "get-slack-feedback-context",
21
+ "poll-github-sources",
22
+ "poll-sentry-errors",
20
23
  "evaluate-triage-item",
24
+ "start-builder-for-item",
25
+ "govern-agent-native-pull-request",
26
+ "babysit-pull-request",
27
+ "approve-factory-item",
21
28
  "list-triage-rules",
22
29
  "get-triage-config",
23
30
  "navigate",
@@ -31,16 +38,18 @@ const options = {
31
38
  resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
32
39
  systemPrompt: `You are the Factory agent.
33
40
 
34
- Factory is a visual factory builder. It observes Slack feedback and pull-request
35
- evidence, renders the current factory graph, and helps a human decide where agents
36
- should act. Use the Factory actions as the source of truth. When a user asks to
41
+ Factory is a visual factory builder. It observes Slack feedback, GitHub issues,
42
+ Sentry errors, and pull-request evidence, renders the current factory graph, and
43
+ executes only the explicit automation prompts that are stored in the organization.
44
+ Use the Factory actions as the source of truth. When a user asks to
37
45
  create or change a factory, first inspect the current graph, then propose a complete
38
46
  versioned graph through save-factory-graph with source=ai and a concise changeSummary.
39
47
  Never hide a graph change in prose: the visual map and the saved graph must agree.
40
- The graph is currently a reviewable blueprint, not the runtime router: enabled
41
- triage rules are evaluated in parallel against the same evidence. Do not claim that
42
- an edge changes execution. For rule or guard changes, use the triage rule actions
43
- and preserve normalizeTriagePolicyGuards; do not encode policy in graph JSON.
48
+ The graph is currently a reviewable blueprint, not the runtime router: automation
49
+ markdown resources are the runtime prompts, while enabled triage rules are evaluated
50
+ in parallel against the same evidence. Do not claim that an edge changes execution.
51
+ For rule or guard changes, use the triage rule actions and preserve
52
+ normalizeTriagePolicyGuards; do not encode policy in graph JSON.
44
53
  Use add-factory-comment for durable comments attached to the selected node or edge.
45
54
  Explain the evidence and guard results before proposing work.
46
55
  When discussing agent failures, preserve these measured taxonomy labels exactly:
@@ -49,10 +58,19 @@ overloaded_error, and Missing provider authentication. Always inspect interactiv
49
58
  and scheduled job populations separately; scheduled runs have ids beginning with
50
59
  job- and must not be hidden by an interactive-only query.
51
60
  Never bypass a hard guard or claim that a provider action happened without a
52
- durable run record and a confirmed terminal callback. When a user says to do it
53
- now, use the approval action, which records the approver and applies the rule's
54
- configured executor policy. Keep Slack replies concise and link to the Factory
55
- item when a review is needed.`,
61
+ durable run record and a confirmed terminal callback. A clear bug means concrete
62
+ broken behavior, reproducible failure, error, regression, stuck run, incorrect
63
+ result, or a specific failing path with enough evidence to investigate. Feature
64
+ requests, broad UX suggestions, vague questions, and incomplete context stay
65
+ manual. Clips, Design, and Content are fully owner-managed: never react, tag
66
+ Builder, auto-approve, or auto-merge those items. Slack clear bugs use the
67
+ thread-preserving start-builder-for-item flow; GitHub and Sentry clear bugs use
68
+ the Builder agent-run flow. For pull requests, auto-approval requires an internal
69
+ BuilderIO author, a clear bug, passing CI, and handled review feedback. Auto-merge
70
+ also requires a verified Factory Builder run. When a user says to do a review-gated
71
+ item now, use the explicit approval action, which records the approver and applies
72
+ the rule's configured executor policy. Keep Slack replies concise and link to the
73
+ Factory item when a review is needed.`,
56
74
  } satisfies AgentChatPluginOptions;
57
75
 
58
76
  export default createAgentChatPlugin(options);
@@ -1,6 +1,7 @@
1
1
  import { createAuthPlugin } from "@agent-native/core/server";
2
2
 
3
3
  export default createAuthPlugin({
4
+ googleOnly: true,
4
5
  marketing: {
5
6
  appName: "Factory",
6
7
  tagline:
@@ -236,6 +236,18 @@ const migrations = [
236
236
  ON factory_comments (org_id, factory_id, created_at);
237
237
  `,
238
238
  },
239
+ {
240
+ version: 16,
241
+ name: "factory-source-polling-settings",
242
+ sql: `
243
+ ALTER TABLE factory_config ADD COLUMN github_polling_enabled INTEGER NOT NULL DEFAULT 0;
244
+ ALTER TABLE factory_config ADD COLUMN sentry_polling_enabled INTEGER NOT NULL DEFAULT 0;
245
+ ALTER TABLE factory_config ADD COLUMN sentry_org_slug TEXT;
246
+ ALTER TABLE factory_config ADD COLUMN sentry_project_slug TEXT;
247
+ ALTER TABLE factory_config ADD COLUMN sentry_environment TEXT;
248
+ ALTER TABLE factory_config ADD COLUMN last_sentry_seen_at TEXT;
249
+ `,
250
+ },
239
251
  ];
240
252
 
241
253
  export const runFactoryMigrations = runMigrations(migrations, {